summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoman Birg <roman@cyngn.com>2016-08-25 06:49:57 -0700
committerRoman Birg <roman@cyngn.com>2016-08-25 06:49:57 -0700
commit173320f2fcc50d819a0ed681e12f34e8739ed610 (patch)
tree4c12e256a18eb75aeacfd47ae852a0644598d93d
parent47248a06db1abcefd0668bd2dd6d61d2abb3bbb3 (diff)
parente95b0267e571f128d881b9c0881f5e25f725239e (diff)
downloadandroid_packages_apps_AudioFX-173320f2fcc50d819a0ed681e12f34e8739ed610.tar.gz
android_packages_apps_AudioFX-173320f2fcc50d819a0ed681e12f34e8739ed610.tar.bz2
android_packages_apps_AudioFX-173320f2fcc50d819a0ed681e12f34e8739ed610.zip
Merge branch 'cm-13.0-oss' into HEAD
Change-Id: Ie762fdbe5b70dec6843ce489e78d802662e148fb
-rw-r--r--.gitignore2
-rw-r--r--Android.mk41
-rw-r--r--AndroidManifest.xml88
-rw-r--r--res/drawable-hdpi/ab_transparent_dark_holo.9.pngbin2892 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_action_device_bluetooth.pngbin0 -> 811 bytes
-rw-r--r--res/drawable-hdpi/ic_action_device_headphones.pngbin0 -> 1167 bytes
-rw-r--r--res/drawable-hdpi/ic_action_device_speaker.pngbin0 -> 1371 bytes
-rw-r--r--res/drawable-hdpi/ic_action_device_usb.pngbin0 -> 857 bytes
-rw-r--r--res/drawable-hdpi/ic_action_dsp_icons_bluetoof.pngbin0 -> 689 bytes
-rw-r--r--res/drawable-hdpi/ic_action_dsp_icons_headphones.pngbin0 -> 1033 bytes
-rw-r--r--res/drawable-hdpi/ic_action_dsp_icons_speaker.pngbin0 -> 855 bytes
-rw-r--r--res/drawable-hdpi/ic_action_dsp_icons_usb.pngbin0 -> 892 bytes
-rw-r--r--res/drawable-hdpi/ic_action_dsp_icons_wifi.pngbin0 -> 832 bytes
-rw-r--r--res/drawable-hdpi/ic_action_lock_open.pngbin0 -> 681 bytes
-rw-r--r--res/drawable-hdpi/ic_action_lock_outline.pngbin0 -> 661 bytes
-rw-r--r--res/drawable-hdpi/ic_content_add_circle_outline.pngbin0 -> 923 bytes
-rw-r--r--res/drawable-hdpi/ic_content_clear.pngbin0 -> 431 bytes
-rw-r--r--res/drawable-hdpi/ic_content_create.pngbin0 -> 476 bytes
-rw-r--r--res/drawable-hdpi/knob.pngbin9403 -> 0 bytes
-rw-r--r--res/drawable-hdpi/knob_large.pngbin51511 -> 0 bytes
-rw-r--r--res/drawable-hdpi/knob_toggle_off.pngbin3071 -> 0 bytes
-rw-r--r--res/drawable-hdpi/knob_toggle_on.pngbin3218 -> 0 bytes
-rw-r--r--res/drawable-hdpi/preset_bar.9.pngbin19094 -> 0 bytes
-rw-r--r--res/drawable-hdpi/progress_vertical_bg_holo_dark.9.pngbin194 -> 0 bytes
-rw-r--r--res/drawable-hdpi/progress_vertical_primary_holo_dark.9.pngbin674 -> 0 bytes
-rw-r--r--res/drawable-hdpi/progress_vertical_secondary_holo_dark.9.pngbin220 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_control_disabled_holo.pngbin3326 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_control_focused_holo.pngbin3468 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_control_normal_holo.pngbin3556 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_control_pressed_holo.pngbin3951 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_vertical_primary_holo.9.pngbin2840 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_vertical_secondary_holo.9.pngbin2856 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_vertical_track_holo_dark.9.pngbin190 -> 0 bytes
-rw-r--r--res/drawable-hdpi/scrubber_vertical_track_holo_light.9.pngbin179 -> 0 bytes
-rw-r--r--res/drawable-hdpi/switch_thumb_activated.9.pngbin5117 -> 0 bytes
-rw-r--r--res/drawable-hdpi/switch_thumb_off.9.pngbin5098 -> 0 bytes
-rw-r--r--res/drawable-mdpi/ic_action_device_bluetooth.pngbin0 -> 497 bytes
-rw-r--r--res/drawable-mdpi/ic_action_device_headphones.pngbin0 -> 749 bytes
-rw-r--r--res/drawable-mdpi/ic_action_device_speaker.pngbin0 -> 819 bytes
-rw-r--r--res/drawable-mdpi/ic_action_device_usb.pngbin0 -> 568 bytes
-rw-r--r--res/drawable-mdpi/ic_action_dsp_icons_bluetoof.pngbin0 -> 471 bytes
-rw-r--r--res/drawable-mdpi/ic_action_dsp_icons_headphones.pngbin0 -> 668 bytes
-rw-r--r--res/drawable-mdpi/ic_action_dsp_icons_speaker.pngbin0 -> 541 bytes
-rw-r--r--res/drawable-mdpi/ic_action_dsp_icons_usb.pngbin0 -> 606 bytes
-rw-r--r--res/drawable-mdpi/ic_action_dsp_icons_wifi.pngbin0 -> 560 bytes
-rw-r--r--res/drawable-mdpi/ic_action_lock_open.pngbin0 -> 523 bytes
-rw-r--r--res/drawable-mdpi/ic_action_lock_outline.pngbin0 -> 525 bytes
-rw-r--r--res/drawable-mdpi/ic_content_add_circle_outline.pngbin0 -> 658 bytes
-rw-r--r--res/drawable-mdpi/ic_content_clear.pngbin0 -> 320 bytes
-rw-r--r--res/drawable-mdpi/ic_content_create.pngbin0 -> 387 bytes
-rw-r--r--res/drawable-mdpi/knob.pngbin5351 -> 0 bytes
-rw-r--r--res/drawable-mdpi/knob_large.pngbin41941 -> 0 bytes
-rw-r--r--res/drawable-mdpi/preset_bar.9.pngbin19212 -> 0 bytes
-rw-r--r--res/drawable-mdpi/progress_vertical_bg_holo_dark.9.pngbin189 -> 0 bytes
-rw-r--r--res/drawable-mdpi/progress_vertical_primary_holo_dark.9.pngbin470 -> 0 bytes
-rw-r--r--res/drawable-mdpi/progress_vertical_secondary_holo_dark.9.pngbin208 -> 0 bytes
-rw-r--r--res/drawable-mdpi/scrubber_vertical_primary_holo.9.pngbin179 -> 0 bytes
-rw-r--r--res/drawable-mdpi/scrubber_vertical_secondary_holo.9.pngbin180 -> 0 bytes
-rw-r--r--res/drawable-mdpi/scrubber_vertical_track_holo_dark.9.pngbin185 -> 0 bytes
-rw-r--r--res/drawable-mdpi/scrubber_vertical_track_holo_light.9.pngbin170 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_device_bluetooth.pngbin0 -> 1067 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_device_headphones.pngbin0 -> 1551 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_device_speaker.pngbin0 -> 1926 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_device_usb.pngbin0 -> 1107 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_dsp_icons_bluetoof.pngbin0 -> 904 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_dsp_icons_headphones.pngbin0 -> 1439 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_dsp_icons_speaker.pngbin0 -> 1159 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_dsp_icons_usb.pngbin0 -> 1141 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_dsp_icons_wifi.pngbin0 -> 1120 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_lock_open.pngbin0 -> 1026 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_lock_outline.pngbin0 -> 1036 bytes
-rw-r--r--res/drawable-xhdpi/ic_content_add_circle_outline.pngbin0 -> 1352 bytes
-rw-r--r--res/drawable-xhdpi/ic_content_clear.pngbin0 -> 696 bytes
-rw-r--r--res/drawable-xhdpi/ic_content_create.pngbin0 -> 719 bytes
-rw-r--r--res/drawable-xhdpi/knob.pngbin13248 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/knob_large.pngbin77986 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/preset_bar.9.pngbin19090 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/progress_vertical_primary_holo_dark.9.pngbin882 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/progress_vertical_secondary_holo_dark.9.pngbin214 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/scrubber_vertical_primary_holo.9.pngbin2840 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/scrubber_vertical_secondary_holo.9.pngbin2856 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/scrubber_vertical_track_holo_dark.9.pngbin201 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/scrubber_vertical_track_holo_light.9.pngbin191 -> 0 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_device_bluetooth.pngbin0 -> 1828 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_device_headphones.pngbin0 -> 2430 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_device_speaker.pngbin0 -> 3162 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_device_usb.pngbin0 -> 1745 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_dsp_icons_bluetoof.pngbin0 -> 1521 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_dsp_icons_headphones.pngbin0 -> 2204 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_dsp_icons_speaker.pngbin0 -> 1868 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_dsp_icons_usb.pngbin0 -> 1796 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_dsp_icons_wifi.pngbin0 -> 1746 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_lock_open.pngbin0 -> 1468 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_lock_outline.pngbin0 -> 1470 bytes
-rw-r--r--res/drawable-xxhdpi/ic_content_add_circle_outline.pngbin0 -> 2282 bytes
-rw-r--r--res/drawable-xxhdpi/ic_content_clear.pngbin0 -> 962 bytes
-rw-r--r--res/drawable-xxhdpi/ic_content_create.pngbin0 -> 942 bytes
-rw-r--r--res/drawable-xxhdpi/knob.pngbin24993 -> 0 bytes
-rwxr-xr-xres/drawable-xxhdpi/toggle_check_off.pngbin0 -> 5347 bytes
-rwxr-xr-xres/drawable-xxhdpi/toggle_check_on.pngbin0 -> 6133 bytes
-rw-r--r--res/drawable-xxhdpi/toggle_check_on_disabled.pngbin0 -> 5338 bytes
-rw-r--r--res/drawable/above_shadow.xml8
-rw-r--r--res/drawable/below_shadow.xml8
-rw-r--r--res/drawable/dash.xml12
-rw-r--r--res/drawable/ic_action_dsp_icons_lineout.xml29
-rw-r--r--res/drawable/ic_qs_visualizer_off.xml13
-rw-r--r--res/drawable/ic_qs_visualizer_on.xml13
-rw-r--r--res/drawable/logo_dts_1c.xml83
-rw-r--r--res/drawable/logo_dts_fc.xml83
-rw-r--r--res/drawable/maxvolume_white.pngbin0 -> 3264 bytes
-rw-r--r--res/drawable/maxxbass_white.pngbin0 -> 3055 bytes
-rw-r--r--res/drawable/maxxreble_white.pngbin0 -> 2931 bytes
-rw-r--r--res/drawable/maxxspace_white.pngbin0 -> 3089 bytes
-rw-r--r--res/drawable/progress_vertical_holo_dark.xml32
-rw-r--r--res/drawable/scrubber_control_selector_holo.xml36
-rw-r--r--res/drawable/scrubber_progress_vertical_holo_dark.xml28
-rw-r--r--res/drawable/scrubber_progress_vertical_holo_light.xml28
-rw-r--r--res/drawable/toggle_check.xml14
-rw-r--r--res/drawable/toggle_lock.xml9
-rw-r--r--res/layout-land/activity_main.xml8
-rw-r--r--res/layout-land/controls_generic.xml15
-rw-r--r--res/layout-land/controls_maxx_audio.xml142
-rw-r--r--res/layout-land/fragment_audiofx.xml25
-rw-r--r--res/layout-land/fragment_audiofx_maxxaudio.xml25
-rw-r--r--res/layout-land/generic_knob_control.xml21
-rw-r--r--res/layout/action_bar_custom_components.xml23
-rw-r--r--res/layout/action_bar_dts_logo.xml26
-rw-r--r--res/layout/activity_main.xml10
-rw-r--r--res/layout/controls_generic.xml13
-rw-r--r--res/layout/controls_maxx_audio.xml148
-rw-r--r--res/layout/eq_container.xml57
-rw-r--r--res/layout/equalizer.xml50
-rw-r--r--res/layout/fragment_audiofx.xml25
-rw-r--r--res/layout/fragment_audiofx_maxxaudio.xml25
-rw-r--r--res/layout/fragment_dts.xml17
-rw-r--r--res/layout/generic_knob_control.xml20
-rw-r--r--res/layout/knob.xml70
-rw-r--r--res/layout/music_main.xml174
-rw-r--r--res/layout/preset_adapter_row.xml18
-rw-r--r--res/menu/devices.xml27
-rw-r--r--res/mipmap-hdpi/ic_launcher.pngbin0 -> 23836 bytes
-rw-r--r--res/mipmap-mdpi/ic_launcher.pngbin0 -> 22469 bytes
-rw-r--r--res/mipmap-xhdpi/ic_launcher.pngbin0 -> 25591 bytes
-rw-r--r--res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 29601 bytes
-rw-r--r--res/mipmap-xxxhdpi/ic_launcher.pngbin0 -> 33207 bytes
-rw-r--r--res/values-af/cm_strings.xml15
-rw-r--r--res/values-ar/cm_strings.xml23
-rw-r--r--res/values-as-rIN/cm_strings.xml14
-rw-r--r--res/values-ast-rES/cm_strings.xml8
-rw-r--r--res/values-az-rAZ/cm_strings.xml7
-rw-r--r--res/values-be/cm_strings.xml38
-rw-r--r--res/values-bg/cm_strings.xml19
-rw-r--r--res/values-bn-rBD/cm_strings.xml8
-rw-r--r--res/values-bn/cm_strings.xml49
-rw-r--r--res/values-ca/cm_strings.xml15
-rw-r--r--res/values-cs/cm_strings.xml15
-rw-r--r--res/values-da/cm_strings.xml15
-rw-r--r--res/values-de/cm_strings.xml17
-rw-r--r--res/values-el/cm_strings.xml15
-rw-r--r--res/values-en-rAU/cm_strings.xml6
-rw-r--r--res/values-en-rIN/cm_strings.xml14
-rw-r--r--res/values-es-rUS/cm_strings.xml19
-rw-r--r--res/values-es-rXA/strings.xml30
-rw-r--r--res/values-es/cm_strings.xml15
-rw-r--r--res/values-et-rEE/cm_strings.xml7
-rw-r--r--res/values-fa/cm_strings.xml14
-rw-r--r--res/values-fi/cm_strings.xml15
-rw-r--r--res/values-fr-rCA/cm_strings.xml48
-rw-r--r--res/values-fr/cm_strings.xml15
-rw-r--r--res/values-fy-rNL/cm_strings.xml20
-rw-r--r--res/values-gl-rES/cm_strings.xml18
-rw-r--r--res/values-gl/cm_strings.xml37
-rw-r--r--res/values-gu-rIN/cm_strings.xml16
-rw-r--r--res/values-hdpi/knobs.xml (renamed from res/layout/music_eq.xml)15
-rw-r--r--res/values-hr/cm_strings.xml15
-rw-r--r--res/values-hu/cm_strings.xml15
-rw-r--r--res/values-in/cm_strings.xml17
-rw-r--r--res/values-it/cm_strings.xml17
-rw-r--r--res/values-iw/cm_strings.xml17
-rw-r--r--res/values-ja/cm_strings.xml17
-rw-r--r--res/values-kn-rIN/cm_strings.xml16
-rw-r--r--res/values-ko/cm_strings.xml15
-rw-r--r--res/values-ku/cm_strings.xml6
-rw-r--r--res/values-ku/strings.xml8
-rw-r--r--res/values-lb/cm_strings.xml15
-rw-r--r--res/values-lb/strings.xml12
-rw-r--r--res/values-lt/cm_strings.xml24
-rw-r--r--res/values-lv/cm_strings.xml6
-rw-r--r--res/values-ml-rIN/cm_strings.xml14
-rw-r--r--res/values-mr-rIN/cm_strings.xml16
-rw-r--r--res/values-nb/cm_strings.xml15
-rw-r--r--res/values-nl/cm_strings.xml15
-rw-r--r--res/values-or-rIN/cm_strings.xml14
-rw-r--r--res/values-pl/cm_strings.xml15
-rw-r--r--res/values-pt-rBR/cm_strings.xml21
-rw-r--r--res/values-pt-rPT/cm_strings.xml17
-rw-r--r--res/values-ro/cm_strings.xml11
-rw-r--r--res/values-ru/cm_strings.xml17
-rw-r--r--res/values-si-rLK/cm_strings.xml7
-rw-r--r--res/values-sk/cm_strings.xml14
-rw-r--r--res/values-sl/cm_strings.xml19
-rw-r--r--res/values-sr/cm_strings.xml15
-rw-r--r--res/values-sv/cm_strings.xml15
-rw-r--r--res/values-ta-rIN/cm_strings.xml14
-rw-r--r--res/values-te-rIN/cm_strings.xml20
-rw-r--r--res/values-th/cm_strings.xml19
-rw-r--r--res/values-tr/cm_strings.xml17
-rw-r--r--res/values-ug/cm_strings.xml16
-rw-r--r--res/values-uk/cm_strings.xml14
-rw-r--r--res/values-vi/cm_strings.xml25
-rw-r--r--res/values-zh-rCN/cm_strings.xml15
-rw-r--r--res/values-zh-rHK/cm_strings.xml14
-rw-r--r--res/values-zh-rTW/cm_strings.xml20
-rw-r--r--res/values/attrs.xml37
-rw-r--r--res/values/cm_strings.xml38
-rw-r--r--res/values/colors.xml (renamed from res/values/color.xml)44
-rw-r--r--res/values/dimens.xml35
-rw-r--r--res/values/strings.xml10
-rw-r--r--res/values/styles.xml40
-rw-r--r--res/values/vpi__attrs.xml129
-rw-r--r--res/values/vpi__colors.xml26
-rw-r--r--res/values/vpi__defaults.xml53
-rw-r--r--src/org/cyanogenmod/audiofx/ActivityMusic.java789
-rw-r--r--src/org/cyanogenmod/audiofx/BootReceiver.java14
-rw-r--r--src/org/cyanogenmod/audiofx/HeadsetService.java708
-rw-r--r--src/org/cyanogenmod/audiofx/OpenSLESConstants.java124
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/AudioFxApplication.java47
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/Compatibility.java (renamed from src/org/cyanogenmod/audiofx/Compatibility.java)22
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/Constants.java160
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/Preset.java236
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/activity/ActivityMusic.java198
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/activity/ControlPanelPicker.java (renamed from src/org/cyanogenmod/audiofx/ControlPanelPicker.java)22
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/activity/EqualizerManager.java634
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/activity/MasterConfigControl.java367
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/activity/StateCallbacks.java154
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/backends/AndroidEffects.java185
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/backends/EffectSet.java235
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/backends/EffectSetWithAndroidEq.java123
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/backends/IEffectFactory.java16
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/eq/EqBarView.java208
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/eq/EqContainerView.java518
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/eq/EqSwipeController.java133
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/eq/EqUtils.java149
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxBaseFragment.java66
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxFragment.java489
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/fragment/ControlsFragment.java103
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/fragment/EqualizerFragment.java559
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/knobs/KnobCommander.java177
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/knobs/KnobContainer.java380
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/knobs/RadialKnob.java570
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/preset/InfinitePagerAdapter.java95
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/preset/InfiniteViewPager.java106
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/preset/PresetPagerAdapter.java82
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/receiver/QuickSettingsTileReceiver.java36
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/receiver/ServiceDispatcher.java (renamed from src/org/cyanogenmod/audiofx/ServiceDispatcher.java)29
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/service/AudioFxService.java347
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/service/AudioOutputChangeListener.java131
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/service/BootReceiver.java14
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/service/DevicePreferenceManager.java294
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/service/SessionManager.java422
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/stats/AppState.java41
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/stats/UserSession.java202
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/CirclePageIndicator.java505
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/PageIndicator.java63
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/widget/Biquad.java (renamed from src/org/cyanogenmod/audiofx/widget/Biquad.java)8
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/widget/Complex.java (renamed from src/org/cyanogenmod/audiofx/widget/Complex.java)22
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/widget/EqualizerSurface.java (renamed from src/org/cyanogenmod/audiofx/widget/EqualizerSurface.java)15
-rw-r--r--src/org/cyanogenmod/audiofx/audiofx/widget/InterceptableLinearLayout.java (renamed from src/org/cyanogenmod/audiofx/widget/InterceptableLinearLayout.java)7
-rw-r--r--src/org/cyanogenmod/audiofx/widget/Gallery.java120
-rw-r--r--src/org/cyanogenmod/audiofx/widget/Knob.java434
-rw-r--r--src_effects/com/cyngn/audiofx/backends/EffectsFactory.java35
-rw-r--r--tests/Android.mk36
-rw-r--r--tests/AndroidManifest.xml20
-rw-r--r--tests/README.md5
-rw-r--r--tests/lib/rules-0.3-release.jarbin0 -> 515762 bytes
-rwxr-xr-xtests/res/raw/testmp3.mp3bin0 -> 90412 bytes
-rw-r--r--tests/res/values/strings.xml4
-rw-r--r--tests/src/com/cyngn/audiofx/PresetParcelTests.java94
-rw-r--r--tests/src/com/cyngn/audiofx/eq/EqUtilTests.java40
-rw-r--r--tests/src/com/cyngn/audiofx/service/AudioFxServiceTests.java178
-rw-r--r--tests/src/com/cyngn/audiofx/tests/DebugActivity.java87
-rw-r--r--tests/src/com/cyngn/audiofx/tests/TestActivity.java62
-rw-r--r--tests/src/com/cyngn/audiofx/util/BaseAudioFxServiceInstrumentationTest.java59
-rw-r--r--tests/src/com/cyngn/audiofx/util/TestDuckingMediaPlayer.java59
-rw-r--r--tests/src/com/cyngn/audiofx/util/TestMediaPlayer.java31
285 files changed, 11035 insertions, 3058 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..259e997
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.DS_Store
+src_effects_priv
diff --git a/Android.mk b/Android.mk
index 7b18e38..e07a2a9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,13 +1,42 @@
-LOCAL_PATH:= $(call my-dir)
+LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := framework
-LOCAL_STATIC_JAVA_LIBRARIES := org.cyanogenmod.platform.sdk
+LOCAL_PACKAGE_NAME := AudioFX
+LOCAL_MODULE_TAGS := optional
+
LOCAL_OVERRIDES_PACKAGES := DSPManager
-LOCAL_PACKAGE_NAME := AudioFX
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+ifeq ($(wildcard $(LOCAL_PATH)/src_effects_priv),)
+LOCAL_SRC_FILES += $(call all-java-files-under, src_effects)
+else
+$(warning *** including private implementations of effects ***)
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.cyngn.audiofx
+LOCAL_SRC_FILES += $(call all-java-files-under, src_effects_priv)
+endif
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 org.cyanogenmod.platform.sdk
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
+LOCAL_AAPT_FLAGS := --auto-add-overlay
+LOCAL_AAPT_FLAGS += --extra-packages com.cyanogen.ambient
+
+LOCAL_STATIC_JAVA_AAR_LIBRARIES := ambientsdk
+
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := platform
+# Sign the package when not using test-keys
+ifneq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/testkey)
+LOCAL_CERTIFICATE := cyngn-app
+endif
+
include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3d87d52..5941995 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -15,58 +15,50 @@
-->
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.cyanogenmod.audiofx"
- android:installLocation="auto"
- android:versionName="1.4.0"
- android:versionCode="10400">
+ package="com.cyngn.audiofx"
+ android:versionName="2.1.0"
+ android:versionCode="20100">
- <uses-sdk android:minSdkVersion="21"/>
+ <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="23" />
- <uses-feature android:name="android.software.leanback"
- android:required="false" />
-
- <uses-feature android:name="android.hardware.touchscreen"
- android:required="false" />
-
- <uses-feature android:name="android.hardware.screen.portrait"
- android:required="false" />
-
- <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
- <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.BLUETOOTH"/>
- <uses-permission android:name="android.permission.RECORD_AUDIO"/>
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+ <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
+ <uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING" />
+ <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />
<uses-permission android:name="cyanogenmod.permission.OBSERVE_AUDIO_SESSIONS" />
+ <permission android:name="com.cyngn.audiofx.ANALYTICS_PERMISSION"
+ android:protectionLevel="signature" />
+
<application
- android:icon="@mipmap/ic_launcher_audiofx"
- android:label="@string/app_name_cm"
+ android:icon="@mipmap/ic_launcher"
+ android:allowBackup="false"
+ android:label="@string/app_name"
android:supportsRtl="true"
android:hardwareAccelerated="true"
- android:persistent="true"
+ android:name=".AudioFxApplication"
android:theme="@android:style/Theme.NoTitleBar">
<activity
- android:name=".ActivityMusic"
- android:theme="@style/AppTheme"
- android:label="@string/app_name_cm"
- android:launchMode="singleTop"
- android:noHistory="false">
+ android:name=".activity.ActivityMusic"
+ android:theme="@style/AppThemeV2"
+ android:label="@string/eq_dialog_title"
+ android:launchMode="singleInstance"
+ android:configChanges="locale|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
- <category android:name="android.intent.category.LEANBACK_SETTINGS" />
</intent-filter>
<intent-filter>
<action android:name="android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL"/>
<category android:name="android.intent.category.DEFAULT"/>
- <category android:name="android.intent.category.CATEGORY_CONTENT_MUSIC"/>
</intent-filter>
</activity>
<activity
- android:name=".ControlPanelPicker"
+ android:name=".activity.ControlPanelPicker"
android:theme="@*android:style/Theme.Material.Dialog.Alert"
android:excludeFromRecents="true"/>
@@ -86,10 +78,15 @@
</intent-filter>
</receiver>
+ <receiver android:name=".receiver.QuickSettingsTileReceiver">
+ <intent-filter>
+ <action android:name="com.cyngn.audiofx.action.TOGGLE_DEVICE" />
+ </intent-filter>
+ </receiver>
+
<service
android:name="Compatibility$Service"
android:exported="false"/>
- <service android:name=".HeadsetService"/>
<activity
android:name="Compatibility$Redirector">
@@ -100,15 +97,9 @@
</intent-filter>
</activity>
- <service android:name=".HeadsetService" />
-
- <receiver android:name=".BootReceiver">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- </intent-filter>
- </receiver>
+ <service android:name=".service.AudioFxService"/>
- <receiver android:name=".ServiceDispatcher">
+ <receiver android:name=".receiver.ServiceDispatcher">
<intent-filter>
<action android:name="android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"/>
<action android:name="android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"/>
@@ -118,5 +109,20 @@
</intent-filter>
</receiver>
+ <receiver android:name=".service.BootReceiver">
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ </intent-filter>
+ </receiver>
+
+ <provider
+ android:name="com.cyanogen.ambient.analytics.provider.AnalyticsProvider"
+ android:authorities="com.cyngn.audiofx"
+ android:exported="true"
+ android:grantUriPermissions="true"
+ android:readPermission="com.cyngn.audiofx.ANALYTICS_PERMISSION"/>
+
+ <meta-data android:name="com.cyanogen.ambient.analytics.key"
+ android:value="38dsfaasfdk2347dfsuiadslk43"/>
</application>
</manifest>
diff --git a/res/drawable-hdpi/ab_transparent_dark_holo.9.png b/res/drawable-hdpi/ab_transparent_dark_holo.9.png
deleted file mode 100644
index 8c6afff..0000000
--- a/res/drawable-hdpi/ab_transparent_dark_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_device_bluetooth.png b/res/drawable-hdpi/ic_action_device_bluetooth.png
new file mode 100644
index 0000000..4405ab0
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_device_bluetooth.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_device_headphones.png b/res/drawable-hdpi/ic_action_device_headphones.png
new file mode 100644
index 0000000..3753efb
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_device_headphones.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_device_speaker.png b/res/drawable-hdpi/ic_action_device_speaker.png
new file mode 100644
index 0000000..47e868b
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_device_speaker.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_device_usb.png b/res/drawable-hdpi/ic_action_device_usb.png
new file mode 100644
index 0000000..ebcec02
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_device_usb.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_dsp_icons_bluetoof.png b/res/drawable-hdpi/ic_action_dsp_icons_bluetoof.png
new file mode 100644
index 0000000..886ad7c
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_dsp_icons_bluetoof.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_dsp_icons_headphones.png b/res/drawable-hdpi/ic_action_dsp_icons_headphones.png
new file mode 100644
index 0000000..6b16ec9
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_dsp_icons_headphones.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_dsp_icons_speaker.png b/res/drawable-hdpi/ic_action_dsp_icons_speaker.png
new file mode 100644
index 0000000..0b0a440
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_dsp_icons_speaker.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_dsp_icons_usb.png b/res/drawable-hdpi/ic_action_dsp_icons_usb.png
new file mode 100644
index 0000000..c5653f2
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_dsp_icons_usb.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_dsp_icons_wifi.png b/res/drawable-hdpi/ic_action_dsp_icons_wifi.png
new file mode 100644
index 0000000..6ad6a1f
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_dsp_icons_wifi.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_lock_open.png b/res/drawable-hdpi/ic_action_lock_open.png
new file mode 100644
index 0000000..63b06ba
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_lock_open.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_lock_outline.png b/res/drawable-hdpi/ic_action_lock_outline.png
new file mode 100644
index 0000000..78549eb
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_lock_outline.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_content_add_circle_outline.png b/res/drawable-hdpi/ic_content_add_circle_outline.png
new file mode 100644
index 0000000..413ae29
--- /dev/null
+++ b/res/drawable-hdpi/ic_content_add_circle_outline.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_content_clear.png b/res/drawable-hdpi/ic_content_clear.png
new file mode 100644
index 0000000..9fa0919
--- /dev/null
+++ b/res/drawable-hdpi/ic_content_clear.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_content_create.png b/res/drawable-hdpi/ic_content_create.png
new file mode 100644
index 0000000..80eeb02
--- /dev/null
+++ b/res/drawable-hdpi/ic_content_create.png
Binary files differ
diff --git a/res/drawable-hdpi/knob.png b/res/drawable-hdpi/knob.png
deleted file mode 100644
index df50b22..0000000
--- a/res/drawable-hdpi/knob.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/knob_large.png b/res/drawable-hdpi/knob_large.png
deleted file mode 100644
index 1eba937..0000000
--- a/res/drawable-hdpi/knob_large.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/knob_toggle_off.png b/res/drawable-hdpi/knob_toggle_off.png
deleted file mode 100644
index a89595e..0000000
--- a/res/drawable-hdpi/knob_toggle_off.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/knob_toggle_on.png b/res/drawable-hdpi/knob_toggle_on.png
deleted file mode 100644
index ab8d3d7..0000000
--- a/res/drawable-hdpi/knob_toggle_on.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/preset_bar.9.png b/res/drawable-hdpi/preset_bar.9.png
deleted file mode 100644
index 71cbc96..0000000
--- a/res/drawable-hdpi/preset_bar.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/progress_vertical_bg_holo_dark.9.png b/res/drawable-hdpi/progress_vertical_bg_holo_dark.9.png
deleted file mode 100644
index 92e34bf..0000000
--- a/res/drawable-hdpi/progress_vertical_bg_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/progress_vertical_primary_holo_dark.9.png b/res/drawable-hdpi/progress_vertical_primary_holo_dark.9.png
deleted file mode 100644
index cbd537b..0000000
--- a/res/drawable-hdpi/progress_vertical_primary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/progress_vertical_secondary_holo_dark.9.png b/res/drawable-hdpi/progress_vertical_secondary_holo_dark.9.png
deleted file mode 100644
index 73a0e40..0000000
--- a/res/drawable-hdpi/progress_vertical_secondary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_control_disabled_holo.png b/res/drawable-hdpi/scrubber_control_disabled_holo.png
deleted file mode 100644
index c173f0e..0000000
--- a/res/drawable-hdpi/scrubber_control_disabled_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_control_focused_holo.png b/res/drawable-hdpi/scrubber_control_focused_holo.png
deleted file mode 100644
index d302df6..0000000
--- a/res/drawable-hdpi/scrubber_control_focused_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_control_normal_holo.png b/res/drawable-hdpi/scrubber_control_normal_holo.png
deleted file mode 100644
index 802d046..0000000
--- a/res/drawable-hdpi/scrubber_control_normal_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_control_pressed_holo.png b/res/drawable-hdpi/scrubber_control_pressed_holo.png
deleted file mode 100644
index 5e82872..0000000
--- a/res/drawable-hdpi/scrubber_control_pressed_holo.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_vertical_primary_holo.9.png b/res/drawable-hdpi/scrubber_vertical_primary_holo.9.png
deleted file mode 100644
index 874dcc8..0000000
--- a/res/drawable-hdpi/scrubber_vertical_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_vertical_secondary_holo.9.png b/res/drawable-hdpi/scrubber_vertical_secondary_holo.9.png
deleted file mode 100644
index a783343..0000000
--- a/res/drawable-hdpi/scrubber_vertical_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_vertical_track_holo_dark.9.png b/res/drawable-hdpi/scrubber_vertical_track_holo_dark.9.png
deleted file mode 100644
index 9f12c60..0000000
--- a/res/drawable-hdpi/scrubber_vertical_track_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/scrubber_vertical_track_holo_light.9.png b/res/drawable-hdpi/scrubber_vertical_track_holo_light.9.png
deleted file mode 100644
index 325b86a..0000000
--- a/res/drawable-hdpi/scrubber_vertical_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/switch_thumb_activated.9.png b/res/drawable-hdpi/switch_thumb_activated.9.png
deleted file mode 100644
index 072aa64..0000000
--- a/res/drawable-hdpi/switch_thumb_activated.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/switch_thumb_off.9.png b/res/drawable-hdpi/switch_thumb_off.9.png
deleted file mode 100644
index 45786a3..0000000
--- a/res/drawable-hdpi/switch_thumb_off.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_device_bluetooth.png b/res/drawable-mdpi/ic_action_device_bluetooth.png
new file mode 100644
index 0000000..73efdb4
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_device_bluetooth.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_device_headphones.png b/res/drawable-mdpi/ic_action_device_headphones.png
new file mode 100644
index 0000000..5eab0ae
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_device_headphones.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_device_speaker.png b/res/drawable-mdpi/ic_action_device_speaker.png
new file mode 100644
index 0000000..3b5da86
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_device_speaker.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_device_usb.png b/res/drawable-mdpi/ic_action_device_usb.png
new file mode 100644
index 0000000..8d96938
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_device_usb.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_dsp_icons_bluetoof.png b/res/drawable-mdpi/ic_action_dsp_icons_bluetoof.png
new file mode 100644
index 0000000..8ae42f2
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_dsp_icons_bluetoof.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_dsp_icons_headphones.png b/res/drawable-mdpi/ic_action_dsp_icons_headphones.png
new file mode 100644
index 0000000..0891cd2
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_dsp_icons_headphones.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_dsp_icons_speaker.png b/res/drawable-mdpi/ic_action_dsp_icons_speaker.png
new file mode 100644
index 0000000..055e078
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_dsp_icons_speaker.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_dsp_icons_usb.png b/res/drawable-mdpi/ic_action_dsp_icons_usb.png
new file mode 100644
index 0000000..a0ad195
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_dsp_icons_usb.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_dsp_icons_wifi.png b/res/drawable-mdpi/ic_action_dsp_icons_wifi.png
new file mode 100644
index 0000000..da14e4d
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_dsp_icons_wifi.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_lock_open.png b/res/drawable-mdpi/ic_action_lock_open.png
new file mode 100644
index 0000000..ac0f891
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_lock_open.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_lock_outline.png b/res/drawable-mdpi/ic_action_lock_outline.png
new file mode 100644
index 0000000..86eeca4
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_lock_outline.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_content_add_circle_outline.png b/res/drawable-mdpi/ic_content_add_circle_outline.png
new file mode 100644
index 0000000..5928019
--- /dev/null
+++ b/res/drawable-mdpi/ic_content_add_circle_outline.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_content_clear.png b/res/drawable-mdpi/ic_content_clear.png
new file mode 100644
index 0000000..ee7dea1
--- /dev/null
+++ b/res/drawable-mdpi/ic_content_clear.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_content_create.png b/res/drawable-mdpi/ic_content_create.png
new file mode 100644
index 0000000..13dd7da
--- /dev/null
+++ b/res/drawable-mdpi/ic_content_create.png
Binary files differ
diff --git a/res/drawable-mdpi/knob.png b/res/drawable-mdpi/knob.png
deleted file mode 100644
index bfdf28f..0000000
--- a/res/drawable-mdpi/knob.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/knob_large.png b/res/drawable-mdpi/knob_large.png
deleted file mode 100644
index 43b508e..0000000
--- a/res/drawable-mdpi/knob_large.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/preset_bar.9.png b/res/drawable-mdpi/preset_bar.9.png
deleted file mode 100644
index 5cadbb4..0000000
--- a/res/drawable-mdpi/preset_bar.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/progress_vertical_bg_holo_dark.9.png b/res/drawable-mdpi/progress_vertical_bg_holo_dark.9.png
deleted file mode 100644
index 662e59b..0000000
--- a/res/drawable-mdpi/progress_vertical_bg_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/progress_vertical_primary_holo_dark.9.png b/res/drawable-mdpi/progress_vertical_primary_holo_dark.9.png
deleted file mode 100644
index e7e32cb..0000000
--- a/res/drawable-mdpi/progress_vertical_primary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/progress_vertical_secondary_holo_dark.9.png b/res/drawable-mdpi/progress_vertical_secondary_holo_dark.9.png
deleted file mode 100644
index 2fee3a8..0000000
--- a/res/drawable-mdpi/progress_vertical_secondary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/scrubber_vertical_primary_holo.9.png b/res/drawable-mdpi/scrubber_vertical_primary_holo.9.png
deleted file mode 100644
index ecea48d..0000000
--- a/res/drawable-mdpi/scrubber_vertical_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/scrubber_vertical_secondary_holo.9.png b/res/drawable-mdpi/scrubber_vertical_secondary_holo.9.png
deleted file mode 100644
index 35bf199..0000000
--- a/res/drawable-mdpi/scrubber_vertical_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/scrubber_vertical_track_holo_dark.9.png b/res/drawable-mdpi/scrubber_vertical_track_holo_dark.9.png
deleted file mode 100644
index 8a7fbde..0000000
--- a/res/drawable-mdpi/scrubber_vertical_track_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/scrubber_vertical_track_holo_light.9.png b/res/drawable-mdpi/scrubber_vertical_track_holo_light.9.png
deleted file mode 100644
index 097d05e..0000000
--- a/res/drawable-mdpi/scrubber_vertical_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_device_bluetooth.png b/res/drawable-xhdpi/ic_action_device_bluetooth.png
new file mode 100644
index 0000000..d599eea
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_device_bluetooth.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_device_headphones.png b/res/drawable-xhdpi/ic_action_device_headphones.png
new file mode 100644
index 0000000..ed14cb6
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_device_headphones.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_device_speaker.png b/res/drawable-xhdpi/ic_action_device_speaker.png
new file mode 100644
index 0000000..31400d3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_device_speaker.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_device_usb.png b/res/drawable-xhdpi/ic_action_device_usb.png
new file mode 100644
index 0000000..721b1c6
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_device_usb.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_dsp_icons_bluetoof.png b/res/drawable-xhdpi/ic_action_dsp_icons_bluetoof.png
new file mode 100644
index 0000000..8940456
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_dsp_icons_bluetoof.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_dsp_icons_headphones.png b/res/drawable-xhdpi/ic_action_dsp_icons_headphones.png
new file mode 100644
index 0000000..8543892
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_dsp_icons_headphones.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_dsp_icons_speaker.png b/res/drawable-xhdpi/ic_action_dsp_icons_speaker.png
new file mode 100644
index 0000000..7365ba3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_dsp_icons_speaker.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_dsp_icons_usb.png b/res/drawable-xhdpi/ic_action_dsp_icons_usb.png
new file mode 100644
index 0000000..79a6eaa
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_dsp_icons_usb.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_dsp_icons_wifi.png b/res/drawable-xhdpi/ic_action_dsp_icons_wifi.png
new file mode 100644
index 0000000..d1e365a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_dsp_icons_wifi.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_lock_open.png b/res/drawable-xhdpi/ic_action_lock_open.png
new file mode 100644
index 0000000..fc93a7e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_lock_open.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_lock_outline.png b/res/drawable-xhdpi/ic_action_lock_outline.png
new file mode 100644
index 0000000..ecb4c0a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_lock_outline.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_content_add_circle_outline.png b/res/drawable-xhdpi/ic_content_add_circle_outline.png
new file mode 100644
index 0000000..3efd9aa
--- /dev/null
+++ b/res/drawable-xhdpi/ic_content_add_circle_outline.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_content_clear.png b/res/drawable-xhdpi/ic_content_clear.png
new file mode 100644
index 0000000..6a3e8ca
--- /dev/null
+++ b/res/drawable-xhdpi/ic_content_clear.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_content_create.png b/res/drawable-xhdpi/ic_content_create.png
new file mode 100644
index 0000000..6cbbd01
--- /dev/null
+++ b/res/drawable-xhdpi/ic_content_create.png
Binary files differ
diff --git a/res/drawable-xhdpi/knob.png b/res/drawable-xhdpi/knob.png
deleted file mode 100644
index 39225b7..0000000
--- a/res/drawable-xhdpi/knob.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/knob_large.png b/res/drawable-xhdpi/knob_large.png
deleted file mode 100644
index 232e726..0000000
--- a/res/drawable-xhdpi/knob_large.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/preset_bar.9.png b/res/drawable-xhdpi/preset_bar.9.png
deleted file mode 100644
index 11fbdc5..0000000
--- a/res/drawable-xhdpi/preset_bar.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/progress_vertical_primary_holo_dark.9.png b/res/drawable-xhdpi/progress_vertical_primary_holo_dark.9.png
deleted file mode 100644
index 27c8647..0000000
--- a/res/drawable-xhdpi/progress_vertical_primary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/progress_vertical_secondary_holo_dark.9.png b/res/drawable-xhdpi/progress_vertical_secondary_holo_dark.9.png
deleted file mode 100644
index 5c622d8..0000000
--- a/res/drawable-xhdpi/progress_vertical_secondary_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/scrubber_vertical_primary_holo.9.png b/res/drawable-xhdpi/scrubber_vertical_primary_holo.9.png
deleted file mode 100644
index 874dcc8..0000000
--- a/res/drawable-xhdpi/scrubber_vertical_primary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/scrubber_vertical_secondary_holo.9.png b/res/drawable-xhdpi/scrubber_vertical_secondary_holo.9.png
deleted file mode 100644
index a783343..0000000
--- a/res/drawable-xhdpi/scrubber_vertical_secondary_holo.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/scrubber_vertical_track_holo_dark.9.png b/res/drawable-xhdpi/scrubber_vertical_track_holo_dark.9.png
deleted file mode 100644
index 5f0fc26..0000000
--- a/res/drawable-xhdpi/scrubber_vertical_track_holo_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/scrubber_vertical_track_holo_light.9.png b/res/drawable-xhdpi/scrubber_vertical_track_holo_light.9.png
deleted file mode 100644
index fc89474..0000000
--- a/res/drawable-xhdpi/scrubber_vertical_track_holo_light.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_device_bluetooth.png b/res/drawable-xxhdpi/ic_action_device_bluetooth.png
new file mode 100644
index 0000000..8aea295
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_device_bluetooth.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_device_headphones.png b/res/drawable-xxhdpi/ic_action_device_headphones.png
new file mode 100644
index 0000000..d9c52d1
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_device_headphones.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_device_speaker.png b/res/drawable-xxhdpi/ic_action_device_speaker.png
new file mode 100644
index 0000000..d3eaaa1
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_device_speaker.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_device_usb.png b/res/drawable-xxhdpi/ic_action_device_usb.png
new file mode 100644
index 0000000..30708bd
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_device_usb.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_dsp_icons_bluetoof.png b/res/drawable-xxhdpi/ic_action_dsp_icons_bluetoof.png
new file mode 100644
index 0000000..7bd8dfe
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_dsp_icons_bluetoof.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_dsp_icons_headphones.png b/res/drawable-xxhdpi/ic_action_dsp_icons_headphones.png
new file mode 100644
index 0000000..b571992
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_dsp_icons_headphones.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_dsp_icons_speaker.png b/res/drawable-xxhdpi/ic_action_dsp_icons_speaker.png
new file mode 100644
index 0000000..2faaa1c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_dsp_icons_speaker.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_dsp_icons_usb.png b/res/drawable-xxhdpi/ic_action_dsp_icons_usb.png
new file mode 100644
index 0000000..df93498
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_dsp_icons_usb.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_dsp_icons_wifi.png b/res/drawable-xxhdpi/ic_action_dsp_icons_wifi.png
new file mode 100644
index 0000000..eaa3a38
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_dsp_icons_wifi.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_lock_open.png b/res/drawable-xxhdpi/ic_action_lock_open.png
new file mode 100644
index 0000000..9ed6219
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_lock_open.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_lock_outline.png b/res/drawable-xxhdpi/ic_action_lock_outline.png
new file mode 100644
index 0000000..cab70f3
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_lock_outline.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_content_add_circle_outline.png b/res/drawable-xxhdpi/ic_content_add_circle_outline.png
new file mode 100644
index 0000000..dabb3be
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_content_add_circle_outline.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_content_clear.png b/res/drawable-xxhdpi/ic_content_clear.png
new file mode 100644
index 0000000..e2d1bec
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_content_clear.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_content_create.png b/res/drawable-xxhdpi/ic_content_create.png
new file mode 100644
index 0000000..98c9332
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_content_create.png
Binary files differ
diff --git a/res/drawable-xxhdpi/knob.png b/res/drawable-xxhdpi/knob.png
deleted file mode 100644
index 4cd9670..0000000
--- a/res/drawable-xxhdpi/knob.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/toggle_check_off.png b/res/drawable-xxhdpi/toggle_check_off.png
new file mode 100755
index 0000000..20e5439
--- /dev/null
+++ b/res/drawable-xxhdpi/toggle_check_off.png
Binary files differ
diff --git a/res/drawable-xxhdpi/toggle_check_on.png b/res/drawable-xxhdpi/toggle_check_on.png
new file mode 100755
index 0000000..81f3299
--- /dev/null
+++ b/res/drawable-xxhdpi/toggle_check_on.png
Binary files differ
diff --git a/res/drawable-xxhdpi/toggle_check_on_disabled.png b/res/drawable-xxhdpi/toggle_check_on_disabled.png
new file mode 100644
index 0000000..b25911b
--- /dev/null
+++ b/res/drawable-xxhdpi/toggle_check_on_disabled.png
Binary files differ
diff --git a/res/drawable/above_shadow.xml b/res/drawable/above_shadow.xml
new file mode 100644
index 0000000..cf890b9
--- /dev/null
+++ b/res/drawable/above_shadow.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:startColor="#20000000"
+ android:endColor="@android:color/transparent"
+ android:angle="90" >
+ </gradient>
+</shape> \ No newline at end of file
diff --git a/res/drawable/below_shadow.xml b/res/drawable/below_shadow.xml
new file mode 100644
index 0000000..3255f0e
--- /dev/null
+++ b/res/drawable/below_shadow.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <gradient
+ android:startColor="#20000000"
+ android:endColor="@android:color/transparent"
+ android:angle="270" >
+ </gradient>
+</shape> \ No newline at end of file
diff --git a/res/drawable/dash.xml b/res/drawable/dash.xml
new file mode 100644
index 0000000..dbd88ba
--- /dev/null
+++ b/res/drawable/dash.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="line">
+
+ <solid android:color="#ffffffff"/>
+ <stroke
+ android:color="#66ffffff"
+ android:width="1dp"
+ android:dashWidth="1dp"
+ android:dashGap="1dp" />
+</shape> \ No newline at end of file
diff --git a/res/drawable/ic_action_dsp_icons_lineout.xml b/res/drawable/ic_action_dsp_icons_lineout.xml
new file mode 100644
index 0000000..ab04210
--- /dev/null
+++ b/res/drawable/ic_action_dsp_icons_lineout.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2016 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#CCFFFFFF"
+ android:pathData="M17 2H7c-1.1 0-2 .9-2 2v16c0 1.1 .9 1.99 2 1.99L17 22c1.1 0 2-.9
+2-2V4c0-1.1-.9-2-2-2zm-5 2c1.1 0 2 .9 2 2s-.9 2-2 2c-1.11 0-2-.9-2-2s.89-2
+2-2zm0 16c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3
+1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z" />
+</vector> \ No newline at end of file
diff --git a/res/drawable/ic_qs_visualizer_off.xml b/res/drawable/ic_qs_visualizer_off.xml
new file mode 100644
index 0000000..87b5df9
--- /dev/null
+++ b/res/drawable/ic_qs_visualizer_off.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#a5a5a5"
+ android:pathData="M14,42H6v-4h8V42Z M28,38h-8v4h8V38z M42,38h-8v4h8V38z M14,30H6v4h8V30z
+M28,30h-8v4h8 V30z M42,30h-8v4h8V30z M14,22H6v4h8V22z M28,22h-8v4h8V22z
+M42,22h-8v4h8V22z M28,14h-8v4h8V14z M42,14h-8v4h8V14z M28,6h-8v4h8V6z" />
+</vector> \ No newline at end of file
diff --git a/res/drawable/ic_qs_visualizer_on.xml b/res/drawable/ic_qs_visualizer_on.xml
new file mode 100644
index 0000000..8ef7991
--- /dev/null
+++ b/res/drawable/ic_qs_visualizer_on.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M14,42H6v-4h8V42Z M28,38h-8v4h8V38z M42,38h-8v4h8V38z M14,30H6v4h8V30z
+M28,30h-8v4h8 V30z M42,30h-8v4h8V30z M14,22H6v4h8V22z M28,22h-8v4h8V22z
+M42,22h-8v4h8V22z M28,14h-8v4h8V14z M42,14h-8v4h8V14z M28,6h-8v4h8V6z" />
+</vector> \ No newline at end of file
diff --git a/res/drawable/logo_dts_1c.xml b/res/drawable/logo_dts_1c.xml
new file mode 100644
index 0000000..ed81042
--- /dev/null
+++ b/res/drawable/logo_dts_1c.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="24dp"
+ android:viewportWidth="60"
+ android:viewportHeight="24">
+
+ <group>
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M4.5,6.3c0,0-0.1-0.1-0.1-0.1C5.5,4.8,9,3.7,13.2,3.6c5.1-0.1,9.2,1.3,9.4,3.2
+c0,0,0,0.4,0,1.2l0,0c-0.4-1.7-4.3-3.3-9.1-3.6C9.3,4.2,5.7,5,4.5,6.3L4.5,6.3z
+M5.6,7.2c1.7-0.8,4.6-1.3,7.9-1.1
+c4.8,0.3,8.7,1.8,9.1,3.6l0,0c0-0.7,0-1.2,0-1.2c-0.1-1.8-4.3-3.3-9.4-3.2C9.9,5.3,7,6,5.3,7C5.3,7,5.5,7.1,5.6,7.2L5.6,7.2z
+M7.8,8.1c1.6-0.4,3.6-0.5,5.8-0.4c4.8,0.3,8.7,1.8,9.1,3.6v0c0-0.7,0-1.2,0-1.2c-0.1-1.8-4.3-3.3-9.4-3.2c-2.4,0-4.5,0.4-6.1,0.9
+C7.1,7.8,7.4,8,7.8,8.1L7.8,8.1z
+M4,5.2c0.6-1.5,4.6-2.7,9.5-2.4c4.8,0.3,8.7,1.8,9.1,3.6l0-0.1c0-1-0.1-1.3-0.1-1.3
+c0-0.2-0.1-0.3-0.1-0.3c-0.7-1.6-4.5-2.8-9.2-2.7C8.4,2.1,4.4,3.5,4,5.2L4,5.2z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M22.2,10.5c-1.1,1.4-4.7,2.5-8.9,2.5C8.2,13.1,4.1,11.7,4,9.9c0,0,0-0.4,0-1.2l0,0
+c0.4,1.7,4.3,3.3,9.1,3.6c4.2,0.3,7.8-0.5,9.1-1.9C22.1,10.4,22.2,10.5,22.2,10.5L22.2,10.5z
+M21.2,9.7C21.1,9.6,21,9.5,21,9.5
+c-1.7,0.8-4.6,1.3-7.9,1.1C8.2,10.3,4.4,8.8,4,7.1l0,0c0,0.7,0,1.2,0,1.2c0.1,1.8,4.3,3.3,9.4,3.2C16.7,11.4,19.6,10.7,21.2,9.7
+L21.2,9.7z
+M19.4,8.8c-0.4-0.1-0.7-0.2-0.7-0.2C17.2,9,15.2,9.1,13,9C8.2,8.7,4.4,7.1,4,5.4l0,0c0,0.7,0,1.2,0,1.2
+c0.1,1.8,4.3,3.3,9.4,3.2C15.7,9.7,17.8,9.4,19.4,8.8L19.4,8.8z
+M22.5,11.5C22,13,17.9,14.2,13,13.9c-4.8-0.3-8.7-1.8-9.1-3.6
+l0,0.1c0,1,0.1,1.3,0.1,1.3c0,0.2,0.1,0.3,0.1,0.3c0.7,1.6,4.5,2.8,9.2,2.7C18.2,14.6,22.1,13.2,22.5,11.5L22.5,11.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M37.6,14.5c-2.4,0-4.3,0-4.3,0c-2.3,0.1-3.5,0-3.5,0c-2.5,0-4.5-1.7-4.6-3.9
+c-0.1-2.1,1.7-3.9,4.3-4c0,0,1.2-0.1,3.2,0.2l0-0.2l0-4.3l5,0l0,4.6H40V5.3l4.8-2.1l0,3.6l1.7,0l0,1.3c-0.9,0-1.7,0-1.7,0v2.4
+c0,0.1,0,1.2,0,1.5c0,0,0.1,0.7,0.6,1.1c0,0,0.3,0.3,1,0.3c0,0,0.2,0,0.6,0h1.1l0,0c0.9,0,1.1-0.2,1.1-0.2c0.4-0.2,0.6-0.5,0.6-0.9
+c0-0.3-0.1-0.6-0.3-0.8l0,0l-1.3-1.2C48,10,47.8,9.7,47.7,9.6l0,0c-0.2-0.3-0.2-0.6-0.2-0.9c0-0.6,0.4-1.2,0.9-1.5l0,0
+C48.8,6.9,51.2,6,55.6,7l0,1.1l-0.1,0c0,0-1.2-0.1-1.6,0l0,0c-0.4,0.1-0.6,0.3-0.6,0.7c0,0.2,0.1,0.4,0.2,0.5l0,0l1.7,1.7l0,0
+c0.4,0.4,0.6,0.8,0.6,1.4c0,0.9-0.6,1.6-1.4,1.9c0,0-0.5,0.2-1.3,0.2c0,0-0.4,0-1.5,0h-0.1c-3.9,0-8,0-8,0l-0.1,0
+c-2.6-0.1-3.1-2-3.1-2c-0.1-0.4-0.2-1.3-0.2-1.3l0-3.2l-2.4,0L37.6,14.5
+M29.8,10.7c0,1.3,0.6,2,0.6,2c0.4,0.5,1.2,0.6,1.2,0.6
+c0.4,0.1,1,0,1,0l0-5.3c0,0-0.6-0.1-1,0c0,0-0.7,0-1.2,0.7c0,0-0.6,0.7-0.6,2V10.7z
+M27.4,22c-1.1,0-1.5-0.5-1.5-1.5v-0.1h0.6v0.1
+c0,0.6,0.1,1,0.8,1c0.6,0,0.8-0.3,0.8-0.9c0-0.7-0.4-0.9-0.9-1.1c-0.7-0.4-1.3-0.7-1.3-1.7c0-0.9,0.6-1.3,1.4-1.3
+c0.9,0,1.4,0.4,1.4,1.3V18h-0.6v-0.1c0-0.5-0.1-0.8-0.8-0.8c-0.5,0-0.8,0.3-0.8,0.8c0,0.7,0.5,0.9,1.1,1.2c0.6,0.4,1.1,0.6,1.1,1.6
+C28.8,21.5,28.3,22,27.4,22z
+M33.9,22c-1.2,0-1.3-0.8-1.3-1.9c0-1.1,0.1-2,1.3-2c1.2,0,1.2,0.8,1.2,1.9C35.2,21.3,35.1,22,33.9,22z
+M34.6,19.9c0-0.6,0-1.3-0.7-1.3c-0.7,0-0.7,0.8-0.7,1.3v0.5c0,0.5,0,1.1,0.7,1.1c0.6,0,0.7-0.6,0.7-1.1V19.9z
+M41.2,21.9l0-0.5
+C41,21.8,40.7,22,40.3,22c-0.7,0-1-0.5-1-1.1v-2.6h0.6v2.4c0,0.4,0,1,0.6,1c0.6,0,0.7-0.6,0.7-1.1v-2.2h0.6v2.9c0,0.3,0,0.5,0,0.8
+H41.2z
+M47.8,22v-2.4c0-0.4,0-1-0.6-1c-0.5,0-0.7,0.6-0.7,1.1V22h-0.6v-2.9c0-0.3,0-0.5,0-0.8h0.6v0.5c0.2-0.3,0.5-0.6,1-0.6
+c0.7,0,1,0.5,1,1.1V22H47.8z
+M54.4,21.9l0-0.4C54.2,21.8,54,22,53.6,22c-1.1,0-1.1-1.1-1.1-2c0-0.9,0.1-1.9,1.1-1.9
+c0.4,0,0.7,0.1,0.8,0.4v-2H55v4.6c0,0.2,0,0.5,0,0.7H54.4z
+M53.7,18.6c-0.7,0-0.7,0.8-0.7,1.5c0,0.8,0.1,1.5,0.7,1.5
+c0.7,0,0.7-0.8,0.7-1.4C54.4,19.3,54.4,18.6,53.7,18.6z
+M55.1,2.1c0.2,0,0.3,0,0.5,0.1c0.1,0.1,0.3,0.2,0.3,0.3
+C56,2.8,56,2.9,56,3.1c0,0.2,0,0.3-0.1,0.5c-0.1,0.1-0.2,0.3-0.3,0.3C55.4,4,55.3,4,55.1,4c-0.2,0-0.3,0-0.5-0.1
+c-0.1-0.1-0.3-0.2-0.3-0.3c-0.1-0.1-0.1-0.3-0.1-0.5c0-0.2,0-0.3,0.1-0.5c0.1-0.1,0.2-0.3,0.3-0.3C54.8,2.2,55,2.1,55.1,2.1z
+M55.1,2.3c-0.1,0-0.3,0-0.4,0.1c-0.1,0.1-0.2,0.2-0.3,0.3c-0.1,0.1-0.1,0.3-0.1,0.4c0,0.1,0,0.3,0.1,0.4c0.1,0.1,0.2,0.2,0.3,0.3
+c0.1,0.1,0.3,0.1,0.4,0.1c0.1,0,0.3,0,0.4-0.1c0.1-0.1,0.2-0.2,0.3-0.3c0.1-0.1,0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4
+c-0.1-0.1-0.2-0.2-0.3-0.3C55.4,2.3,55.2,2.3,55.1,2.3z
+M54.7,3.6v-1H55c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0.1,0.1,0.1c0,0,0,0.1,0,0.1
+c0,0.1,0,0.1-0.1,0.2c-0.1,0.1-0.1,0.1-0.2,0.1c0,0,0.1,0,0.1,0.1c0,0,0.1,0.1,0.1,0.2l0.1,0.2h-0.2l-0.1-0.2
+c-0.1-0.1-0.1-0.2-0.2-0.2c0,0-0.1,0-0.1,0h-0.1v0.4H54.7z
+M54.9,3h0.2c0.1,0,0.2,0,0.2,0c0,0,0.1-0.1,0.1-0.1c0,0,0-0.1,0-0.1
+c0,0,0,0-0.1-0.1c0,0-0.1,0-0.2,0h-0.2V3z" />
+ </group>
+</vector> \ No newline at end of file
diff --git a/res/drawable/logo_dts_fc.xml b/res/drawable/logo_dts_fc.xml
new file mode 100644
index 0000000..a9abeb3
--- /dev/null
+++ b/res/drawable/logo_dts_fc.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2015 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="60dp"
+ android:height="24dp"
+ android:viewportWidth="60"
+ android:viewportHeight="24">
+
+ <group>
+ <path
+ android:fillColor="#FDB813"
+ android:pathData="M4.5,6.3c0,0-0.1-0.1-0.1-0.1C5.5,4.8,9,3.7,13.2,3.6c5.1-0.1,9.2,1.3,9.4,3.2
+c0,0,0,0.4,0,1.2l0,0c-0.4-1.7-4.3-3.3-9.1-3.6C9.3,4.2,5.7,5,4.5,6.3L4.5,6.3z
+M5.6,7.2c1.7-0.8,4.6-1.3,7.9-1.1
+c4.8,0.3,8.7,1.8,9.1,3.6l0,0c0-0.7,0-1.2,0-1.2c-0.1-1.8-4.3-3.3-9.4-3.2C9.9,5.3,7,6,5.3,7C5.3,7,5.5,7.1,5.6,7.2L5.6,7.2z
+M7.8,8.1c1.6-0.4,3.6-0.5,5.8-0.4c4.8,0.3,8.7,1.8,9.1,3.6v0c0-0.7,0-1.2,0-1.2c-0.1-1.8-4.3-3.3-9.4-3.2c-2.4,0-4.5,0.4-6.1,0.9
+C7.1,7.8,7.4,8,7.8,8.1L7.8,8.1z
+M4,5.2c0.6-1.5,4.6-2.7,9.5-2.4c4.8,0.3,8.7,1.8,9.1,3.6l0-0.1c0-1-0.1-1.3-0.1-1.3
+c0-0.2-0.1-0.3-0.1-0.3c-0.7-1.6-4.5-2.8-9.2-2.7C8.4,2.1,4.4,3.5,4,5.2L4,5.2z" />
+ <path
+ android:fillColor="#F16521"
+ android:pathData="M22.2,10.5c-1.1,1.4-4.7,2.5-8.9,2.5C8.2,13.1,4.1,11.7,4,9.9c0,0,0-0.4,0-1.2l0,0
+c0.4,1.7,4.3,3.3,9.1,3.6c4.2,0.3,7.8-0.5,9.1-1.9C22.1,10.4,22.2,10.5,22.2,10.5L22.2,10.5z
+M21.2,9.7C21.1,9.6,21,9.5,21,9.5
+c-1.7,0.8-4.6,1.3-7.9,1.1C8.2,10.3,4.4,8.8,4,7.1l0,0c0,0.7,0,1.2,0,1.2c0.1,1.8,4.3,3.3,9.4,3.2C16.7,11.4,19.6,10.7,21.2,9.7
+L21.2,9.7z
+M19.4,8.8c-0.4-0.1-0.7-0.2-0.7-0.2C17.2,9,15.2,9.1,13,9C8.2,8.7,4.4,7.1,4,5.4l0,0c0,0.7,0,1.2,0,1.2
+c0.1,1.8,4.3,3.3,9.4,3.2C15.7,9.7,17.8,9.4,19.4,8.8L19.4,8.8z
+M22.5,11.5C22,13,17.9,14.2,13,13.9c-4.8-0.3-8.7-1.8-9.1-3.6
+l0,0.1c0,1,0.1,1.3,0.1,1.3c0,0.2,0.1,0.3,0.1,0.3c0.7,1.6,4.5,2.8,9.2,2.7C18.2,14.6,22.1,13.2,22.5,11.5L22.5,11.5z" />
+ <path
+ android:fillColor="#FFFFFF"
+ android:pathData="M37.6,14.5c-2.4,0-4.3,0-4.3,0c-2.3,0.1-3.5,0-3.5,0c-2.5,0-4.5-1.7-4.6-3.9
+c-0.1-2.1,1.7-3.9,4.3-4c0,0,1.2-0.1,3.2,0.2l0-0.2l0-4.3l5,0l0,4.6H40V5.3l4.8-2.1l0,3.6l1.7,0l0,1.3c-0.9,0-1.7,0-1.7,0v2.4
+c0,0.1,0,1.2,0,1.5c0,0,0.1,0.7,0.6,1.1c0,0,0.3,0.3,1,0.3c0,0,0.2,0,0.6,0h1.1l0,0c0.9,0,1.1-0.2,1.1-0.2c0.4-0.2,0.6-0.5,0.6-0.9
+c0-0.3-0.1-0.6-0.3-0.8l0,0l-1.3-1.2C48,10,47.8,9.7,47.7,9.6l0,0c-0.2-0.3-0.2-0.6-0.2-0.9c0-0.6,0.4-1.2,0.9-1.5l0,0
+C48.8,6.9,51.2,6,55.6,7l0,1.1l-0.1,0c0,0-1.2-0.1-1.6,0l0,0c-0.4,0.1-0.6,0.3-0.6,0.7c0,0.2,0.1,0.4,0.2,0.5l0,0l1.7,1.7l0,0
+c0.4,0.4,0.6,0.8,0.6,1.4c0,0.9-0.6,1.6-1.4,1.9c0,0-0.5,0.2-1.3,0.2c0,0-0.4,0-1.5,0h-0.1c-3.9,0-8,0-8,0l-0.1,0
+c-2.6-0.1-3.1-2-3.1-2c-0.1-0.4-0.2-1.3-0.2-1.3l0-3.2l-2.4,0L37.6,14.5
+M29.8,10.7c0,1.3,0.6,2,0.6,2c0.4,0.5,1.2,0.6,1.2,0.6
+c0.4,0.1,1,0,1,0l0-5.3c0,0-0.6-0.1-1,0c0,0-0.7,0-1.2,0.7c0,0-0.6,0.7-0.6,2V10.7z
+M27.4,22c-1.1,0-1.5-0.5-1.5-1.5v-0.1h0.6v0.1
+c0,0.6,0.1,1,0.8,1c0.6,0,0.8-0.3,0.8-0.9c0-0.7-0.4-0.9-0.9-1.1c-0.7-0.4-1.3-0.7-1.3-1.7c0-0.9,0.6-1.3,1.4-1.3
+c0.9,0,1.4,0.4,1.4,1.3V18h-0.6v-0.1c0-0.5-0.1-0.8-0.8-0.8c-0.5,0-0.8,0.3-0.8,0.8c0,0.7,0.5,0.9,1.1,1.2c0.6,0.4,1.1,0.6,1.1,1.6
+C28.8,21.5,28.3,22,27.4,22z
+M33.9,22c-1.2,0-1.3-0.8-1.3-1.9c0-1.1,0.1-2,1.3-2c1.2,0,1.2,0.8,1.2,1.9C35.2,21.3,35.1,22,33.9,22z
+M34.6,19.9c0-0.6,0-1.3-0.7-1.3c-0.7,0-0.7,0.8-0.7,1.3v0.5c0,0.5,0,1.1,0.7,1.1c0.6,0,0.7-0.6,0.7-1.1V19.9z
+M41.2,21.9l0-0.5
+C41,21.8,40.7,22,40.3,22c-0.7,0-1-0.5-1-1.1v-2.6h0.6v2.4c0,0.4,0,1,0.6,1c0.6,0,0.7-0.6,0.7-1.1v-2.2h0.6v2.9c0,0.3,0,0.5,0,0.8
+H41.2z
+M47.8,22v-2.4c0-0.4,0-1-0.6-1c-0.5,0-0.7,0.6-0.7,1.1V22h-0.6v-2.9c0-0.3,0-0.5,0-0.8h0.6v0.5c0.2-0.3,0.5-0.6,1-0.6
+c0.7,0,1,0.5,1,1.1V22H47.8z
+M54.4,21.9l0-0.4C54.2,21.8,54,22,53.6,22c-1.1,0-1.1-1.1-1.1-2c0-0.9,0.1-1.9,1.1-1.9
+c0.4,0,0.7,0.1,0.8,0.4v-2H55v4.6c0,0.2,0,0.5,0,0.7H54.4z
+M53.7,18.6c-0.7,0-0.7,0.8-0.7,1.5c0,0.8,0.1,1.5,0.7,1.5
+c0.7,0,0.7-0.8,0.7-1.4C54.4,19.3,54.4,18.6,53.7,18.6z
+M55.1,2.1c0.2,0,0.3,0,0.5,0.1c0.1,0.1,0.3,0.2,0.3,0.3
+C56,2.8,56,2.9,56,3.1c0,0.2,0,0.3-0.1,0.5c-0.1,0.1-0.2,0.3-0.3,0.3C55.4,4,55.3,4,55.1,4c-0.2,0-0.3,0-0.5-0.1
+c-0.1-0.1-0.3-0.2-0.3-0.3c-0.1-0.1-0.1-0.3-0.1-0.5c0-0.2,0-0.3,0.1-0.5c0.1-0.1,0.2-0.3,0.3-0.3C54.8,2.2,55,2.1,55.1,2.1z
+M55.1,2.3c-0.1,0-0.3,0-0.4,0.1c-0.1,0.1-0.2,0.2-0.3,0.3c-0.1,0.1-0.1,0.3-0.1,0.4c0,0.1,0,0.3,0.1,0.4c0.1,0.1,0.2,0.2,0.3,0.3
+c0.1,0.1,0.3,0.1,0.4,0.1c0.1,0,0.3,0,0.4-0.1c0.1-0.1,0.2-0.2,0.3-0.3c0.1-0.1,0.1-0.3,0.1-0.4c0-0.1,0-0.3-0.1-0.4
+c-0.1-0.1-0.2-0.2-0.3-0.3C55.4,2.3,55.2,2.3,55.1,2.3z
+M54.7,3.6v-1H55c0.1,0,0.2,0,0.3,0c0.1,0,0.1,0.1,0.1,0.1c0,0,0,0.1,0,0.1
+c0,0.1,0,0.1-0.1,0.2c-0.1,0.1-0.1,0.1-0.2,0.1c0,0,0.1,0,0.1,0.1c0,0,0.1,0.1,0.1,0.2l0.1,0.2h-0.2l-0.1-0.2
+c-0.1-0.1-0.1-0.2-0.2-0.2c0,0-0.1,0-0.1,0h-0.1v0.4H54.7z
+M54.9,3h0.2c0.1,0,0.2,0,0.2,0c0,0,0.1-0.1,0.1-0.1c0,0,0-0.1,0-0.1
+c0,0,0,0-0.1-0.1c0,0-0.1,0-0.2,0h-0.2V3z" />
+ </group>
+</vector>
diff --git a/res/drawable/maxvolume_white.png b/res/drawable/maxvolume_white.png
new file mode 100644
index 0000000..1df2aef
--- /dev/null
+++ b/res/drawable/maxvolume_white.png
Binary files differ
diff --git a/res/drawable/maxxbass_white.png b/res/drawable/maxxbass_white.png
new file mode 100644
index 0000000..118602b
--- /dev/null
+++ b/res/drawable/maxxbass_white.png
Binary files differ
diff --git a/res/drawable/maxxreble_white.png b/res/drawable/maxxreble_white.png
new file mode 100644
index 0000000..44b8688
--- /dev/null
+++ b/res/drawable/maxxreble_white.png
Binary files differ
diff --git a/res/drawable/maxxspace_white.png b/res/drawable/maxxspace_white.png
new file mode 100644
index 0000000..726ac03
--- /dev/null
+++ b/res/drawable/maxxspace_white.png
Binary files differ
diff --git a/res/drawable/progress_vertical_holo_dark.xml b/res/drawable/progress_vertical_holo_dark.xml
deleted file mode 100644
index 9eb54b7..0000000
--- a/res/drawable/progress_vertical_holo_dark.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:id="@android:id/background"
- android:drawable="@drawable/progress_vertical_bg_holo_dark" />
-
- <item android:id="@android:id/secondaryProgress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/progress_vertical_secondary_holo_dark" />
- </item>
-
- <item android:id="@android:id/progress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/progress_vertical_primary_holo_dark" />
- </item>
-
-</layer-list>
diff --git a/res/drawable/scrubber_control_selector_holo.xml b/res/drawable/scrubber_control_selector_holo.xml
deleted file mode 100644
index f53b6b3..0000000
--- a/res/drawable/scrubber_control_selector_holo.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2013, The Linux Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false" android:drawable="@drawable/scrubber_control_disabled_holo" />
- <item android:state_pressed="true" android:drawable="@drawable/scrubber_control_pressed_holo" />
- <item android:state_selected="true" android:drawable="@drawable/scrubber_control_focused_holo" />
- <item android:drawable="@drawable/scrubber_control_normal_holo" />
-</selector>
diff --git a/res/drawable/scrubber_progress_vertical_holo_dark.xml b/res/drawable/scrubber_progress_vertical_holo_dark.xml
deleted file mode 100644
index 0cc56bf..0000000
--- a/res/drawable/scrubber_progress_vertical_holo_dark.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@android:id/background"
- android:drawable="@drawable/scrubber_vertical_track_holo_dark" />
- <item android:id="@android:id/secondaryProgress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/scrubber_vertical_secondary_holo" />
- </item>
- <item android:id="@android:id/progress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/scrubber_vertical_primary_holo" />
- </item>
-</layer-list>
diff --git a/res/drawable/scrubber_progress_vertical_holo_light.xml b/res/drawable/scrubber_progress_vertical_holo_light.xml
deleted file mode 100644
index 8a54edf..0000000
--- a/res/drawable/scrubber_progress_vertical_holo_light.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@android:id/background"
- android:drawable="@drawable/scrubber_vertical_track_holo_light" />
- <item android:id="@android:id/secondaryProgress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/scrubber_vertical_secondary_holo" />
- </item>
- <item android:id="@android:id/progress">
- <scale android:scaleHeight="100%" android:scaleGravity="bottom"
- android:drawable="@drawable/scrubber_vertical_primary_holo" />
- </item>
-</layer-list>
diff --git a/res/drawable/toggle_check.xml b/res/drawable/toggle_check.xml
new file mode 100644
index 0000000..a58137c
--- /dev/null
+++ b/res/drawable/toggle_check.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_checked="true">
+ <bitmap android:src="@drawable/toggle_check_on_disabled" android:gravity="top"/>
+ </item>
+
+ <item android:state_checked="true">
+ <bitmap android:src="@drawable/toggle_check_on" android:gravity="top"/>
+ </item>
+
+ <item android:state_checked="false">
+ <bitmap android:src="@drawable/toggle_check_off" android:gravity="top"/>
+ </item>
+</selector> \ No newline at end of file
diff --git a/res/drawable/toggle_lock.xml b/res/drawable/toggle_lock.xml
new file mode 100644
index 0000000..f63c24f
--- /dev/null
+++ b/res/drawable/toggle_lock.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_enabled="false" android:state_checked="true" android:drawable="@drawable/ic_action_lock_outline"/>
+
+ <item android:state_checked="true" android:drawable="@drawable/ic_action_lock_outline"/>
+
+ <item android:state_checked="false" android:drawable="@drawable/ic_action_lock_open"/>
+</selector> \ No newline at end of file
diff --git a/res/layout-land/activity_main.xml b/res/layout-land/activity_main.xml
new file mode 100644
index 0000000..bfae19c
--- /dev/null
+++ b/res/layout-land/activity_main.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/main_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
diff --git a/res/layout-land/controls_generic.xml b/res/layout-land/controls_generic.xml
new file mode 100644
index 0000000..b31ddcb
--- /dev/null
+++ b/res/layout-land/controls_generic.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.cyngn.audiofx.knobs.KnobContainer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@color/knob_container_background"
+ android:id="@+id/knob_container"
+ android:layout_width="160dp"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:orientation="vertical"
+ android:animateLayoutChanges="true"
+ android:elevation="8dp"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp"/>
diff --git a/res/layout-land/controls_maxx_audio.xml b/res/layout-land/controls_maxx_audio.xml
new file mode 100644
index 0000000..857f718
--- /dev/null
+++ b/res/layout-land/controls_maxx_audio.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@color/knob_container_background"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:elevation="8dp"
+ android:paddingLeft="20dp"
+ android:padding="4dp">
+
+ <LinearLayout
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:minHeight="?android:listPreferredItemHeightSmall"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal">
+
+ <ImageView
+ android:layout_width="83dp"
+ android:layout_height="22dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/maxvolume_white"
+ android:scaleType="fitCenter"/>
+
+ <Space
+ android:layout_width="12dp"
+ android:layout_height="match_parent"/>
+
+ <CheckBox
+ android:id="@+id/maxx_volume_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:button="@drawable/toggle_check"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"/>
+
+ </LinearLayout>
+
+ <com.cyngn.audiofx.knobs.KnobContainer
+ android:id="@+id/knob_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:gravity="top|center_horizontal"
+ android:orientation="vertical"
+ android:animateLayoutChanges="true"
+ android:layout_weight="1">
+
+ <!-- row 1 treble & bass -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="0dp"
+ android:orientation="horizontal">
+
+ <FrameLayout
+ android:id="@+id/treble_knob_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_width="@dimen/knob_width"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"/>
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="76dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxreble_white"
+ android:scaleType="fitCenter"/>
+
+ </FrameLayout>
+
+ <FrameLayout
+ android:visibility="gone"
+ android:id="@+id/virtualizer_knob_container"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="@dimen/knob_width"
+ android:layout_height="wrap_content"/>
+
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="69dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxspace_white"
+ android:scaleType="fitCenter"/>
+ </FrameLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_weight="1"
+ android:layout_height="0dp"
+ android:orientation="horizontal">
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="1"
+ android:id="@+id/bass_knob_container"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="@dimen/knob_width"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"/>
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="68dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxbass_white"
+ android:scaleType="fitCenter"/>
+
+ </FrameLayout>
+ </LinearLayout>
+ </com.cyngn.audiofx.knobs.KnobContainer>
+
+</LinearLayout>
diff --git a/res/layout-land/fragment_audiofx.xml b/res/layout-land/fragment_audiofx.xml
new file mode 100644
index 0000000..76e3e59
--- /dev/null
+++ b/res/layout-land/fragment_audiofx.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.cyngn.audiofx.widget.InterceptableLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/interceptable_layout"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- equalizer layout -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.EqualizerFragment"
+ android:id="@+id/equalizer"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ <!-- knobs -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.ControlsFragment"
+ android:id="@+id/controls"
+ android:layout_weight="0"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
+
+</com.cyngn.audiofx.widget.InterceptableLinearLayout>
diff --git a/res/layout-land/fragment_audiofx_maxxaudio.xml b/res/layout-land/fragment_audiofx_maxxaudio.xml
new file mode 100644
index 0000000..76e3e59
--- /dev/null
+++ b/res/layout-land/fragment_audiofx_maxxaudio.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.cyngn.audiofx.widget.InterceptableLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/interceptable_layout"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- equalizer layout -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.EqualizerFragment"
+ android:id="@+id/equalizer"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ <!-- knobs -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.ControlsFragment"
+ android:id="@+id/controls"
+ android:layout_weight="0"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"/>
+
+</com.cyngn.audiofx.widget.InterceptableLinearLayout>
diff --git a/res/layout-land/generic_knob_control.xml b/res/layout-land/generic_knob_control.xml
new file mode 100644
index 0000000..38883e1
--- /dev/null
+++ b/res/layout-land/generic_knob_control.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="0"
+ android:layout_gravity="center_vertical"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/knob_width" />
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="22dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="wrap_content"/>
+
+</FrameLayout>
diff --git a/res/layout/action_bar_custom_components.xml b/res/layout/action_bar_custom_components.xml
new file mode 100644
index 0000000..3d65eb3
--- /dev/null
+++ b/res/layout/action_bar_custom_components.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+
+ <ViewStub
+ android:id="@+id/logo_stub"
+ android:gravity="center_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <CheckBox
+ android:id="@+id/global_toggle"
+ android:layout_gravity="center_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:button="@drawable/toggle_check"
+ android:paddingRight="@dimen/action_bar_switch_padding"
+ />
+
+</LinearLayout>
diff --git a/res/layout/action_bar_dts_logo.xml b/res/layout/action_bar_dts_logo.xml
new file mode 100644
index 0000000..89a439c
--- /dev/null
+++ b/res/layout/action_bar_dts_logo.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingRight="@dimen/action_bar_dts_switch_padding">
+
+ <TextView
+ android:text="@string/powered_by"
+ android:layout_gravity="center_horizontal"
+ android:textSize="10sp"
+ android:typeface="sans"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
+
+ <ImageView
+ android:id="@+id/dts_logo"
+ android:src="@drawable/logo_dts_fc"
+ android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="0dp"
+ />
+
+
+</LinearLayout>
diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml
new file mode 100644
index 0000000..e6c9f53
--- /dev/null
+++ b/res/layout/activity_main.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/main_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+</FrameLayout>
diff --git a/res/layout/controls_generic.xml b/res/layout/controls_generic.xml
new file mode 100644
index 0000000..48b8e2f
--- /dev/null
+++ b/res/layout/controls_generic.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.cyngn.audiofx.knobs.KnobContainer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@color/knob_container_background"
+ android:id="@+id/knob_container"
+ android:gravity="top|center_horizontal"
+ android:orientation="horizontal"
+ android:animateLayoutChanges="true"
+ android:layout_width="match_parent"
+ android:layout_height="160dp"
+ android:elevation="8dp"
+ android:padding="4dp"
+ android:layout_weight="1"/>
diff --git a/res/layout/controls_maxx_audio.xml b/res/layout/controls_maxx_audio.xml
new file mode 100644
index 0000000..9d75cd7
--- /dev/null
+++ b/res/layout/controls_maxx_audio.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:background="@color/knob_container_background"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="200dp"
+ android:elevation="8dp"
+ android:padding="4dp">
+
+ <LinearLayout
+ android:paddingLeft="30dp"
+ android:paddingRight="30dp"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:minHeight="?android:listPreferredItemHeightSmall"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal">
+
+ <ImageView
+ android:layout_width="83dp"
+ android:layout_height="22dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/maxvolume_white"
+ android:scaleType="fitCenter"/>
+
+ <Space
+ android:layout_width="12dp"
+ android:layout_height="match_parent"/>
+
+ <CheckBox
+ android:id="@+id/maxx_volume_switch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:button="@drawable/toggle_check"
+ android:gravity="center_vertical"
+ android:layout_gravity="center_vertical"/>
+
+ </LinearLayout>
+
+ <com.cyngn.audiofx.knobs.KnobContainer
+ android:id="@+id/knob_container"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:gravity="top|center_horizontal"
+ android:orientation="horizontal"
+ android:animateLayoutChanges="true"
+ android:layout_weight="1">
+
+ <Space
+ android:layout_weight="0.1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ <FrameLayout
+ android:id="@+id/treble_knob_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_weight="0"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_width="@dimen/knob_width"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"/>
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="76dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxreble_white"
+ android:scaleType="fitCenter"/>
+
+ </FrameLayout>
+
+ <Space
+ android:layout_weight="0.1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="0"
+ android:id="@+id/bass_knob_container"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="@dimen/knob_width"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"/>
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="68dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxbass_white"
+ android:scaleType="fitCenter"/>
+
+ </FrameLayout>
+
+ <Space
+ android:layout_weight="0.1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ <FrameLayout
+ android:visibility="gone"
+ android:id="@+id/virtualizer_knob_container"
+ android:layout_width="wrap_content"
+ android:layout_weight="0"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="@dimen/knob_width"
+ android:layout_height="wrap_content"/>
+
+
+ <ImageView
+ android:id="@+id/label"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="69dp"
+ android:layout_height="22dp"
+ android:src="@drawable/maxxspace_white"
+ android:scaleType="fitCenter"/>
+ </FrameLayout>
+
+ <Space
+ android:visibility="gone"
+ android:layout_weight="0.1"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"/>
+
+ </com.cyngn.audiofx.knobs.KnobContainer>
+
+</LinearLayout>
diff --git a/res/layout/eq_container.xml b/res/layout/eq_container.xml
new file mode 100644
index 0000000..e41defb
--- /dev/null
+++ b/res/layout/eq_container.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.cyngn.audiofx.eq.EqContainerView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/eq_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <FrameLayout
+ android:id="@+id/eq_controls"
+ android:padding="4dp"
+ android:alpha="0"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/remove"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_content_clear"
+ android:paddingRight="12dp"
+ />
+
+ <ImageView
+ android:id="@+id/rename"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_content_create"
+ android:paddingRight="12dp"
+ />
+ <CheckBox
+ android:id="@+id/lock"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:button="@drawable/toggle_lock"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_gravity="right"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent">
+ <ImageView
+ android:id="@+id/save"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_content_add_circle_outline"
+ />
+ </LinearLayout>
+
+ </FrameLayout>
+
+
+</com.cyngn.audiofx.eq.EqContainerView>
diff --git a/res/layout/equalizer.xml b/res/layout/equalizer.xml
index 2ebee34..0f2a613 100644
--- a/res/layout/equalizer.xml
+++ b/res/layout/equalizer.xml
@@ -1,16 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center"
- android:background="#cc191919"
- >
+<com.cyngn.audiofx.eq.EqSwipeController
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/swipe_interceptor"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <include
+ layout="@layout/eq_container"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"/>
- <org.cyanogenmod.audiofx.widget.EqualizerSurface
- android:id="@+id/frequencyResponse"
- android:layout_height="match_parent"
- android:layout_width="match_parent" />
+ <LinearLayout
+ android:orientation="vertical"
+ android:id="@+id/preset_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
-</LinearLayout>
+ <com.cyngn.audiofx.preset.InfiniteViewPager
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <com.cyngn.audiofx.viewpagerindicator.CirclePageIndicator
+ android:id="@+id/indicator"
+ android:padding="10dip"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ />
+
+ <android.support.v4.view.ViewPager
+ android:layout_height="0dp"
+ android:layout_width="0dp"
+ android:visibility="gone"
+ android:id="@+id/fake_pager"
+ />
+
+ </LinearLayout>
+</com.cyngn.audiofx.eq.EqSwipeController>
diff --git a/res/layout/fragment_audiofx.xml b/res/layout/fragment_audiofx.xml
new file mode 100644
index 0000000..c4bb367
--- /dev/null
+++ b/res/layout/fragment_audiofx.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.cyngn.audiofx.widget.InterceptableLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/interceptable_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- equalizer layout -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.EqualizerFragment"
+ android:id="@+id/equalizer"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"/>
+
+ <!-- knobs -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.ControlsFragment"
+ android:id="@+id/controls"
+ android:layout_weight="0"
+ android:layout_width="match_parent"
+ android:layout_height="160dp"/>
+
+</com.cyngn.audiofx.widget.InterceptableLinearLayout>
diff --git a/res/layout/fragment_audiofx_maxxaudio.xml b/res/layout/fragment_audiofx_maxxaudio.xml
new file mode 100644
index 0000000..3f5a022
--- /dev/null
+++ b/res/layout/fragment_audiofx_maxxaudio.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.cyngn.audiofx.widget.InterceptableLinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res/com.cyngn.audiofx"
+ android:id="@+id/interceptable_layout"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <!-- equalizer layout -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.EqualizerFragment"
+ android:id="@+id/equalizer"
+ android:layout_weight="1"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"/>
+
+ <!-- knobs -->
+ <FrameLayout class="com.cyngn.audiofx.fragment.ControlsFragment"
+ android:id="@+id/controls"
+ android:layout_weight="0"
+ android:layout_width="match_parent"
+ android:layout_height="200dp"/>
+
+</com.cyngn.audiofx.widget.InterceptableLinearLayout>
diff --git a/res/layout/fragment_dts.xml b/res/layout/fragment_dts.xml
new file mode 100644
index 0000000..785b996
--- /dev/null
+++ b/res/layout/fragment_dts.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/logo"
+ android:layout_width="120dp"
+ android:layout_height="48dp"
+ android:layout_centerInParent="true"
+ android:src="@drawable/logo_dts_1c"
+ />
+
+</RelativeLayout>
diff --git a/res/layout/generic_knob_control.xml b/res/layout/generic_knob_control.xml
new file mode 100644
index 0000000..6d9f531
--- /dev/null
+++ b/res/layout/generic_knob_control.xml
@@ -0,0 +1,20 @@
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="center_horizontal"
+ android:layout_weight="0"
+ android:paddingBottom="@dimen/knob_container_padding_bottom">
+
+ <com.cyngn.audiofx.knobs.RadialKnob
+ android:id="@+id/knob"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_width="@dimen/knob_width"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/label"
+ android:layout_height="22dp"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_width="wrap_content"/>
+
+</FrameLayout>
diff --git a/res/layout/knob.xml b/res/layout/knob.xml
deleted file mode 100644
index 57030e7..0000000
--- a/res/layout/knob.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2013, The Linux Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- tools:context=".ActivityMusic">
-
- <ImageView
- android:id="@+id/knob_foreground"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
- <ImageView
- android:id="@+id/knob_toggle_on"
- android:layout_gravity="center_horizontal|center_vertical"
- android:layout_width="21px"
- android:layout_height="21px"
- android:src="@drawable/knob_simple"
- android:visibility="gone" />
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_gravity="center_horizontal"
- android:orientation="vertical"
- android:gravity="center_horizontal">
-
- <TextView
- android:id="@+id/knob_value"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone" />
- <TextView
- android:id="@+id/knob_label"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:textAlignment="center"
- android:ellipsize="marquee"
- android:visibility="gone" />
- </LinearLayout>
-
-</FrameLayout>
diff --git a/res/layout/music_main.xml b/res/layout/music_main.xml
deleted file mode 100644
index b797c55..0000000
--- a/res/layout/music_main.xml
+++ /dev/null
@@ -1,174 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!-- Copyright (C) 2010-2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:custom="http://schemas.android.com/apk/res/org.cyanogenmod.audiofx"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <TextView
- android:id="@+id/noEffectsTextView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:layout_gravity="center"
- android:gravity="center"
- android:text="@string/no_effects"
- android:layout_weight="1"
- android:visibility="gone"/>
-
- <org.cyanogenmod.audiofx.widget.InterceptableLinearLayout
- android:id="@+id/contentSoundEffects"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_weight="1"
- android:layout_height="0dp">
-
- <include
- layout="@layout/equalizer"
- android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="2"/>
-
- <View
- android:layout_width="match_parent"
- android:layout_height="20dp"
- android:background="@color/audiofx_background_color"
- />
-
- <TextView
- android:id="@+id/eq_preset_label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/eq_preset_label_text_color"
- android:layout_gravity="center"
- android:gravity="center"
- android:textSize="10sp"
- android:background="@color/audiofx_background_color"
- android:text="@string/eq_preset"
- android:textAllCaps="true"/>
-
- <org.cyanogenmod.audiofx.widget.Gallery
- android:id="@+id/eqPresets"
- android:layout_width="match_parent"
- android:layout_height="48dip"
- android:background="@color/audiofx_background_color"
- android:gravity="center_vertical"/>
-
-
- <View
- android:layout_width="match_parent"
- android:layout_height="20dp"
- />
-
- <!--<FrameLayout-->
- <!--android:layout_width="match_parent"-->
- <!--android:layout_height="0dip"-->
- <!--android:layout_weight="23">-->
-
- <!--<com.pheelicks.visualizer.VisualizerView-->
- <!--android:id="@+id/visualizerView"-->
- <!--android:layout_width="match_parent"-->
- <!--android:layout_height="match_parent">-->
- <!--</com.pheelicks.visualizer.VisualizerView>-->
-
- <!--<LinearLayout-->
- <!--android:layout_width="match_parent"-->
- <!--android:layout_height="0dp"-->
- <!--android:orientation="vertical"-->
- <!--android:layout_weight="1">-->
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center"
- android:orientation="horizontal">
-
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- />
-
- <org.cyanogenmod.audiofx.widget.Knob
- android:id="@+id/bBStrengthKnob"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- custom:label="@string/bass_boost_strength"
- custom:foreground="@drawable/knob_large"/>
-
- <Space
- android:layout_weight="2"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- />
-
- <org.cyanogenmod.audiofx.widget.Knob
- android:id="@+id/vIStrengthKnob"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="10dip"
- custom:label="@string/virtualizer_strength"
- custom:foreground="@drawable/knob_large"/>
-
- <Space
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- />
- </LinearLayout>
-
-
- <!--<View-->
- <!--android:layout_width="match_parent"-->
- <!--android:layout_height="1dp"-->
- <!--android:background="@color/disabled"/>-->
-
- <View
- android:layout_width="match_parent"
- android:layout_height="20dp"
- />
-
- <TextView
- android:id="@+id/reverb_label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="@color/reverb_label_text_color"
- android:layout_gravity="center"
- android:gravity="center"
- android:background="@color/audiofx_background_color"
- android:paddingTop="8dp"
- android:textSize="10sp"
- android:text="@string/reverb"
- android:textAllCaps="true"/>
-
-
- <org.cyanogenmod.audiofx.widget.Gallery
- android:id="@+id/reverb_gallery"
- android:layout_width="match_parent"
- android:layout_height="40dip"
- android:background="@color/audiofx_background_color"
- android:gravity="center_vertical"/>
-
-
- <!--</FrameLayout>-->
-
- </org.cyanogenmod.audiofx.widget.InterceptableLinearLayout>
-</LinearLayout>
diff --git a/res/layout/preset_adapter_row.xml b/res/layout/preset_adapter_row.xml
new file mode 100644
index 0000000..f7e6e86
--- /dev/null
+++ b/res/layout/preset_adapter_row.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/text"
+
+ android:layout_gravity="center"
+ android:fontFamily="sans-serif"
+ android:textStyle="bold"
+ android:textSize="@dimen/preset_text_size"
+ android:gravity="center"
+ android:layout_margin="@dimen/preset_text_padding"
+ android:textColor="@color/white"
+ android:textAllCaps="true"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
diff --git a/res/menu/devices.xml b/res/menu/devices.xml
new file mode 100644
index 0000000..ddcf02b
--- /dev/null
+++ b/res/menu/devices.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:title="@string/devices"
+ android:id="@+id/devices"
+ android:icon="@drawable/ic_action_dsp_icons_speaker"
+ android:showAsAction="ifRoom">
+ <menu>
+ <group android:id="@+id/device_group">
+ </group>
+ </menu>
+ </item>
+</menu>
diff --git a/res/mipmap-hdpi/ic_launcher.png b/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a22b1fc
--- /dev/null
+++ b/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-mdpi/ic_launcher.png b/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..cd0f81e
--- /dev/null
+++ b/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xhdpi/ic_launcher.png b/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..0150eb5
--- /dev/null
+++ b/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xxhdpi/ic_launcher.png b/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..6cef165
--- /dev/null
+++ b/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/res/mipmap-xxxhdpi/ic_launcher.png b/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..7e6e264
--- /dev/null
+++ b/res/mipmap-xxxhdpi/ic_launcher.png
Binary files differ
diff --git a/res/values-af/cm_strings.xml b/res/values-af/cm_strings.xml
index ae00872..e3015bc 100644
--- a/res/values-af/cm_strings.xml
+++ b/res/values-af/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normaal</string>
<string name="classical">Klassiek</string>
<string name="dance">Dans</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronies</string>
+ <string name="ci_extreme">Elektronies</string>
<string name="small_speakers">Klein luidsprekers</string>
- <string name="custom">Persoonlik</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Persoonlik</string>
+ <string name="user_n">Persoonlik <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Geen</string>
<string name="smallroom">Klein kamer</string>
<string name="mediumroom">Medium kamer</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effek nie beskikbaar vir Luidspreker modus.</string>
<string name="device_headset">Oorfone</string>
<string name="device_speaker">Luidspreker</string>
- <string name="device_lineout">Line out</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Koordloos</string>
<string name="reverb">Galm</string>
<string name="eq_preset">Voorafbepaalde gelykmaker</string>
+ <string name="devices">Toestelle</string>
+ <string name="virtualizer">Virtualiseerder</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bas</string>
+ <string name="rename">Hernoem</string>
+ <string name="remove_custom_preset_warning_message">Is jy seker jy wil dit verwyder %1$s?</string>
</resources>
diff --git a/res/values-ar/cm_strings.xml b/res/values-ar/cm_strings.xml
index 6bc6060..3191570 100644
--- a/res/values-ar/cm_strings.xml
+++ b/res/values-ar/cm_strings.xml
@@ -15,20 +15,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <string name="normal">عادي</string>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="normal">عاديّ</string>
<string name="classical">كلاسيكي</string>
<string name="dance">رقص</string>
<string name="flat">معتدل</string>
<string name="folk">شعبي</string>
<string name="heavy_metal">المعادن الثقيلة</string>
<string name="hip_hop">الهيب هوب</string>
- <string name="jazz">الجاز</string>
+ <string name="jazz">موسيقى الجاز</string>
<string name="pop">البوب</string>
<string name="rock">روك</string>
- <string name="electronic">إلكتروني</string>
+ <string name="ci_extreme">إلكتروني</string>
<string name="small_speakers">سماعات صغيرة</string>
- <string name="custom">مخصص</string>
+ <string name="multimedia">وسائط متعددة</string>
+ <string name="user">مخصص</string>
+ <string name="user_n">مخصص<xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">بلا</string>
<string name="smallroom">غرفة صغيرة</string>
<string name="mediumroom">غرفة متوسطة</string>
@@ -36,14 +38,19 @@
<string name="mediumhall">قاعة متوسطة</string>
<string name="largehall">قاعة كبيرة</string>
<string name="plate">لوح</string>
- <string name="power_on_prompt">اضغط على زر الطاقة في الجزء الأيمن العلوي.</string>
- <string name="effect_unavalable_for_speaker">التأثير غير متاح لوضع السماعة.</string>
+ <string name="power_on_prompt">اضغط على زر التشغيل في أعلى اليمين.</string>
+ <string name="effect_unavalable_for_speaker">التأثير غير متاح لوضع السماعات.</string>
<string name="device_headset">سماعة الرأس</string>
<string name="device_speaker">سماعة</string>
- <string name="device_lineout">توصيل</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">بلوتوث</string>
<string name="device_wireless">لاسلكي</string>
<string name="reverb">الصدى</string>
<string name="eq_preset">التعيين المسبق للمعادل</string>
+ <string name="devices">أجهزة</string>
+ <string name="virtualizer">أداة الظاهرية</string>
+ <string name="treble">الطنين الثلاثي</string>
+ <string name="bass">الجهير</string>
+ <string name="rename">إعادة تسمية</string>
+ <string name="remove_custom_preset_warning_message">هل تريد بالتأكيد إزالة %1$s؟</string>
</resources>
diff --git a/res/values-as-rIN/cm_strings.xml b/res/values-as-rIN/cm_strings.xml
index d90f79c..a7ce35c 100644
--- a/res/values-as-rIN/cm_strings.xml
+++ b/res/values-as-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">সাধাৰণ</string>
<string name="classical">ধ্ৰুপদী</string>
<string name="dance">নৃত্য</string>
@@ -26,9 +26,11 @@
<string name="jazz">জেজ</string>
<string name="pop">পপ</string>
<string name="rock">ৰক</string>
- <string name="electronic">ইলেক্ট্ৰনিক</string>
+ <string name="ci_extreme">ইলেক্ট্ৰনিক</string>
<string name="small_speakers">সৰু স্পিকাৰ</string>
- <string name="custom">কাষ্টম</string>
+ <string name="multimedia">মাল্টিমিডিয়া</string>
+ <string name="user">কাষ্টম</string>
+ <string name="user_n">কাষ্টম<xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">হাল্লা</string>
<string name="smallroom">সৰু কোঠা</string>
<string name="mediumroom">মধ্যমীয়া কোঠা</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">বেতাঁৰ</string>
<string name="reverb">ৰিভাৰ্ব</string>
<string name="eq_preset">ইকুইলাইজাৰ প্ৰিছেট</string>
+ <string name="devices">ডিভাইচসমূহ</string>
+ <string name="virtualizer">ভিজুৱেলাইজাৰ</string>
+ <string name="treble">ট্ৰেবল</string>
+ <string name="bass">বাছ</string>
+ <string name="rename">পুনঃনামাকৰণ</string>
+ <string name="remove_custom_preset_warning_message">আপুনি %1$s আঁতৰাব বিচৰাটো নিশ্চিত নে?</string>
</resources>
diff --git a/res/values-ast-rES/cm_strings.xml b/res/values-ast-rES/cm_strings.xml
index 9c73fcb..57a6b8f 100644
--- a/res/values-ast-rES/cm_strings.xml
+++ b/res/values-ast-rES/cm_strings.xml
@@ -26,9 +26,9 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
+ <string name="ci_extreme">Electronic</string>
<string name="small_speakers">Altavoces pequeños</string>
- <string name="custom">Custom</string>
+ <string name="user">Custom</string>
<string name="none">Nengún</string>
<string name="smallroom">Habitación pequeña</string>
<string name="mediumroom">Habitación media</string>
@@ -36,14 +36,14 @@
<string name="mediumhall">Sala media</string>
<string name="largehall">Sala grande</string>
<string name="plate">Estudiu</string>
+ <string name="eq_custom">Pa personalizar, seleiciona \'Custom\'</string>
<string name="power_on_prompt">Calca nel botón d\'apagar na parte superior a mandrecha.</string>
<string name="effect_unavalable_for_speaker">L\'efeutu nun ta disponible nel mou altavoz.</string>
<string name="device_headset">Auriculares</string>
<string name="device_speaker">Altavoz</string>
- <string name="device_lineout">Salida de llinia</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Wireless</string>
- <string name="reverb">Reverberación</string>
<string name="eq_preset">Ecualizador preestablecíu</string>
+ <string name="reverb">Reverberación</string>
</resources>
diff --git a/res/values-az-rAZ/cm_strings.xml b/res/values-az-rAZ/cm_strings.xml
index f80054c..3afc8ad 100644
--- a/res/values-az-rAZ/cm_strings.xml
+++ b/res/values-az-rAZ/cm_strings.xml
@@ -19,16 +19,14 @@
<string name="normal">Normal</string>
<string name="classical">Klassik</string>
<string name="dance">Rәqs</string>
- <string name="flat">Düz</string>
<string name="folk">Xalq</string>
<string name="heavy_metal">Ağır Metal</string>
<string name="hip_hop">Hip Hop</string>
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rok</string>
- <string name="electronic">Elektronik</string>
+ <string name="ci_extreme">Elektronik</string>
<string name="small_speakers">Kiçik səsucaldanlar</string>
- <string name="custom">Özəl</string>
<string name="none">Yoxdur</string>
<string name="smallroom">Balaca otaq</string>
<string name="mediumroom">Orta otaq</string>
@@ -42,7 +40,4 @@
<string name="device_speaker">Səsucaldan</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
- <string name="device_wireless">Simsiz</string>
- <string name="reverb">Əks-səda</string>
- <string name="eq_preset">Ekvalayzer hazır tənzimləmələri</string>
</resources>
diff --git a/res/values-be/cm_strings.xml b/res/values-be/cm_strings.xml
index 3ddabc8..e7be23f 100644
--- a/res/values-be/cm_strings.xml
+++ b/res/values-be/cm_strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.com-->
<!--
- Copyright (C) 2014-2015 The CyanogenMod Project
+ Copyright (C) 2014 The CyanogenMod Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,34 +15,42 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <string name="normal">Звычайная</string>
- <string name="classical">Класічная</string>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="normal">Звычайны</string>
+ <string name="classical">Класіка</string>
<string name="dance">Танцы</string>
- <string name="flat">Пляската</string>
+ <string name="flat">Flat</string>
<string name="folk">Фолк</string>
- <string name="heavy_metal">Хэві-метал</string>
+ <string name="heavy_metal">Heavy Metal</string>
<string name="hip_hop">Хіп-хоп</string>
<string name="jazz">Джаз</string>
<string name="pop">Поп</string>
<string name="rock">Рок</string>
- <string name="electronic">Электронная музыка</string>
+ <string name="ci_extreme">Электронная музыка</string>
<string name="small_speakers">Малыя дынамікі</string>
- <string name="custom">Карыстальніцкія</string>
+ <string name="multimedia">Мультымедыя</string>
+ <string name="user">Уласныя налады</string>
+ <string name="user_n">Карыстацкія налады <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Няма</string>
- <string name="smallroom">Маленькі пакой</string>
+ <string name="smallroom">Малы пакой</string>
<string name="mediumroom">Сярэдні пакой</string>
<string name="largeroom">Вялікі пакой</string>
<string name="mediumhall">Сярэдняя зала</string>
<string name="largehall">Вялікая зала</string>
- <string name="plate">Пласцінка</string>
- <string name="power_on_prompt">Націсніце вымыкач у правым верхнім куце.</string>
- <string name="effect_unavalable_for_speaker">Эфект недаступны для дынамікаў.</string>
- <string name="device_headset">Слухаўкі</string>
+ <string name="plate">Грамафон</string>
+ <string name="power_on_prompt">Націсніце выключальнік у правым верхнім куце.</string>
+ <string name="effect_unavalable_for_speaker">Эфект не даступны для дынамікаў.</string>
+ <string name="device_headset">Гарнітура</string>
<string name="device_speaker">Дынамік</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
- <string name="device_wireless">Бесправодныя прылады</string>
+ <string name="device_wireless">Бесправадная прылада</string>
<string name="reverb">Рэверберацыя</string>
- <string name="eq_preset">Прадусталёўкі эквалайзера</string>
+ <string name="eq_preset">Нарыхтоўка эквалайзера</string>
+ <string name="devices">Прылады</string>
+ <string name="virtualizer">Віртуалізацыя</string>
+ <string name="treble">Высокія частоты</string>
+ <string name="bass">Бас</string>
+ <string name="rename">Пераназваць</string>
+ <string name="remove_custom_preset_warning_message">Вы сапраўды хочаце выдаліць %1$s?</string>
</resources>
diff --git a/res/values-bg/cm_strings.xml b/res/values-bg/cm_strings.xml
index e458da6..eb81cd7 100644
--- a/res/values-bg/cm_strings.xml
+++ b/res/values-bg/cm_strings.xml
@@ -15,8 +15,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <string name="normal">Нормална</string>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="normal">Нормално</string>
<string name="classical">Класическа</string>
<string name="dance">Танцувална</string>
<string name="flat">Плосък</string>
@@ -26,12 +26,14 @@
<string name="jazz">Джаз</string>
<string name="pop">Поп</string>
<string name="rock">Рок</string>
- <string name="electronic">Електронна</string>
+ <string name="ci_extreme">Електронна</string>
<string name="small_speakers">Малки говорители</string>
- <string name="custom">По избор</string>
+ <string name="multimedia">Мултимедия</string>
+ <string name="user">По избор</string>
+ <string name="user_n">По избор <xliff:g id="preset_num">%1$d </xliff:g></string>
<string name="none">Без</string>
<string name="smallroom">Малка стая</string>
- <string name="mediumroom">Среднa стая</string>
+ <string name="mediumroom">Средна стая</string>
<string name="largeroom">Голяма стая</string>
<string name="mediumhall">Средна зала</string>
<string name="largehall">Голяма зала</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Ефекта не е достъпен за високоговорителя.</string>
<string name="device_headset">Слушалки</string>
<string name="device_speaker">Говорител</string>
- <string name="device_lineout">Линеен изход</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Безжичен</string>
<string name="reverb">Ехо</string>
<string name="eq_preset">Настройки на еквалайзера</string>
+ <string name="devices">Устройства</string>
+ <string name="virtualizer">Виртуализатор</string>
+ <string name="treble">Троен</string>
+ <string name="bass">Бас</string>
+ <string name="rename">Преименуване</string>
+ <string name="remove_custom_preset_warning_message">Сигурни ли сте, че искате да премахнете %1$s?</string>
</resources>
diff --git a/res/values-bn-rBD/cm_strings.xml b/res/values-bn-rBD/cm_strings.xml
index 0888203..4f3a763 100644
--- a/res/values-bn-rBD/cm_strings.xml
+++ b/res/values-bn-rBD/cm_strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--Generated by crowdin.com-->
<!--
- Copyright (C) 2014-2015 The CyanogenMod Project
+ Copyright (C) 2014 The CyanogenMod Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">স্বাভাবিক</string>
<string name="classical">ধ্রুপদী</string>
<string name="dance">নৃত্য</string>
@@ -26,9 +26,9 @@
<string name="jazz">জ্যাজ</string>
<string name="pop">পপ</string>
<string name="rock">রক</string>
- <string name="electronic">ইলেকট্রনিক</string>
+ <string name="ci_extreme">ইলেকট্রনিক</string>
<string name="small_speakers">ছোট স্পিকার</string>
- <string name="custom">পছন্দসই</string>
+ <string name="user">পছন্দসই</string>
<string name="none">কোনটি না</string>
<string name="smallroom">ছোট ঘর</string>
<string name="mediumroom">মধ্যম ঘর</string>
diff --git a/res/values-bn/cm_strings.xml b/res/values-bn/cm_strings.xml
new file mode 100644
index 0000000..6e62161
--- /dev/null
+++ b/res/values-bn/cm_strings.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!--
+ Copyright (C) 2014 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="normal">স্বাভাবিক</string>
+ <string name="classical">ধ্রুপদী</string>
+ <string name="dance">নৃত্য</string>
+ <string name="flat">ফ্ল্যাট</string>
+ <string name="folk">লোকগীতি</string>
+ <string name="heavy_metal">হেভি মেটাল</string>
+ <string name="hip_hop">হিপ-হপ</string>
+ <string name="jazz">জ্যাজ</string>
+ <string name="pop">পপ</string>
+ <string name="rock">রক</string>
+ <string name="ci_extreme">ইলেকট্রনিক</string>
+ <string name="small_speakers">ছোট স্পিকার</string>
+ <string name="user">পছন্দসই</string>
+ <string name="none">কোনটি না</string>
+ <string name="smallroom">ছোট ঘর</string>
+ <string name="mediumroom">মধ্যম ঘর</string>
+ <string name="largeroom">বড় ঘর</string>
+ <string name="mediumhall">মধ্যম হল</string>
+ <string name="largehall">বড় হল</string>
+ <string name="plate">প্লেট</string>
+ <string name="eq_custom">পছন্দসই-বিন্যাস করতে, \'পছন্দসই\' নির্বাচন করুন</string>
+ <string name="power_on_prompt">উপরের-ডানে পাওয়ার বোতাম চাপুন।</string>
+ <string name="effect_unavalable_for_speaker">স্পীকারের জন্য প্রভাব উপলব্ধ নয়।</string>
+ <string name="device_headset">হেডসেট</string>
+ <string name="device_speaker">স্পীকার</string>
+ <string name="device_usb">ইউএসবি</string>
+ <string name="device_bluetooth">ব্লুটুথ</string>
+ <string name="device_wireless">ওয়্যারলেস</string>
+ <string name="eq_preset">ইকুয়ালাইজার বিন্যাস-পূর্বাবস্থা</string>
+ <string name="reverb">প্রতিধ্বনি</string>
+</resources>
diff --git a/res/values-ca/cm_strings.xml b/res/values-ca/cm_strings.xml
index a9d614e..c87ca5d 100644
--- a/res/values-ca/cm_strings.xml
+++ b/res/values-ca/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clàssica</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electrònica</string>
+ <string name="ci_extreme">Electrònica</string>
<string name="small_speakers">Altaveus petits</string>
- <string name="custom">Personalitzat</string>
+ <string name="multimedia">Multimèdia</string>
+ <string name="user">Personalitzat</string>
+ <string name="user_n">Personalitzat <xliff:g id="preset_num">%1$d </xliff:g></string>
<string name="none">Cap</string>
<string name="smallroom">Habitació petita</string>
<string name="mediumroom">Habitació mitjana</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">L\'efecte no està disponible en el mode Altaveu.</string>
<string name="device_headset">Auriculars</string>
<string name="device_speaker">Altaveu</string>
- <string name="device_lineout">Sortida de línia</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Sense fils</string>
<string name="reverb">Reverberació</string>
<string name="eq_preset">Presintonia de l\'equalitzador</string>
+ <string name="devices">Dispositius</string>
+ <string name="virtualizer">Virtualitzador</string>
+ <string name="treble">Aguts</string>
+ <string name="bass">Greus</string>
+ <string name="rename">Reanomena</string>
+ <string name="remove_custom_preset_warning_message">Estàs segur que vols esborrar %1$s?</string>
</resources>
diff --git a/res/values-cs/cm_strings.xml b/res/values-cs/cm_strings.xml
index 957874a..b0e1e8c 100644
--- a/res/values-cs/cm_strings.xml
+++ b/res/values-cs/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normalní</string>
<string name="classical">Klasická hudba</string>
<string name="dance">Taneční</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronická</string>
+ <string name="ci_extreme">Elektronická</string>
<string name="small_speakers">Malé reproduktory</string>
- <string name="custom">Vlastní</string>
+ <string name="multimedia">Multimédia</string>
+ <string name="user">Vlastní</string>
+ <string name="user_n">Vlastní <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Žádný</string>
<string name="smallroom">Malá místnost</string>
<string name="mediumroom">Střední místnost</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efekt není pro režim reproduktoru dostupný.</string>
<string name="device_headset">Sluchátka</string>
<string name="device_speaker">Reproduktor</string>
- <string name="device_lineout">Linkový výstup</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Bezdrátové</string>
<string name="reverb">Dozvuku</string>
<string name="eq_preset">Předvolba ekvalizéru</string>
+ <string name="devices">Zařízení</string>
+ <string name="virtualizer">Virtualizér</string>
+ <string name="treble">Výšky</string>
+ <string name="bass">Basy</string>
+ <string name="rename">Přejmenovat</string>
+ <string name="remove_custom_preset_warning_message">Opravdu chcete odstranit %1$s?</string>
</resources>
diff --git a/res/values-da/cm_strings.xml b/res/values-da/cm_strings.xml
index 3cc09e5..1b731a8 100644
--- a/res/values-da/cm_strings.xml
+++ b/res/values-da/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klassisk</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronisk</string>
+ <string name="ci_extreme">Elektronisk</string>
<string name="small_speakers">Små højttalere</string>
- <string name="custom">Brugerdefineret</string>
+ <string name="multimedia">Multimedier</string>
+ <string name="user">Brugerdefineret</string>
+ <string name="user_n">Tilpasset <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Ingen</string>
<string name="smallroom">Lille værelse</string>
<string name="mediumroom">Mellemstort værelse</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effekt ikke tilgængelig i Højttalertilstand.</string>
<string name="device_headset">Håndfri</string>
<string name="device_speaker">Højttaler</string>
- <string name="device_lineout">Linjeudgang</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Trådløs</string>
<string name="reverb">Rumklang</string>
<string name="eq_preset">Equalizer-forudindstilling</string>
+ <string name="devices">Enheder</string>
+ <string name="virtualizer">Virtualisator</string>
+ <string name="treble">Diskant</string>
+ <string name="bass">Bas</string>
+ <string name="rename">Omdøb</string>
+ <string name="remove_custom_preset_warning_message">Er du sikker på du vil fjerne %1$s?</string>
</resources>
diff --git a/res/values-de/cm_strings.xml b/res/values-de/cm_strings.xml
index e515b2b..b8199e0 100644
--- a/res/values-de/cm_strings.xml
+++ b/res/values-de/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klassik</string>
<string name="dance">Dance</string>
@@ -26,10 +26,12 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronisch</string>
+ <string name="ci_extreme">Elektronisch</string>
<string name="small_speakers">Kleine Lautsprecher</string>
- <string name="custom">Benutzerdefiniert</string>
- <string name="none">Keiner</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Benutzerdefiniert</string>
+ <string name="user_n">Benutzerdefiniert <xliff:g id="preset_num">%1$d </xliff:g></string>
+ <string name="none">Keine</string>
<string name="smallroom">Kleiner Raum</string>
<string name="mediumroom">Mittlerer Raum</string>
<string name="largeroom">Großer Raum</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effekt für Lautsprecher-Modus nicht verfügbar.</string>
<string name="device_headset">Kopfhörer</string>
<string name="device_speaker">Lautsprecher</string>
- <string name="device_lineout">Line-Ausgang</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Drahtlos</string>
<string name="reverb">Halleffekt</string>
<string name="eq_preset">Equalizer-Voreinstellung</string>
+ <string name="devices">Geräte</string>
+ <string name="virtualizer">Virtualisierung</string>
+ <string name="treble">Höhen</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Umbenennen</string>
+ <string name="remove_custom_preset_warning_message">Sind Sie sicher, dass Sie %1$s entfernen möchten?</string>
</resources>
diff --git a/res/values-el/cm_strings.xml b/res/values-el/cm_strings.xml
index 26fa04d..0030f99 100644
--- a/res/values-el/cm_strings.xml
+++ b/res/values-el/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Κανονικό</string>
<string name="classical">Κλασική</string>
<string name="dance">Χορευτική</string>
@@ -26,9 +26,11 @@
<string name="jazz">Τζαζ</string>
<string name="pop">Ποπ</string>
<string name="rock">Ροκ</string>
- <string name="electronic">Ηλεκτρονική</string>
+ <string name="ci_extreme">Ηλεκτρονική</string>
<string name="small_speakers">Μικρά ηχεία</string>
- <string name="custom">Προσαρμοσμένο</string>
+ <string name="multimedia">Πολυμέσα</string>
+ <string name="user">Προσαρμοσμένο</string>
+ <string name="user_n">Προσαρμοσμένο <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Κανένα</string>
<string name="smallroom">Μικρό δωμάτιο</string>
<string name="mediumroom">Μεσαίο δωμάτιο</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Το εφέ δεν είναι διαθέσιμο κατά την αναπαραγωγή από το ηχείο.</string>
<string name="device_headset">Ακουστικά</string>
<string name="device_speaker">Ήχειο</string>
- <string name="device_lineout">Έξοδος</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Ασύρματα</string>
<string name="reverb">Αντήχηση</string>
<string name="eq_preset">Προκαθορισμένη ρύθμιση ισοσταθμιστή</string>
+ <string name="devices">Συσκευές</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Πρίμα</string>
+ <string name="bass">Μπάσα</string>
+ <string name="rename">Μετονομασία</string>
+ <string name="remove_custom_preset_warning_message">Είστε βέβαιοι ότι θέλετε να διαγράψετε το %1$s;</string>
</resources>
diff --git a/res/values-en-rAU/cm_strings.xml b/res/values-en-rAU/cm_strings.xml
index 11ef81a..c7c1f08 100644
--- a/res/values-en-rAU/cm_strings.xml
+++ b/res/values-en-rAU/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Classical</string>
<string name="dance">Dance</string>
@@ -26,9 +26,9 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
+ <string name="ci_extreme">Electronic</string>
<string name="small_speakers">Small speakers</string>
- <string name="custom">Custom</string>
+ <string name="user">Custom</string>
<string name="none">None</string>
<string name="smallroom">Small room</string>
<string name="mediumroom">Medium room</string>
diff --git a/res/values-en-rIN/cm_strings.xml b/res/values-en-rIN/cm_strings.xml
index 41abf06..43a3277 100644
--- a/res/values-en-rIN/cm_strings.xml
+++ b/res/values-en-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Classical</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
+ <string name="ci_extreme">Electronic</string>
<string name="small_speakers">Small speakers</string>
- <string name="custom">Custom</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Custom</string>
+ <string name="user_n">Custom <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">None</string>
<string name="smallroom">Small room</string>
<string name="mediumroom">Medium room</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">Wireless</string>
<string name="reverb">Reverb</string>
<string name="eq_preset">Equalizer preset</string>
+ <string name="devices">Devices</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Rename</string>
+ <string name="remove_custom_preset_warning_message">Are you sure you want to remove %1$s?</string>
</resources>
diff --git a/res/values-es-rUS/cm_strings.xml b/res/values-es-rUS/cm_strings.xml
index 2540a88..befca2c 100644
--- a/res/values-es-rUS/cm_strings.xml
+++ b/res/values-es-rUS/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clásica</string>
<string name="dance">Dance</string>
@@ -26,24 +26,31 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electrónica</string>
+ <string name="ci_extreme">Electrónica</string>
<string name="small_speakers">Altavoces pequeños</string>
- <string name="custom">Personalizado</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personalizado</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> personalizado</string>
<string name="none">Ninguno</string>
<string name="smallroom">Habitación pequeña</string>
<string name="mediumroom">Habitación mediana</string>
- <string name="largeroom">Habitación grande</string>
+ <string name="largeroom">Gran habitación</string>
<string name="mediumhall">Sala mediana</string>
- <string name="largehall">Sala grande</string>
+ <string name="largehall">Gran sala</string>
<string name="plate">Vinilo</string>
<string name="power_on_prompt">Pulsar el botón de encendido en la parte superior derecha.</string>
<string name="effect_unavalable_for_speaker">Efecto no disponible para el modo altavoz.</string>
<string name="device_headset">Auriculares</string>
<string name="device_speaker">Altavoz</string>
- <string name="device_lineout">Salida de línea</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Inalámbrico</string>
<string name="reverb">Reverberación</string>
<string name="eq_preset">Ecualizador preestablecido</string>
+ <string name="devices">Dispositivos</string>
+ <string name="virtualizer">Virtualizador</string>
+ <string name="treble">Agudos</string>
+ <string name="bass">Bajos</string>
+ <string name="rename">Cambiar nombre</string>
+ <string name="remove_custom_preset_warning_message">¿Estás seguro de que deseas quitar %1$s?</string>
</resources>
diff --git a/res/values-es-rXA/strings.xml b/res/values-es-rXA/strings.xml
new file mode 100644
index 0000000..0c5dbe6
--- /dev/null
+++ b/res/values-es-rXA/strings.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!-- Copyright (C) 2010-2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="app_name">AudioFX</string>
+ <string name="no_effects">Efeutos non disponibles.</string>
+ <string name="main_toggle_effects_title">Efeutos d\'audiu</string>
+ <string name="eq_dialog_title">AudioFX</string>
+ <string name="headset_plug">Coneuta los auriculares pa estos efectos.</string>
+ <string name="bass_boost_strength">Bass boost</string>
+ <string name="virtualizer_strength">Soníu envolvente</string>
+ <string name="pr_title">Reverberación:</string>
+ <string name="pr_summary">Efeutos de reverberación de sala adicionales</string>
+ <string name="pr_dialog_title">Preaxuste de reverberación</string>
+ <string name="setup">Configuración</string>
+ <string name="picker_title">Panel de control d\'efeutos de música\"</string>
+</resources>
diff --git a/res/values-es/cm_strings.xml b/res/values-es/cm_strings.xml
index d4926cc..2d2113b 100644
--- a/res/values-es/cm_strings.xml
+++ b/res/values-es/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clásica</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electrónica</string>
+ <string name="ci_extreme">Electrónica</string>
<string name="small_speakers">Altavoces pequeños</string>
- <string name="custom">Personalizado</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personalizado</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> personalizado</string>
<string name="none">Ninguno</string>
<string name="smallroom">Habitación pequeña</string>
<string name="mediumroom">Habitación mediana</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efecto no disponible para el modo altavoz.</string>
<string name="device_headset">Auriculares</string>
<string name="device_speaker">Altavoz</string>
- <string name="device_lineout">Salida de línea</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Inalámbrico</string>
<string name="reverb">Reverberación</string>
<string name="eq_preset">Ecualizador preestablecido</string>
+ <string name="devices">Dispositivos</string>
+ <string name="virtualizer">Virtualizador</string>
+ <string name="treble">Agudos</string>
+ <string name="bass">Bajos</string>
+ <string name="rename">Cambiar el nombre</string>
+ <string name="remove_custom_preset_warning_message">¿Estás seguro que deseas eliminar %1$s?</string>
</resources>
diff --git a/res/values-et-rEE/cm_strings.xml b/res/values-et-rEE/cm_strings.xml
index 6dd71f1..02e026f 100644
--- a/res/values-et-rEE/cm_strings.xml
+++ b/res/values-et-rEE/cm_strings.xml
@@ -26,9 +26,9 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rokk</string>
- <string name="electronic">Elektrooniline</string>
+ <string name="ci_extreme">Elektrooniline</string>
<string name="small_speakers">Väiksed kõlarid</string>
- <string name="custom">Kohandatud</string>
+ <string name="user">Kohandatud</string>
<string name="none">Puudub</string>
<string name="smallroom">Väike tuba</string>
<string name="mediumroom">Keskmine tuba</string>
@@ -36,6 +36,7 @@
<string name="mediumhall">Keskmine hall</string>
<string name="largehall">Suur hall</string>
<string name="plate">Plate</string>
+ <string name="eq_custom">Kohandamiseks vali \'Kohandatud\'</string>
<string name="power_on_prompt">Vajutage power nuppu üleval paremal.</string>
<string name="effect_unavalable_for_speaker">Efekt puudub Kõlari-režiimis.</string>
<string name="device_headset">Peakomplekt</string>
@@ -43,6 +44,6 @@
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Juhtmeta</string>
- <string name="reverb">Peegeldus</string>
<string name="eq_preset">Ekvalaiseri eelsäte</string>
+ <string name="reverb">Peegeldus</string>
</resources>
diff --git a/res/values-fa/cm_strings.xml b/res/values-fa/cm_strings.xml
index 4991163..074d513 100644
--- a/res/values-fa/cm_strings.xml
+++ b/res/values-fa/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">عادی</string>
<string name="classical">کلاسیک</string>
<string name="dance">رقص</string>
@@ -26,9 +26,11 @@
<string name="jazz">جاز</string>
<string name="pop">پاپ</string>
<string name="rock">راک</string>
- <string name="electronic">الکترونیک</string>
+ <string name="ci_extreme">الکترونیک</string>
<string name="small_speakers">بلندگوهای کوچک</string>
- <string name="custom">سفارشی</string>
+ <string name="multimedia">چند رسانه‌ای</string>
+ <string name="user">سفارشی</string>
+ <string name="user_n">سفارشی <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">هیچ‌کدام</string>
<string name="smallroom">اتاق کوچک</string>
<string name="mediumroom">اتاق متوسط</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">بی‌سیم</string>
<string name="reverb">طنین</string>
<string name="eq_preset">اکولایزر تنظیم شده</string>
+ <string name="devices">دستگاه‌ها</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">صدای زیر</string>
+ <string name="bass">صدای بم</string>
+ <string name="rename">تغییرنام</string>
+ <string name="remove_custom_preset_warning_message">از حذف %1$s اطمینان دارید؟</string>
</resources>
diff --git a/res/values-fi/cm_strings.xml b/res/values-fi/cm_strings.xml
index 4bac476..79e2a9a 100644
--- a/res/values-fi/cm_strings.xml
+++ b/res/values-fi/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normaali</string>
<string name="classical">Klassinen</string>
<string name="dance">Tanssi</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektroninen</string>
+ <string name="ci_extreme">Elektroninen</string>
<string name="small_speakers">Pienet kaiuttimet</string>
- <string name="custom">Muokattu</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Muokattu</string>
+ <string name="user_n">Mukautettu <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Ei mitään</string>
<string name="smallroom">Pieni huone</string>
<string name="mediumroom">Keskikokoinen huone</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efekti ei käytettävissä kaiutintilassa.</string>
<string name="device_headset">Kuulokkeet</string>
<string name="device_speaker">Kaiutin</string>
- <string name="device_lineout">Ulostulo</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Langaton</string>
<string name="reverb">Kaikuefekti</string>
<string name="eq_preset">Taajuuskorjaimen esiasetus</string>
+ <string name="devices">Laitteet</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Diskantti</string>
+ <string name="bass">Basso</string>
+ <string name="rename">Nimeä uudelleen</string>
+ <string name="remove_custom_preset_warning_message">Haluatko varmasti poistaa asetusen %1$s?</string>
</resources>
diff --git a/res/values-fr-rCA/cm_strings.xml b/res/values-fr-rCA/cm_strings.xml
new file mode 100644
index 0000000..d1a2578
--- /dev/null
+++ b/res/values-fr-rCA/cm_strings.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!--
+ Copyright (C) 2014 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="normal">Normal</string>
+ <string name="classical">Classique</string>
+ <string name="dance">Dance</string>
+ <string name="flat">Plat</string>
+ <string name="folk">Folk</string>
+ <string name="heavy_metal">Heavy Metal</string>
+ <string name="hip_hop">Hip Hop</string>
+ <string name="jazz">Jazz</string>
+ <string name="pop">Pop</string>
+ <string name="rock">Rock</string>
+ <string name="ci_extreme">Électronique</string>
+ <string name="small_speakers">Petits haut-parleurs</string>
+ <string name="user">Personnalisé</string>
+ <string name="none">Aucun</string>
+ <string name="smallroom">Petite pièce</string>
+ <string name="mediumroom">Pièce moyenne</string>
+ <string name="largeroom">Grande pièce</string>
+ <string name="mediumhall">Salle moyenne</string>
+ <string name="largehall">Grande salle</string>
+ <string name="plate">Plat</string>
+ <string name="power_on_prompt">Appuyez sur le bouton d\'activation en haut à droite.</string>
+ <string name="effect_unavalable_for_speaker">Effet non disponible pour le mode haut-parleur.</string>
+ <string name="device_headset">Casque d\'écoute</string>
+ <string name="device_speaker">Haut-parleur</string>
+ <string name="device_usb">USB</string>
+ <string name="device_bluetooth">Périphérique Bluetooth</string>
+ <string name="device_wireless">Sans fil</string>
+ <string name="reverb">Réverbération</string>
+ <string name="eq_preset">Égaliseur prédéfini</string>
+</resources>
diff --git a/res/values-fr/cm_strings.xml b/res/values-fr/cm_strings.xml
index 8896d7e..13394c9 100644
--- a/res/values-fr/cm_strings.xml
+++ b/res/values-fr/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Classique</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Électronique</string>
+ <string name="ci_extreme">Électronique</string>
<string name="small_speakers">Petits haut-parleurs</string>
- <string name="custom">Personnalisé</string>
+ <string name="multimedia">Multimédia</string>
+ <string name="user">Personnalisé</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> personnalisé</string>
<string name="none">Aucun</string>
<string name="smallroom">Petite salle</string>
<string name="mediumroom">Salle moyenne</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effet non disponible pour le mode haut-parleur.</string>
<string name="device_headset">Casque</string>
<string name="device_speaker">Haut-parleur</string>
- <string name="device_lineout">Sortie ligne</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Sans fil</string>
<string name="reverb">Réverbération</string>
<string name="eq_preset">Égaliseur prédéfini</string>
+ <string name="devices">Appareils</string>
+ <string name="virtualizer">Virtualiseur</string>
+ <string name="treble">Aiguës</string>
+ <string name="bass">Basses</string>
+ <string name="rename">Renommer</string>
+ <string name="remove_custom_preset_warning_message">Êtes-vous sûr de vouloir supprimer %1$s ?</string>
</resources>
diff --git a/res/values-fy-rNL/cm_strings.xml b/res/values-fy-rNL/cm_strings.xml
new file mode 100644
index 0000000..ca92ab6
--- /dev/null
+++ b/res/values-fy-rNL/cm_strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!--
+ Copyright (C) 2014 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="none">Gjin</string>
+</resources>
diff --git a/res/values-gl-rES/cm_strings.xml b/res/values-gl-rES/cm_strings.xml
index 582d739..2c9ea9c 100644
--- a/res/values-gl-rES/cm_strings.xml
+++ b/res/values-gl-rES/cm_strings.xml
@@ -15,34 +15,30 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clásica</string>
<string name="dance">Dance</string>
<string name="flat">Plano</string>
- <string name="folk">Folk</string>
<string name="heavy_metal">Heavy Metal</string>
<string name="hip_hop">Hip Hop</string>
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electrónica</string>
- <string name="small_speakers">Altofalantes pequenos</string>
- <string name="custom">Personalizado</string>
+ <string name="ci_extreme">Electrónica</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personalizado</string>
<string name="none">Ningunha</string>
<string name="smallroom">Cuarto pequeno</string>
<string name="mediumroom">Cuarto mediano</string>
<string name="largeroom">Cuarto grande</string>
<string name="mediumhall">Sala mediana</string>
<string name="largehall">Sala grande</string>
- <string name="plate">Disco</string>
- <string name="power_on_prompt">Prema o botón de acendido na esquina dereita.</string>
- <string name="effect_unavalable_for_speaker">O efecto non está dispoñíbel no modo altavoz.</string>
- <string name="device_headset">Auriculares</string>
<string name="device_speaker">Altofalante</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Sen fíos</string>
- <string name="reverb">Reverberar</string>
- <string name="eq_preset">Ecualizador predefinido</string>
+ <string name="devices">Dispositivos</string>
+ <string name="treble">Agudos</string>
+ <string name="bass">Baixos</string>
</resources>
diff --git a/res/values-gl/cm_strings.xml b/res/values-gl/cm_strings.xml
new file mode 100644
index 0000000..161f0ff
--- /dev/null
+++ b/res/values-gl/cm_strings.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--Generated by crowdin.com-->
+<!--
+ Copyright (C) 2014 The CyanogenMod Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <string name="normal">Normal</string>
+ <string name="classical">Clásica</string>
+ <string name="dance">Dance</string>
+ <string name="flat">Plano</string>
+ <string name="jazz">Jazz</string>
+ <string name="rock">Rock</string>
+ <string name="ci_extreme">Electrónica</string>
+ <string name="user">Personalizado</string>
+ <string name="none">Ningunha</string>
+ <string name="smallroom">Cuarto pequeno</string>
+ <string name="mediumroom">Cuarto mediano</string>
+ <string name="largeroom">Cuarto grande</string>
+ <string name="mediumhall">Sala mediana</string>
+ <string name="largehall">Sala grande</string>
+ <string name="eq_custom">Para personalizar, seleccione «Personalizado»</string>
+ <string name="device_speaker">Altofalante</string>
+ <string name="device_usb">USB</string>
+ <string name="device_bluetooth">Bluetooth</string>
+</resources>
diff --git a/res/values-gu-rIN/cm_strings.xml b/res/values-gu-rIN/cm_strings.xml
index cad9bf9..30aa7f3 100644
--- a/res/values-gu-rIN/cm_strings.xml
+++ b/res/values-gu-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">સામાન્ય</string>
<string name="classical">શાસ્ત્રીય</string>
<string name="dance">નૃત્ય</string>
@@ -26,9 +26,11 @@
<string name="jazz">જેઝ</string>
<string name="pop">પોપ</string>
<string name="rock">ઝુમવુ</string>
- <string name="electronic">ઇલેક્ટ્રોનિક</string>
+ <string name="ci_extreme">ઇલેક્ટ્રોનિક</string>
<string name="small_speakers">નાના સ્પીકરો</string>
- <string name="custom">કસ્ટમ</string>
+ <string name="multimedia">મલ્ટિમિડિયા</string>
+ <string name="user">કસ્ટમ</string>
+ <string name="user_n">કસ્ટમ <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">કોઈ નહીં</string>
<string name="smallroom">નાનો ઓરડો</string>
<string name="mediumroom">મધ્યમ ઓરડો</string>
@@ -44,5 +46,11 @@
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">વાયરલેસ</string>
<string name="reverb">રિવર્બ</string>
- <string name="eq_preset">ઇક્વિલાઇઝર પ્રિસેટ</string>
+ <string name="eq_preset">ઈક્વલાઇઝર પ્રિસેટ</string>
+ <string name="devices">ઉપકરણો</string>
+ <string name="virtualizer">વર્ચુઅલાઇઝર</string>
+ <string name="treble">ટ્રેબલ</string>
+ <string name="bass">બાસ</string>
+ <string name="rename">નામ બદલો</string>
+ <string name="remove_custom_preset_warning_message">શું તમને ખાતરી છે કે તમારે %1$s દૂર કરવું છે?</string>
</resources>
diff --git a/res/layout/music_eq.xml b/res/values-hdpi/knobs.xml
index a7a5f36..216f472 100644
--- a/res/layout/music_eq.xml
+++ b/res/values-hdpi/knobs.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8" ?>
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2010-2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,12 +14,7 @@
limitations under the License.
-->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/eqcontainer"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="horizontal"
- android:gravity="center_horizontal">
-
-</LinearLayout>
+<resources>
+ <dimen name="radial_rect_padding">8dp</dimen>
+ <dimen name="radial_knob_stroke">15dp</dimen>
+</resources>
diff --git a/res/values-hr/cm_strings.xml b/res/values-hr/cm_strings.xml
index c512b7f..320f216 100644
--- a/res/values-hr/cm_strings.xml
+++ b/res/values-hr/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normalno</string>
<string name="classical">Klasika</string>
<string name="dance">Ples</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronska</string>
+ <string name="ci_extreme">Elektronska</string>
<string name="small_speakers">Mali zvučnici</string>
- <string name="custom">Prilagođeno</string>
+ <string name="multimedia">Multimedija</string>
+ <string name="user">Prilagođeno</string>
+ <string name="user_n">Prilagođeni <xliff:g id="preset_num">%1$d </xliff:g></string>
<string name="none">Ništa</string>
<string name="smallroom">Mala soba</string>
<string name="mediumroom">Srednja soba</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efekt nije dostupan za način Zvučnika.</string>
<string name="device_headset">Slušalice</string>
<string name="device_speaker">Zvučnik</string>
- <string name="device_lineout">Izlaz za slušalice</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Bežično</string>
<string name="reverb">Odjek</string>
<string name="eq_preset">Predlošci ekvilajzera</string>
+ <string name="devices">Uređaji</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Visoki tonovi</string>
+ <string name="bass">Bas gitara</string>
+ <string name="rename">Preimenuj</string>
+ <string name="remove_custom_preset_warning_message">Jeste li sigurni da želite ukloniti %1$s?</string>
</resources>
diff --git a/res/values-hu/cm_strings.xml b/res/values-hu/cm_strings.xml
index 35b5fb3..f480aaa 100644
--- a/res/values-hu/cm_strings.xml
+++ b/res/values-hu/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normál</string>
<string name="classical">Klasszikus</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronikus</string>
+ <string name="ci_extreme">Elektronikus</string>
<string name="small_speakers">Kis hangszórók</string>
- <string name="custom">Egyéni</string>
+ <string name="multimedia">Multimédia</string>
+ <string name="user">Egyéni</string>
+ <string name="user_n">Egyéni <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Nincs</string>
<string name="smallroom">Kis szoba</string>
<string name="mediumroom">Közepes szoba</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Hangszórót használva az effekt nem elérhető.</string>
<string name="device_headset">Fejhallgató</string>
<string name="device_speaker">Hangszóró</string>
- <string name="device_lineout">Vonal kimenet</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Vezeték nélküli</string>
<string name="reverb">Zengetés</string>
<string name="eq_preset">Hangszín minták</string>
+ <string name="devices">Eszközök</string>
+ <string name="virtualizer">Virtualizáló</string>
+ <string name="treble">Magas hang</string>
+ <string name="bass">Mélyhang</string>
+ <string name="rename">Átnevezés</string>
+ <string name="remove_custom_preset_warning_message">Biztosan el szeretné távolítani: %1$s?</string>
</resources>
diff --git a/res/values-in/cm_strings.xml b/res/values-in/cm_strings.xml
index e671d90..1c7c5dc 100644
--- a/res/values-in/cm_strings.xml
+++ b/res/values-in/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klasik</string>
<string name="dance">Dansa</string>
@@ -26,24 +26,31 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronik</string>
+ <string name="ci_extreme">Elektronik</string>
<string name="small_speakers">Speaker kecil</string>
- <string name="custom">Khusus</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Khusus</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> khusus</string>
<string name="none">Tidak Ada</string>
<string name="smallroom">Ruang kecil</string>
<string name="mediumroom">Ruang sedang</string>
<string name="largeroom">Ruang besar</string>
<string name="mediumhall">Aula sedang</string>
<string name="largehall">Aula besar</string>
- <string name="plate">Pelat</string>
+ <string name="plate">Plate</string>
<string name="power_on_prompt">Tekan tombol power pada bagian kanan atas.</string>
<string name="effect_unavalable_for_speaker">Efek tidak tersedia untuk modus Speaker.</string>
<string name="device_headset">Set kepala</string>
<string name="device_speaker">Speaker</string>
- <string name="device_lineout">Sambungan keluar</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Nirkabel</string>
<string name="reverb">Reverb</string>
<string name="eq_preset">Preset equalizer</string>
+ <string name="devices">Perangkat</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Ubah Nama</string>
+ <string name="remove_custom_preset_warning_message">Apakah Anda yakin Anda ingin menghapus %1$s?</string>
</resources>
diff --git a/res/values-it/cm_strings.xml b/res/values-it/cm_strings.xml
index 2bbae8d..30aee98 100644
--- a/res/values-it/cm_strings.xml
+++ b/res/values-it/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normale</string>
<string name="classical">Classica</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elettronica</string>
+ <string name="ci_extreme">Elettronica</string>
<string name="small_speakers">Altoparlanti piccoli</string>
- <string name="custom">Personalizzato</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personalizzato</string>
+ <string name="user_n">Personalizzato <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Nessuno</string>
<string name="smallroom">Stanza piccola</string>
<string name="mediumroom">Stanza media</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effetto non disponibile per la modalità vivavoce.</string>
<string name="device_headset">Cuffie</string>
<string name="device_speaker">Altoparlante</string>
- <string name="device_lineout">Line out</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
- <string name="device_wireless">Wireless</string>
+ <string name="device_wireless">Senza fili</string>
<string name="reverb">Riverbero</string>
<string name="eq_preset">Equalizzatore predefinito</string>
+ <string name="devices">Dispositivi</string>
+ <string name="virtualizer">Virtualizzatore</string>
+ <string name="treble">Alti</string>
+ <string name="bass">Bassi</string>
+ <string name="rename">Rinomina</string>
+ <string name="remove_custom_preset_warning_message">Sei sicuro di voler rimuovere %1$s?</string>
</resources>
diff --git a/res/values-iw/cm_strings.xml b/res/values-iw/cm_strings.xml
index 4686d1e..5d9278e 100644
--- a/res/values-iw/cm_strings.xml
+++ b/res/values-iw/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">רגיל</string>
<string name="classical">קלאסי</string>
<string name="dance">דאנס</string>
@@ -26,9 +26,11 @@
<string name="jazz">ג\'אז</string>
<string name="pop">פופ</string>
<string name="rock">רוק</string>
- <string name="electronic">אלקטרוני</string>
+ <string name="ci_extreme">אלקטרוני</string>
<string name="small_speakers">רמקולים קטנים</string>
- <string name="custom">מותאם אישית</string>
+ <string name="multimedia">מולטימדיה</string>
+ <string name="user">מותאם אישית</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> מותאם אישית</string>
<string name="none">ללא</string>
<string name="smallroom">חדר קטן</string>
<string name="mediumroom">חדר בינוני</string>
@@ -38,12 +40,17 @@
<string name="plate">צלחת</string>
<string name="power_on_prompt">לחץ על לחצן ההפעלה למעלה מימין.</string>
<string name="effect_unavalable_for_speaker">האפקט אינו זמין במצב רמקול.</string>
- <string name="device_headset">אזניות</string>
+ <string name="device_headset">אוזניה</string>
<string name="device_speaker">רמקול</string>
- <string name="device_lineout">יציאת שמע</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">אלחוטי</string>
<string name="reverb">תהודה</string>
<string name="eq_preset">אקולייזר קבוע מראש</string>
+ <string name="devices">מכשירים</string>
+ <string name="virtualizer">מדמה וירטואלי</string>
+ <string name="treble">טרבל</string>
+ <string name="bass">בס</string>
+ <string name="rename">שנה שם</string>
+ <string name="remove_custom_preset_warning_message">בטוח שברצונך להסיר את %1$s?</string>
</resources>
diff --git a/res/values-ja/cm_strings.xml b/res/values-ja/cm_strings.xml
index 96ad24b..730080a 100644
--- a/res/values-ja/cm_strings.xml
+++ b/res/values-ja/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Classical</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
- <string name="small_speakers">Small speakers</string>
- <string name="custom">カスタム</string>
+ <string name="ci_extreme">Electronic</string>
+ <string name="small_speakers">小さいスピーカー</string>
+ <string name="multimedia">マルチメディア</string>
+ <string name="user">カスタム</string>
+ <string name="user_n">カスタム<xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">なし</string>
<string name="smallroom">小さい部屋</string>
<string name="mediumroom">中くらいの部屋</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">スピーカーモードでは効果は利用できません。</string>
<string name="device_headset">ヘッドセット</string>
<string name="device_speaker">スピーカー</string>
- <string name="device_lineout">ライン出力</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">ワイヤレス</string>
<string name="reverb">リバーブ</string>
<string name="eq_preset">イコライザープリセット</string>
+ <string name="devices">端末</string>
+ <string name="virtualizer">バーチャライザ</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bass</string>
+ <string name="rename">名前の変更</string>
+ <string name="remove_custom_preset_warning_message">%1$sを削除してもよろしいですか?</string>
</resources>
diff --git a/res/values-kn-rIN/cm_strings.xml b/res/values-kn-rIN/cm_strings.xml
index 4370b11..1f5fb22 100644
--- a/res/values-kn-rIN/cm_strings.xml
+++ b/res/values-kn-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">ಸಹಜ</string>
<string name="classical">ಶಾಸ್ತ್ರೀಯ</string>
<string name="dance">ನೃತ್ಯ</string>
@@ -26,9 +26,11 @@
<string name="jazz">ಜಾಝ್</string>
<string name="pop">ಪಾಪ್</string>
<string name="rock">ರಾಕ್</string>
- <string name="electronic">ಎಲೆಕ್ಟ್ರಾನಿಕ್</string>
+ <string name="ci_extreme">ಎಲೆಕ್ಟ್ರಾನಿಕ್</string>
<string name="small_speakers">ಚಿಕ್ಕ ಸ್ಪೀಕರ್‍ಗಳು</string>
- <string name="custom">ಕಸ್ಟಮ್</string>
+ <string name="multimedia">ಬಹುಮಾಧ್ಯಮ</string>
+ <string name="user">ಕಸ್ಟಮ್</string>
+ <string name="user_n">ಕಸ್ಟಮ್ <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">ಶೂನ್ಯ</string>
<string name="smallroom">ಸಣ್ಣ ಕೋಣೆ</string>
<string name="mediumroom">ಮಧ್ಯಮ ಕೊಣೆ</string>
@@ -37,7 +39,7 @@
<string name="largehall">ದೊಡ್ಡ ಹಾಲ್</string>
<string name="plate">ಪ್ಲೇಟ್</string>
<string name="power_on_prompt">ಬಲ-ಮೇಲ್ಭಾಗದಲ್ಲಿರುವ ಪವರ್ ಬಟನ್ ಒತ್ತಿ.</string>
- <string name="effect_unavalable_for_speaker">ಸ್ಪೀಕರ್ ಮೋಡ್ ಪರಿಣಾಮಗಳು ಲಭ್ಯವಿಲ್ಲ.</string>
+ <string name="effect_unavalable_for_speaker">ಪರಿಣಾಮಗಳು ಸ್ಪೀಕರ್ ಮೋಡ್‍ಗೆ ಲಭ್ಯವಿಲ್ಲ.</string>
<string name="device_headset">ಹೆಡ್‍ಸೆಟ್</string>
<string name="device_speaker">ಸ್ಪೀಕರ್</string>
<string name="device_usb">ಯುಎಸ್‍ಬಿ</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">ನಿಸ್ತಂತು</string>
<string name="reverb">ಪ್ರತಿಫಲನ</string>
<string name="eq_preset">ಸಮಕಾರಕ ಪೂರ್ವನಿಗದಿ</string>
+ <string name="devices">ಸಾಧನಗಳು</string>
+ <string name="virtualizer">ವಾಸ್ತವೀಕರಣಕಾರಕ</string>
+ <string name="treble">ಟ್ರೆಬಲ್</string>
+ <string name="bass">ಬಾಸ್</string>
+ <string name="rename">ಮರುಹೆಸರಿಸಿ</string>
+ <string name="remove_custom_preset_warning_message">ನೀವು ಖಚಿತವಾಗಿ %1$s ತೆಗೆಯಲು ಬಯಸುವಿರಾ?</string>
</resources>
diff --git a/res/values-ko/cm_strings.xml b/res/values-ko/cm_strings.xml
index 27144cb..d480a53 100644
--- a/res/values-ko/cm_strings.xml
+++ b/res/values-ko/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">일반</string>
<string name="classical">클래식</string>
<string name="dance">댄스</string>
@@ -26,9 +26,11 @@
<string name="jazz">재즈</string>
<string name="pop">팝</string>
<string name="rock">락</string>
- <string name="electronic">일렉트로닉</string>
+ <string name="ci_extreme">일렉트로닉</string>
<string name="small_speakers">작은 스피커</string>
- <string name="custom">사용자 정의</string>
+ <string name="multimedia">멀티미디어</string>
+ <string name="user">사용자 정의</string>
+ <string name="user_n">사용자 지정 <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">없음</string>
<string name="smallroom">작은 방</string>
<string name="mediumroom">중간 방</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">스피커로는 이 음향효과를 사용할 수 없습니다.</string>
<string name="device_headset">헤드셋</string>
<string name="device_speaker">스피커</string>
- <string name="device_lineout">출력</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">블루투스</string>
<string name="device_wireless">무선</string>
<string name="reverb">리버브</string>
<string name="eq_preset">이퀄라이저 프리셋</string>
+ <string name="devices">기기</string>
+ <string name="virtualizer">버추얼라이저</string>
+ <string name="treble">고음</string>
+ <string name="bass">베이스</string>
+ <string name="rename">이름 바꾸기</string>
+ <string name="remove_custom_preset_warning_message">%1$s을(를) 삭제하시겠습니까?</string>
</resources>
diff --git a/res/values-ku/cm_strings.xml b/res/values-ku/cm_strings.xml
index 0cbb16a..cc3ec9f 100644
--- a/res/values-ku/cm_strings.xml
+++ b/res/values-ku/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">ئاسایی</string>
<string name="classical">كلاسیكی</string>
<string name="dance">سه‌ما</string>
@@ -26,9 +26,9 @@
<string name="jazz">جاز</string>
<string name="pop">پۆپ</string>
<string name="rock">ڕۆک</string>
- <string name="electronic">ئەلیکترۆنیك</string>
+ <string name="ci_extreme">ئەلیکترۆنیك</string>
<string name="small_speakers">دەنگدەری بچووک</string>
- <string name="custom">داواکراو</string>
+ <string name="user">داواکراو</string>
<string name="none">هیچ</string>
<string name="smallroom">ژوری بچوک</string>
<string name="mediumroom">ژوری ئاسایی</string>
diff --git a/res/values-ku/strings.xml b/res/values-ku/strings.xml
index 22cee23..be57ad1 100644
--- a/res/values-ku/strings.xml
+++ b/res/values-ku/strings.xml
@@ -15,12 +15,16 @@
limitations under the License.
-->
<resources>
- <!-- ControlPanelMusic strings -->
+ <string name="app_name">دەنگڕێخەر</string>
<string name="no_effects">کاریگەر لەکارەنیە.</string>
+ <string name="main_toggle_effects_title">کاریگه‌ری ده‌نگ</string>
+ <string name="eq_dialog_title">دەنگڕێخەر</string>
<string name="headset_plug">تکایه‌ بیستۆکی پێوه‌بکه‌ بۆ کاریگه‌ری.</string>
<string name="bass_boost_strength">زیادکردنی دەنگی دور</string>
<string name="virtualizer_strength">دەوردانی دەنگ</string>
+ <string name="pr_title">هەمیشەی:</string>
+ <string name="pr_summary">زیادکردنی کاریگەری دەنگ</string>
+ <string name="pr_dialog_title">هەمیشە ڕێخستن</string>
<string name="setup">دامه‌زراندن</string>
- <!-- title of control panel picker dialog [CHAR LIMIT=30] -->
<string name="picker_title">پەڕەی ڕێکخستنی کاریگەری دەنگ\"</string>
</resources>
diff --git a/res/values-lb/cm_strings.xml b/res/values-lb/cm_strings.xml
index 2bef31f..cf7f852 100644
--- a/res/values-lb/cm_strings.xml
+++ b/res/values-lb/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klassesch</string>
<string name="dance">Danzmusek</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronesch</string>
+ <string name="ci_extreme">Elektronesch</string>
<string name="small_speakers">Kleng Boxen</string>
- <string name="custom">Personaliséiert</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personaliséiert</string>
+ <string name="user_n">Personaliséiert <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Keen</string>
<string name="smallroom">Klenge Raum</string>
<string name="mediumroom">Mëttlere Raum</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effekt am Lautsprecher-Modus net disponibel.</string>
<string name="device_headset">Kopfhörer</string>
<string name="device_speaker">Lautsprecher</string>
- <string name="device_lineout">Line-Ausgank</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Ouni Kabel</string>
<string name="reverb">Halleffekt</string>
<string name="eq_preset">Equalizer-Virastellung</string>
+ <string name="devices">Apparater</string>
+ <string name="virtualizer">Virtualiséierung</string>
+ <string name="treble">Héichten</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Ëmbenennen</string>
+ <string name="remove_custom_preset_warning_message">Bass du sécher, datt s du %1$s ewechhuele wëlls?</string>
</resources>
diff --git a/res/values-lb/strings.xml b/res/values-lb/strings.xml
index 6e63ce9..8d82431 100644
--- a/res/values-lb/strings.xml
+++ b/res/values-lb/strings.xml
@@ -15,16 +15,16 @@
limitations under the License.
-->
<resources>
- <string name="app_name">MusicFX</string>
- <!-- ControlPanelMusic strings -->
+ <string name="app_name">TounFX</string>
<string name="no_effects">Effekter net disponibel.</string>
- <string name="eq_dialog_title">Equalizer</string>
+ <string name="main_toggle_effects_title">Touneffekter</string>
+ <string name="eq_dialog_title">TounFX</string>
<string name="headset_plug">Schléiss Kopfhörer u fir dës Effekter.</string>
<string name="bass_boost_strength">Bassunhiewung</string>
<string name="virtualizer_strength">Surround-Toun</string>
+ <string name="pr_title">Halleffekt:</string>
+ <string name="pr_summary">Zousätzlech Raum-Halleffekter</string>
+ <string name="pr_dialog_title">Virastellunge fir den Hall</string>
<string name="setup">Astellen</string>
- <string name="ci_extreme">FX-Booster</string>
- <string name="user">Benotzer</string>
- <!-- title of control panel picker dialog [CHAR LIMIT=30] -->
<string name="picker_title">Steierelementer fir Touneffekter</string>
</resources>
diff --git a/res/values-lt/cm_strings.xml b/res/values-lt/cm_strings.xml
index 2af6752..a351c58 100644
--- a/res/values-lt/cm_strings.xml
+++ b/res/values-lt/cm_strings.xml
@@ -15,34 +15,42 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normalus</string>
<string name="classical">Klasikinis</string>
<string name="dance">Šokių</string>
<string name="flat">Lygus</string>
<string name="folk">Liaudies</string>
<string name="heavy_metal">Sunkusis metalas</string>
- <string name="hip_hop">Hiphopas</string>
+ <string name="hip_hop">Hip Hop</string>
<string name="jazz">Džiazas</string>
- <string name="pop">Popsas</string>
+ <string name="pop">Pop</string>
<string name="rock">Rokas</string>
- <string name="electronic">Elektronika</string>
+ <string name="ci_extreme">Elektroninis</string>
<string name="small_speakers">Maži garsiakalbiai</string>
- <string name="custom">Priskirtas</string>
+ <string name="multimedia">Multimedija</string>
+ <string name="user">Priskirtas</string>
+ <string name="user_n">Priskirtas <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Joks</string>
<string name="smallroom">Mažas kambarys</string>
<string name="mediumroom">Vidutinio dydžio kambarys</string>
<string name="largeroom">Didelis kambarys</string>
<string name="mediumhall">Vidutinio dydžio salė</string>
<string name="largehall">Didelė salė</string>
- <string name="plate">Platforma</string>
+ <string name="plate">Plokštė</string>
<string name="power_on_prompt">Paspauskite maitinimo mygtuką viršuje dešinėje.</string>
<string name="effect_unavalable_for_speaker">Efektas negalimas garsiakalbio režime.</string>
<string name="device_headset">Laisvų rankų įranga</string>
<string name="device_speaker">Garsiakalbis</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
- <string name="device_wireless">Belaidis</string>
+ <string name="device_wireless">Bevielis</string>
<string name="reverb">Aidas</string>
- <string name="eq_preset">Vienodintuvo išankstiniai nustatymai</string>
+ <string name="eq_preset">Ekvalaizerio išankstiniai nustatymai</string>
+ <string name="devices">Įrenginiai</string>
+ <string name="virtualizer">Virtualizacija</string>
+ <string name="treble">Aukšti dažniai</string>
+ <string name="bass">Žemi dažniai</string>
+ <string name="rename">Pervadinti</string>
+ <string name="remove_custom_preset_warning_message">Ar tikrai norite pašalinti %1$s?</string>
</resources>
diff --git a/res/values-lv/cm_strings.xml b/res/values-lv/cm_strings.xml
index 4cc059d..75b8872 100644
--- a/res/values-lv/cm_strings.xml
+++ b/res/values-lv/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normāls</string>
<string name="classical">Klasika</string>
<string name="dance">Dejas</string>
@@ -26,9 +26,9 @@
<string name="jazz">Džezs</string>
<string name="pop">Pops</string>
<string name="rock">Roks</string>
- <string name="electronic">Elektronika</string>
+ <string name="ci_extreme">Elektronika</string>
<string name="small_speakers">Mazi skaļruņi</string>
- <string name="custom">Pielāgots</string>
+ <string name="user">Pielāgots</string>
<string name="none">Nekas</string>
<string name="smallroom">Maza istaba</string>
<string name="mediumroom">Vidēja istaba</string>
diff --git a/res/values-ml-rIN/cm_strings.xml b/res/values-ml-rIN/cm_strings.xml
index 362e5f1..69bc8be 100644
--- a/res/values-ml-rIN/cm_strings.xml
+++ b/res/values-ml-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">സാധാരണ</string>
<string name="classical">ക്ലാസിക്കൽ</string>
<string name="dance">ഡാൻസ്</string>
@@ -26,9 +26,11 @@
<string name="jazz">ജാസ്സ്</string>
<string name="pop">പോപ്പ്</string>
<string name="rock">റോക്ക്</string>
- <string name="electronic">ഇലക്ട്രോണിക്</string>
+ <string name="ci_extreme">ഇലക്ട്രോണിക്</string>
<string name="small_speakers">ചെറിയ സ്പീക്കറുകൾ</string>
- <string name="custom">ഇഷ്‌ടാനുസൃതം</string>
+ <string name="multimedia">മൾട്ടിമീഡിയ</string>
+ <string name="user">ഇഷ്‌ടാനുസൃതം</string>
+ <string name="user_n">ഇഷ്ടാനുസൃത <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">ആരിൽ നിന്നും വേണ്ട</string>
<string name="smallroom">ചെറിയ റൂം</string>
<string name="mediumroom">ഇടത്തരം റൂം</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">വയർലെസ്</string>
<string name="reverb">പ്രതിധ്വനി</string>
<string name="eq_preset">ഈക്വലൈസര്‍ പ്രീസെറ്റ്</string>
+ <string name="devices">ഉപകരണങ്ങൾ</string>
+ <string name="virtualizer">വര്‍ച്വലൈസര്‍</string>
+ <string name="treble">ട്രെബിൾ</string>
+ <string name="bass">ബാസ്സ്</string>
+ <string name="rename">പേരുമാറ്റുക</string>
+ <string name="remove_custom_preset_warning_message">%1$s നീക്കം ചെയ്യണമെന്ന് നിങ്ങള്‍ക്ക് ഉറപ്പാണോ?</string>
</resources>
diff --git a/res/values-mr-rIN/cm_strings.xml b/res/values-mr-rIN/cm_strings.xml
index ac03835..8c3a7c7 100644
--- a/res/values-mr-rIN/cm_strings.xml
+++ b/res/values-mr-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">सामान्य</string>
<string name="classical">शास्त्रीय</string>
<string name="dance">नृत्य</string>
@@ -26,9 +26,11 @@
<string name="jazz">जॅझ</string>
<string name="pop">पॉप</string>
<string name="rock">रॉक</string>
- <string name="electronic">इलेक्ट्रॉनिक</string>
+ <string name="ci_extreme">इलेक्ट्रॉनिक</string>
<string name="small_speakers">लहान स्पीकर्स</string>
- <string name="custom">सानुकूल</string>
+ <string name="multimedia">मल्टिमिडिया</string>
+ <string name="user">सानुकूल</string>
+ <string name="user_n">सानुकूल करा <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">काहीही नाही</string>
<string name="smallroom">लहान खोली</string>
<string name="mediumroom">मध्यम खोली</string>
@@ -36,7 +38,7 @@
<string name="mediumhall">मध्यम हॉल</string>
<string name="largehall">मोठा हॉल</string>
<string name="plate">प्लेट</string>
- <string name="power_on_prompt">शीर्षाशी-उजवीकडे पॉवर बटण दाबा.</string>
+ <string name="power_on_prompt">शीर्षाच्या-उजवीकडे पॉवर बटण दाबा.</string>
<string name="effect_unavalable_for_speaker">स्पीकर मोडसाठी प्रभाव उपलब्ध नाही.</string>
<string name="device_headset">हेडसेट</string>
<string name="device_speaker">स्पीकर</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">बिनतारी</string>
<string name="reverb">रिव्हर्ब</string>
<string name="eq_preset">इक्वेलायझर प्रीसेट</string>
+ <string name="devices">डिव्हाइसेस</string>
+ <string name="virtualizer">व्हर्च्युअलाझर</string>
+ <string name="treble">ट्रेबल</string>
+ <string name="bass">बास</string>
+ <string name="rename">पुनर्नामित करा</string>
+ <string name="remove_custom_preset_warning_message">तुम्हाला नक्की %1$s काढायचे आहे का?</string>
</resources>
diff --git a/res/values-nb/cm_strings.xml b/res/values-nb/cm_strings.xml
index dc47ad4..eb4cc01 100644
--- a/res/values-nb/cm_strings.xml
+++ b/res/values-nb/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klassisk</string>
<string name="dance">Dans</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronisk</string>
+ <string name="ci_extreme">Elektronisk</string>
<string name="small_speakers">Små høyttalere</string>
- <string name="custom">Egendefinert</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Egendefinert</string>
+ <string name="user_n">Egendefinert <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Ingen</string>
<string name="smallroom">Lite rom</string>
<string name="mediumroom">Medium rom</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effekten er ikke tilgjengelig for høyttaler-modus.</string>
<string name="device_headset">Hodetelefon</string>
<string name="device_speaker">Høyttaler</string>
- <string name="device_lineout">Linje ut</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Trådløs</string>
<string name="reverb">Romklang</string>
<string name="eq_preset">Equalizer forhåndsinnstilling</string>
+ <string name="devices">Enheter</string>
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Diskant</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Gi nytt navn</string>
+ <string name="remove_custom_preset_warning_message">Er du sikker på at du vil fjerne %1$s?</string>
</resources>
diff --git a/res/values-nl/cm_strings.xml b/res/values-nl/cm_strings.xml
index db0897c..04fa891 100644
--- a/res/values-nl/cm_strings.xml
+++ b/res/values-nl/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normaal</string>
<string name="classical">Klassiek</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronisch</string>
+ <string name="ci_extreme">Elektronisch</string>
<string name="small_speakers">Kleine luidsprekers</string>
- <string name="custom">Aangepast</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Aangepast</string>
+ <string name="user_n">Aangepaste <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Geen</string>
<string name="smallroom">Kleine ruimte</string>
<string name="mediumroom">Middelgrote ruimte</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effect niet beschikbaar voor luidsprekermodus.</string>
<string name="device_headset">Koptelefoon</string>
<string name="device_speaker">Luidspreker</string>
- <string name="device_lineout">Lijnuitgang</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Draadloos</string>
<string name="reverb">Galm</string>
<string name="eq_preset">Equalizer-preset</string>
+ <string name="devices">Apparaten</string>
+ <string name="virtualizer">Virtualiseerder</string>
+ <string name="treble">Hoge tonen</string>
+ <string name="bass">Bas</string>
+ <string name="rename">Hernoemen</string>
+ <string name="remove_custom_preset_warning_message">Weet u zeker dat u %1$s wilt verwijderen?</string>
</resources>
diff --git a/res/values-or-rIN/cm_strings.xml b/res/values-or-rIN/cm_strings.xml
index b4cf9e5..a2f43dd 100644
--- a/res/values-or-rIN/cm_strings.xml
+++ b/res/values-or-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">ସାଧାରଣ</string>
<string name="classical">କ୍ଲାସିକାଲ୍</string>
<string name="dance">ନୃତ୍ୟ</string>
@@ -26,9 +26,11 @@
<string name="jazz">ଜାଜ୍</string>
<string name="pop">ପପ୍‌</string>
<string name="rock">ରକ୍</string>
- <string name="electronic">ବୈଦ୍ୟୁତିକ</string>
+ <string name="ci_extreme">ବୈଦ୍ୟୁତିକ</string>
<string name="small_speakers">ଛୋଟ ସ୍ପିକର୍‍ଗୁଡିକ</string>
- <string name="custom">କଷ୍ଟମ୍</string>
+ <string name="multimedia">ମଲ୍ଟିମିଡିଆ</string>
+ <string name="user">କଷ୍ଟମ୍</string>
+ <string name="user_n">କଷ୍ଟମ୍ <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">କିଛି ନୁହେଁ</string>
<string name="smallroom">ଛୋଟ ରୁମ୍‍</string>
<string name="mediumroom">ମଧ୍ୟମ ରୁମ୍</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">ଓୟାର୍‍ଲେସ୍‍</string>
<string name="reverb">ର୍ରିଭର୍ବ:</string>
<string name="eq_preset">ଇକ୍ୱାଲାଇଜର୍‍ ପ୍ରିସେଟ୍‍</string>
+ <string name="devices">ଡିଭାଇସଗୁଡିକ</string>
+ <string name="virtualizer">ଭର୍ଚୁଆଲାଇଜର୍‍</string>
+ <string name="treble">ଟ୍ରେବେଲ୍‍</string>
+ <string name="bass">ବାସ୍‍</string>
+ <string name="rename">ପୁନଃନାମ</string>
+ <string name="remove_custom_preset_warning_message">ଆପଣ %1$s ଅପସାରଣ କରିବାକୁ ଚାହୁଁଛନ୍ତି, ଏଥିରେ ଆପଣ ସୁନି୍ଶ୍ଚିତ କି?</string>
</resources>
diff --git a/res/values-pl/cm_strings.xml b/res/values-pl/cm_strings.xml
index fd9f99a..4df7f01 100644
--- a/res/values-pl/cm_strings.xml
+++ b/res/values-pl/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normalna</string>
<string name="classical">Klasyczna</string>
<string name="dance">Taneczna</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektroniczna</string>
+ <string name="ci_extreme">Elektroniczna</string>
<string name="small_speakers">Małe głośniki</string>
- <string name="custom">Własne</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Własne</string>
+ <string name="user_n">Niestandardowy <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Brak</string>
<string name="smallroom">Mały pokój</string>
<string name="mediumroom">Średni pokój</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efekt nie jest dostępny dla Głośnika urządzenia.</string>
<string name="device_headset">Słuchawki</string>
<string name="device_speaker">Głośnik</string>
- <string name="device_lineout">Wyjście analogowe</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Bezprzewodowe</string>
<string name="reverb">Pogłos</string>
<string name="eq_preset">Ustawienia korektora</string>
+ <string name="devices">Urządzenia</string>
+ <string name="virtualizer">Wirtualizacja</string>
+ <string name="treble">Sopran</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Zmień nazwę</string>
+ <string name="remove_custom_preset_warning_message">Jesteś pewny, że chcesz usunąć %1$s?</string>
</resources>
diff --git a/res/values-pt-rBR/cm_strings.xml b/res/values-pt-rBR/cm_strings.xml
index 9f65d05..3f77695 100644
--- a/res/values-pt-rBR/cm_strings.xml
+++ b/res/values-pt-rBR/cm_strings.xml
@@ -15,20 +15,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clássica</string>
<string name="dance">Dance</string>
<string name="flat">Plano</string>
<string name="folk">Folk</string>
- <string name="heavy_metal">Heavy metal</string>
- <string name="hip_hop">Hip-hop</string>
+ <string name="heavy_metal">Heavy Metal</string>
+ <string name="hip_hop">Hip-Hop</string>
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Eletrônica</string>
- <string name="small_speakers">Falantes pequenos</string>
- <string name="custom">Personalizado</string>
+ <string name="ci_extreme">Eletrônica</string>
+ <string name="small_speakers">Alto-falantes pequenos</string>
+ <string name="multimedia">Multimídia</string>
+ <string name="user">Personalizado</string>
+ <string name="user_n">Personalizado <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Nenhum</string>
<string name="smallroom">Sala pequena</string>
<string name="mediumroom">Sala média</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efeito não disponível no modo de alto-falante.</string>
<string name="device_headset">Fone de ouvido</string>
<string name="device_speaker">Alto-falante</string>
- <string name="device_lineout">Saída de linha</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Sem fio</string>
<string name="reverb">Reverb</string>
<string name="eq_preset">Predefinição do equalizador</string>
+ <string name="devices">Dispositivos</string>
+ <string name="virtualizer">Virtualizador</string>
+ <string name="treble">Agudo</string>
+ <string name="bass">Grave</string>
+ <string name="rename">Renomear</string>
+ <string name="remove_custom_preset_warning_message">Tem certeza que deseja remover %1$s?</string>
</resources>
diff --git a/res/values-pt-rPT/cm_strings.xml b/res/values-pt-rPT/cm_strings.xml
index 760485a..8fc7a09 100644
--- a/res/values-pt-rPT/cm_strings.xml
+++ b/res/values-pt-rPT/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clássica</string>
<string name="dance">Dança</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Eletrónica</string>
+ <string name="ci_extreme">Eletrónica</string>
<string name="small_speakers">Altifalantes pequenos</string>
- <string name="custom">Personalizado</string>
+ <string name="multimedia">Multimédia</string>
+ <string name="user">Personalizado</string>
+ <string name="user_n">Personalizado <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Nenhum</string>
<string name="smallroom">Quarto pequeno</string>
<string name="mediumroom">Quarto médio</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efeito não disponível no modo de altifalante.</string>
<string name="device_headset">Auricular</string>
<string name="device_speaker">Altifalante</string>
- <string name="device_lineout">Saída de linha</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Sem fios</string>
- <string name="reverb">Reverb</string>
+ <string name="reverb">Ressonância</string>
<string name="eq_preset">Predefinição do equalizador</string>
+ <string name="devices">Dispositivos</string>
+ <string name="virtualizer">Virtualizador</string>
+ <string name="treble">Agudos</string>
+ <string name="bass">Graves</string>
+ <string name="rename">Mudar o nome</string>
+ <string name="remove_custom_preset_warning_message">Tem certeza que deseja remover %1$s?</string>
</resources>
diff --git a/res/values-ro/cm_strings.xml b/res/values-ro/cm_strings.xml
index e73caf8..6f85f2b 100644
--- a/res/values-ro/cm_strings.xml
+++ b/res/values-ro/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Clasică</string>
<string name="dance">Dance</string>
@@ -26,9 +26,10 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronică</string>
+ <string name="ci_extreme">Electronică</string>
<string name="small_speakers">Difuzoare Mici</string>
- <string name="custom">Personalizat</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Personalizat</string>
<string name="none">Niciunul</string>
<string name="smallroom">Cameră mică</string>
<string name="mediumroom">Cameră medie</string>
@@ -45,4 +46,8 @@
<string name="device_wireless">Wireless</string>
<string name="reverb">Reverberație</string>
<string name="eq_preset">Preset egalizator</string>
+ <string name="devices">Dispozitive</string>
+ <string name="treble">Înalte</string>
+ <string name="bass">Joase</string>
+ <string name="rename">Redenumire</string>
</resources>
diff --git a/res/values-ru/cm_strings.xml b/res/values-ru/cm_strings.xml
index 46b7efd..2869dd4 100644
--- a/res/values-ru/cm_strings.xml
+++ b/res/values-ru/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Стандартный</string>
<string name="classical">Классика</string>
<string name="dance">Танцевальная музыка</string>
@@ -26,9 +26,11 @@
<string name="jazz">Джаз</string>
<string name="pop">Поп</string>
<string name="rock">Рок</string>
- <string name="electronic">Электронная музыка</string>
+ <string name="ci_extreme">Электронная музыка</string>
<string name="small_speakers">Маленькие динамики</string>
- <string name="custom">Пользовательские настр.</string>
+ <string name="multimedia">Мультимедиа</string>
+ <string name="user">Пользовательские</string>
+ <string name="user_n">Пользоват. <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Нет</string>
<string name="smallroom">Маленькая комната</string>
<string name="mediumroom">Средняя комната</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Эффект недоступен для динамиков.</string>
<string name="device_headset">Наушники</string>
<string name="device_speaker">Динамик</string>
- <string name="device_lineout">Линейный выход</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Беспров. устр.</string>
<string name="reverb">Реверберация</string>
- <string name="eq_preset">Предуст. эквалайзера</string>
+ <string name="eq_preset">Предустановки</string>
+ <string name="devices">Устройства</string>
+ <string name="virtualizer">Виртуализатор</string>
+ <string name="treble">Высокие</string>
+ <string name="bass">НЧ</string>
+ <string name="rename">Переименовать</string>
+ <string name="remove_custom_preset_warning_message">Действительно удалить «%1$s»?</string>
</resources>
diff --git a/res/values-si-rLK/cm_strings.xml b/res/values-si-rLK/cm_strings.xml
index 0ed1eec..34e55cc 100644
--- a/res/values-si-rLK/cm_strings.xml
+++ b/res/values-si-rLK/cm_strings.xml
@@ -26,9 +26,9 @@
<string name="jazz">ජෑස්</string>
<string name="pop">පොප්</string>
<string name="rock">රොක්</string>
- <string name="electronic">ඉලෙක්ට්‍රොනික</string>
+ <string name="ci_extreme">ඉලෙක්ට්‍රොනික</string>
<string name="small_speakers">කුඩා ස්පීකර</string>
- <string name="custom">රිසිවූ</string>
+ <string name="user">රිසිවූ</string>
<string name="none">කිසිවක් නැත</string>
<string name="smallroom">කුඩා කාමරය</string>
<string name="mediumroom">මධ්‍යම කාමරය</string>
@@ -36,6 +36,7 @@
<string name="mediumhall">මධ්‍යම ශාලාව</string>
<string name="largehall">විශාල ශාලාව</string>
<string name="plate">තහඩුව</string>
+ <string name="eq_custom">රිසිකරණය සඳහා, \'රිසිවූ\' තෝරන්න</string>
<string name="power_on_prompt">ඉහළින් දකුණේ ඇති බල බොත්තම ඔබන්න.</string>
<string name="effect_unavalable_for_speaker">ස්පීකර ප්‍රකාරය සඳහා බලපෑම ලබාගත නොහැක.</string>
<string name="device_headset">කන්යොමුව</string>
@@ -43,6 +44,6 @@
<string name="device_usb">USB</string>
<string name="device_bluetooth">බ්ලූටූත්</string>
<string name="device_wireless">රැහැන් රහිත</string>
- <string name="reverb">ආඛ්‍යාතය</string>
<string name="eq_preset">සමකරකයේ පෙරසැකසීම</string>
+ <string name="reverb">ආඛ්‍යාතය</string>
</resources>
diff --git a/res/values-sk/cm_strings.xml b/res/values-sk/cm_strings.xml
index 8cd4758..ca48bbb 100644
--- a/res/values-sk/cm_strings.xml
+++ b/res/values-sk/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normálne</string>
<string name="classical">Klasická hudba</string>
<string name="dance">Tanec</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronická hudba</string>
+ <string name="ci_extreme">Elektronická hudba</string>
<string name="small_speakers">Malé reproduktory</string>
- <string name="custom">Vlastné</string>
+ <string name="multimedia">Multimédiá</string>
+ <string name="user">Vlastné</string>
+ <string name="user_n">Vlastné <xliff:g id="preset_num">%1$d </xliff:g></string>
<string name="none">Žiadny</string>
<string name="smallroom">Malá miestnosť</string>
<string name="mediumroom">Stredná miestnosť</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">Bezdrôtové</string>
<string name="reverb">Reverb</string>
<string name="eq_preset">Predvoľba ekvalizéra</string>
+ <string name="devices">Zariadenia</string>
+ <string name="virtualizer">Virtualizér</string>
+ <string name="treble">Výšky</string>
+ <string name="bass">Basy</string>
+ <string name="rename">Premenovať</string>
+ <string name="remove_custom_preset_warning_message">Naozaj chcete odstrániť %1$s?</string>
</resources>
diff --git a/res/values-sl/cm_strings.xml b/res/values-sl/cm_strings.xml
index c848ded..a6b9601 100644
--- a/res/values-sl/cm_strings.xml
+++ b/res/values-sl/cm_strings.xml
@@ -15,8 +15,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <string name="normal">Običajna</string>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="normal">Običajno</string>
<string name="classical">Klasična</string>
<string name="dance">Plesna</string>
<string name="flat">Ploska</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronska</string>
+ <string name="ci_extreme">Elektronska</string>
<string name="small_speakers">Majhni zvočniki</string>
- <string name="custom">Po meri</string>
+ <string name="multimedia">Večpredstavnost</string>
+ <string name="user">Po meri</string>
+ <string name="user_n"><xliff:g id="preset_num">%1$d</xliff:g> po meri</string>
<string name="none">Brez</string>
<string name="smallroom">Majhna soba</string>
<string name="mediumroom">Srednja soba</string>
@@ -36,14 +38,19 @@
<string name="mediumhall">Srednje velika dvorana</string>
<string name="largehall">Velika dvorana</string>
<string name="plate">Plošča</string>
- <string name="power_on_prompt">Pritisnite gumb za vklop na zgornji desni strani.</string>
+ <string name="power_on_prompt">Pritisnite na gumb za vklop na zgornji desni strani.</string>
<string name="effect_unavalable_for_speaker">Učinek ni na voljo v načinu Zvočnika.</string>
<string name="device_headset">Slušalke</string>
<string name="device_speaker">Zvočnik</string>
- <string name="device_lineout">Izhod za slušalke</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Brezžično</string>
<string name="reverb">Odmev</string>
<string name="eq_preset">Prednastavitev izenačevalnika</string>
+ <string name="devices">Naprave</string>
+ <string name="virtualizer">Navidezovalnik</string>
+ <string name="treble">Visoki toni</string>
+ <string name="bass">Nizki toni</string>
+ <string name="rename">Preimenuj</string>
+ <string name="remove_custom_preset_warning_message">Ali res želite odstraniti %1$s?</string>
</resources>
diff --git a/res/values-sr/cm_strings.xml b/res/values-sr/cm_strings.xml
index a3d2e05..e1bb743 100644
--- a/res/values-sr/cm_strings.xml
+++ b/res/values-sr/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Нормално</string>
<string name="classical">Класика</string>
<string name="dance">Денс</string>
@@ -26,9 +26,11 @@
<string name="jazz">Џез</string>
<string name="pop">Поп</string>
<string name="rock">Рок</string>
- <string name="electronic">Електроника</string>
+ <string name="ci_extreme">Електроника</string>
<string name="small_speakers">Мали звучници</string>
- <string name="custom">Прилагођено</string>
+ <string name="multimedia">Мултимедија</string>
+ <string name="user">Прилагођено</string>
+ <string name="user_n">Прилагођено <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Ниједно</string>
<string name="smallroom">Мала соба</string>
<string name="mediumroom">Средња соба</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Ефекат није доступан за режим Звучника.</string>
<string name="device_headset">Слушалице</string>
<string name="device_speaker">Звучник</string>
- <string name="device_lineout">Излаз</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Wireless</string>
<string name="reverb">Reverb</string>
<string name="eq_preset">Еквилајзер унапред постављен</string>
+ <string name="devices">Уређаји</string>
+ <string name="virtualizer">Визуелно</string>
+ <string name="treble">Високи</string>
+ <string name="bass">Бас</string>
+ <string name="rename">Преименуј</string>
+ <string name="remove_custom_preset_warning_message">Да ли сигурно желиш уклонити %1$s?</string>
</resources>
diff --git a/res/values-sv/cm_strings.xml b/res/values-sv/cm_strings.xml
index d437200..10c5b21 100644
--- a/res/values-sv/cm_strings.xml
+++ b/res/values-sv/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klassisk</string>
<string name="dance">Dance</string>
@@ -26,9 +26,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronisk</string>
+ <string name="ci_extreme">Elektronisk</string>
<string name="small_speakers">Små högtalare</string>
- <string name="custom">Anpassad</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Anpassad</string>
+ <string name="user_n">Anpassade <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Ingen</string>
<string name="smallroom">Litet rum</string>
<string name="mediumroom">Medelstort rum</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Effekten finns inte tillgänglig för högtalarläge.</string>
<string name="device_headset">Hörlurar</string>
<string name="device_speaker">Högtalare</string>
- <string name="device_lineout">Linjeutgång</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Trådlös</string>
<string name="reverb">Rumsklang</string>
<string name="eq_preset">Equalizerförval</string>
+ <string name="devices">Enheter</string>
+ <string name="virtualizer">Virtualiserare</string>
+ <string name="treble">Diskant</string>
+ <string name="bass">Bas</string>
+ <string name="rename">Byt namn</string>
+ <string name="remove_custom_preset_warning_message">Är du säker du vill ta bort %1$s?</string>
</resources>
diff --git a/res/values-ta-rIN/cm_strings.xml b/res/values-ta-rIN/cm_strings.xml
index af60552..c2fbb6b 100644
--- a/res/values-ta-rIN/cm_strings.xml
+++ b/res/values-ta-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">இயல்பு</string>
<string name="classical">கிளாசிக்கல்</string>
<string name="dance">டான்ஸ்</string>
@@ -26,9 +26,11 @@
<string name="jazz">ஜாஸ்</string>
<string name="pop">பாப்</string>
<string name="rock">ராக்</string>
- <string name="electronic">மின்னணு</string>
+ <string name="ci_extreme">மின்னணு</string>
<string name="small_speakers">சிறிய ஒலிபெருக்கிகள்</string>
- <string name="custom">தனிப்பயன்</string>
+ <string name="multimedia">மல்டிமீடியா</string>
+ <string name="user">தனிப்பயன்</string>
+ <string name="user_n">தனிப்பயன் <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">ஏதுமில்லை</string>
<string name="smallroom">சிறிய அறை</string>
<string name="mediumroom">நடுத்தர அறை</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">கம்பியில்லா</string>
<string name="reverb">எதிர்முழக்கம்</string>
<string name="eq_preset">சமனாக்கி முன்னமை</string>
+ <string name="devices">சாதனங்கள்</string>
+ <string name="virtualizer">தோற்றநிலையாக்கி</string>
+ <string name="treble">டிரெபில்</string>
+ <string name="bass">பேஸ்</string>
+ <string name="rename">மறுபெயரிடு</string>
+ <string name="remove_custom_preset_warning_message">%1$sஐ நீக்க நீங்கள் நிச்சயமாக விரும்புகிறீர்களா?</string>
</resources>
diff --git a/res/values-te-rIN/cm_strings.xml b/res/values-te-rIN/cm_strings.xml
index aa52869..2c8344b 100644
--- a/res/values-te-rIN/cm_strings.xml
+++ b/res/values-te-rIN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">సాధారణం</string>
<string name="classical">క్లాసికల్</string>
<string name="dance">నృత్యం</string>
@@ -26,15 +26,17 @@
<string name="jazz">జాజ్</string>
<string name="pop">పాప్</string>
<string name="rock">రాక్</string>
- <string name="electronic">ఎలక్ట్రానిక్</string>
+ <string name="ci_extreme">ఎలక్ట్రానిక్</string>
<string name="small_speakers">చిన్న స్పీకర్లు</string>
- <string name="custom">అనుకూలం</string>
+ <string name="multimedia">మల్టీమీడియా</string>
+ <string name="user">అనుకూలం</string>
+ <string name="user_n">అనుకూల <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">ఏదీ లేదు</string>
<string name="smallroom">చిన్న గది</string>
- <string name="mediumroom">మధ్యస్థం గది</string>
+ <string name="mediumroom">మధ్యస్థ గది</string>
<string name="largeroom">పెద్ద గది</string>
- <string name="mediumhall">మధ్యస్థం హాల్</string>
- <string name="largehall">పెద్ద గది</string>
+ <string name="mediumhall">మధ్యస్థ హాల్</string>
+ <string name="largehall">పెద్ద హాల్</string>
<string name="plate">ప్లేటు</string>
<string name="power_on_prompt">పైన కుడి వైపున ఉన్న పవర్ బటన్ నొక్కండి.</string>
<string name="effect_unavalable_for_speaker">స్పీకర్ రీతి కొరకు ప్రభావం అందుబాటులో లేదు.</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">నిస్తంత్రి</string>
<string name="reverb">ప్రతిధ్వని</string>
<string name="eq_preset">ముందుగా అమర్చిన ఈక్విలైజర్</string>
+ <string name="devices">పరికరంలు</string>
+ <string name="virtualizer">వర్చువలైజర్</string>
+ <string name="treble">ట్రెబెల్</string>
+ <string name="bass">బాస్</string>
+ <string name="rename">పేరు మార్చు</string>
+ <string name="remove_custom_preset_warning_message">మీరు %1$s ను తొలిగించాలని నిర్ధారించుకున్నారా?</string>
</resources>
diff --git a/res/values-th/cm_strings.xml b/res/values-th/cm_strings.xml
index 0d7d1f5..70983d5 100644
--- a/res/values-th/cm_strings.xml
+++ b/res/values-th/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">ปกติ</string>
<string name="classical">คลาสสิก</string>
<string name="dance">แดนซ์</string>
@@ -26,9 +26,11 @@
<string name="jazz">แจ๊ส</string>
<string name="pop">ป๊อป</string>
<string name="rock">ร็อค</string>
- <string name="electronic">อิเล็กทรอนิก</string>
+ <string name="ci_extreme">อิเล็กทรอนิก</string>
<string name="small_speakers">ลำโพงเล็ก</string>
- <string name="custom">กำหนดเอง</string>
+ <string name="multimedia">มัลติมีเดีย</string>
+ <string name="user">กำหนดเอง</string>
+ <string name="user_n">กำหนดเอง <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">ไม่มี</string>
<string name="smallroom">ห้องขนาดเล็ก</string>
<string name="mediumroom">ห้องขนาดกลาง</string>
@@ -36,14 +38,19 @@
<string name="mediumhall">โถงขนาดกลาง</string>
<string name="largehall">โถงขนาดใหญ่</string>
<string name="plate">เวที</string>
- <string name="power_on_prompt">กดปุ่มเพาเวอร์ด้านบนขวา</string>
- <string name="effect_unavalable_for_speaker">เอฟเฟกต์นี้ไม่สามารถใช้ได้กับรูปแบบลำโพง</string>
+ <string name="power_on_prompt">กดปุ่มพาวเวอร์ด้านบนขวา</string>
+ <string name="effect_unavalable_for_speaker">ใช้เอฟเฟกต์ไม่ได้กับรูปแบบลำโพง</string>
<string name="device_headset">หูฟัง</string>
<string name="device_speaker">ลำโพง</string>
- <string name="device_lineout">สายออก</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">บลูทูธ</string>
<string name="device_wireless">แบบไร้สาย</string>
<string name="reverb">เสียงก้อง</string>
<string name="eq_preset">ชุดรูปแบบปรับแต่งเสียง</string>
+ <string name="devices">อุปกรณ์</string>
+ <string name="virtualizer">บริการเอฟเฟกต์เสมือนจริง</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bass</string>
+ <string name="rename">เปลี่ยนชื่อ</string>
+ <string name="remove_custom_preset_warning_message">แน่ใจหรือไม่ว่าต้องการลบ %1$s</string>
</resources>
diff --git a/res/values-tr/cm_strings.xml b/res/values-tr/cm_strings.xml
index 605d772..b6aa029 100644
--- a/res/values-tr/cm_strings.xml
+++ b/res/values-tr/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Normal</string>
<string name="classical">Klasik</string>
<string name="dance">Dans</string>
@@ -26,9 +26,11 @@
<string name="jazz">Caz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Elektronik</string>
+ <string name="ci_extreme">Elektronik</string>
<string name="small_speakers">Küçük hoparlörler</string>
- <string name="custom">Özel</string>
+ <string name="multimedia">Multimedya</string>
+ <string name="user">Özel</string>
+ <string name="user_n">Özel <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">Yok</string>
<string name="smallroom">Küçük oda</string>
<string name="mediumroom">Orta boy oda</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">Efekt Hoparlör modunda kullanılamıyor.</string>
<string name="device_headset">Kulaklık</string>
<string name="device_speaker">Hoparlör</string>
- <string name="device_lineout">Hat çıkışı</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
- <string name="device_wireless">Kablosuz</string>
+ <string name="device_wireless">Kablosuz cihaz</string>
<string name="reverb">Yankı</string>
<string name="eq_preset">Equalizer önayarı</string>
+ <string name="devices">Cihazlar</string>
+ <string name="virtualizer">Görselleştirici</string>
+ <string name="treble">Tiz</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Yeniden adlandır</string>
+ <string name="remove_custom_preset_warning_message">%1$s önayarını kaldırmak istediğinizden emin misiniz?</string>
</resources>
diff --git a/res/values-ug/cm_strings.xml b/res/values-ug/cm_strings.xml
index 9422ddf..174e330 100644
--- a/res/values-ug/cm_strings.xml
+++ b/res/values-ug/cm_strings.xml
@@ -15,20 +15,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">ئادەتتىكى</string>
<string name="classical">كىلاسسىك</string>
<string name="dance">ئۇسسۇل</string>
- <string name="flat">تەكشىلىك</string>
+ <string name="flat">يېنىك</string>
<string name="folk">خەلق ناخشىسى</string>
<string name="heavy_metal">ئېغىر مېتال</string>
<string name="hip_hop">Hip Hop</string>
<string name="jazz">جاز</string>
<string name="pop">مودا نەغمە</string>
<string name="rock">تولغىما ئۇسسۇل</string>
- <string name="electronic">ئېلېكتىرونلۇق</string>
+ <string name="ci_extreme">ئېلېكتىرونلۇق</string>
<string name="small_speakers">كىچىك ياڭراتقۇلار</string>
- <string name="custom">ئىختىيارىي</string>
+ <string name="multimedia">كۆپ ۋاستە</string>
+ <string name="user">ئىختىيارى</string>
+ <string name="user_n">خاسلاشتۇرۇش <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">يوق</string>
<string name="smallroom">كىچىك ئۆي</string>
<string name="mediumroom">ئوتتۇرىھال ئۆي</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">سىمسىز</string>
<string name="reverb">ئارىلاش ئاۋاز</string>
<string name="eq_preset">تەڭشىگۈچنى ئالدىن تەڭشەش</string>
+ <string name="devices">ئۈسكىنە</string>
+ <string name="virtualizer">مەۋھۇم تەڭشىگۈچ</string>
+ <string name="treble">ئۈچ ھەسسە</string>
+ <string name="bass">تۆۋەن ئاۋاز</string>
+ <string name="rename">قايتا ناملاش</string>
+ <string name="remove_custom_preset_warning_message">%1$s نى راستلا ئۆچۈرۋېتەمسىز؟</string>
</resources>
diff --git a/res/values-uk/cm_strings.xml b/res/values-uk/cm_strings.xml
index 8de6491..7620f51 100644
--- a/res/values-uk/cm_strings.xml
+++ b/res/values-uk/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Нормальний</string>
<string name="classical">Класика</string>
<string name="dance">Танцювальна</string>
@@ -26,9 +26,11 @@
<string name="jazz">Джаз</string>
<string name="pop">Поп</string>
<string name="rock">Рок</string>
- <string name="electronic">Електронна</string>
+ <string name="ci_extreme">Електронна</string>
<string name="small_speakers">Маленькі динаміки</string>
- <string name="custom">Користувач</string>
+ <string name="multimedia">Мультимедіа</string>
+ <string name="user">Користувач</string>
+ <string name="user_n">Користувацькі <xliff:g id="preset_num">%1$d </xliff:g></string>
<string name="none">Немає</string>
<string name="smallroom">Мала кімната</string>
<string name="mediumroom">Середня кімната</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">Бездротові</string>
<string name="reverb">Реверберація</string>
<string name="eq_preset">Налаштування еквалайзера</string>
+ <string name="devices">Пристрої</string>
+ <string name="virtualizer">Віртуалізатор</string>
+ <string name="treble">Високі</string>
+ <string name="bass">Бас</string>
+ <string name="rename">Перейменувати</string>
+ <string name="remove_custom_preset_warning_message">Ви дійсно бажаєте видалити %1$s?</string>
</resources>
diff --git a/res/values-vi/cm_strings.xml b/res/values-vi/cm_strings.xml
index 6ee978d..cab13d8 100644
--- a/res/values-vi/cm_strings.xml
+++ b/res/values-vi/cm_strings.xml
@@ -15,35 +15,42 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">Bình thường</string>
<string name="classical">Cổ điển</string>
<string name="dance">Dance</string>
<string name="flat">Flat</string>
- <string name="folk">Dân ca</string>
+ <string name="folk">Dân gian</string>
<string name="heavy_metal">Heavy Metal</string>
<string name="hip_hop">Hip Hop</string>
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
+ <string name="ci_extreme">Electronic</string>
<string name="small_speakers">Loa nhỏ</string>
- <string name="custom">Tùy chỉnh</string>
- <string name="none">Không</string>
+ <string name="multimedia">Đa phương tiện</string>
+ <string name="user">Tuỳ chỉnh</string>
+ <string name="user_n">Tuỳ chỉnh <xliff:g id="preset_num">%1$d </xliff:g></string>
+ <string name="none">Không có</string>
<string name="smallroom">Phòng nhỏ</string>
<string name="mediumroom">Phòng trung bình</string>
<string name="largeroom">Phòng lớn</string>
- <string name="mediumhall">Hội trường trung bình</string>
+ <string name="mediumhall">Hộ trường trung bình</string>
<string name="largehall">Hội trường lớn</string>
- <string name="plate">Đĩa</string>
+ <string name="plate">Plate</string>
<string name="power_on_prompt">Nhấn nút nguồn điện ở trên cùng bên phải.</string>
<string name="effect_unavalable_for_speaker">Hiệu ứng không khả dụng với chế độ Loa ngoài.</string>
<string name="device_headset">Tai nghe</string>
<string name="device_speaker">Loa ngoài</string>
- <string name="device_lineout">Đường tín hiệu cho đầu ra</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Không dây</string>
<string name="reverb">Âm vang</string>
- <string name="eq_preset">Cài sẵn bộ chỉnh âm</string>
+ <string name="eq_preset">Thiết lập trước bộ chỉnh âm</string>
+ <string name="devices">Thiết bị</string>
+ <string name="virtualizer">Trực quan hóa</string>
+ <string name="treble">Gấp ba</string>
+ <string name="bass">Bass</string>
+ <string name="rename">Đổi tên</string>
+ <string name="remove_custom_preset_warning_message">Bạn có chắc là bạn muốn gỡ bỏ %1$s?</string>
</resources>
diff --git a/res/values-zh-rCN/cm_strings.xml b/res/values-zh-rCN/cm_strings.xml
index 025fe9f..00e2159 100644
--- a/res/values-zh-rCN/cm_strings.xml
+++ b/res/values-zh-rCN/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">正常</string>
<string name="classical">古典音乐</string>
<string name="dance">舞曲</string>
@@ -26,9 +26,11 @@
<string name="jazz">爵士</string>
<string name="pop">流行</string>
<string name="rock">摇滚</string>
- <string name="electronic">电子</string>
+ <string name="ci_extreme">电子</string>
<string name="small_speakers">小型喇叭</string>
- <string name="custom">自定义</string>
+ <string name="multimedia">多媒体</string>
+ <string name="user">自定义</string>
+ <string name="user_n">自定义 <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">无</string>
<string name="smallroom">小房间</string>
<string name="mediumroom">中等房间</string>
@@ -40,10 +42,15 @@
<string name="effect_unavalable_for_speaker">效果不适用于扬声器模式。</string>
<string name="device_headset">耳机</string>
<string name="device_speaker">扬声器​​​​</string>
- <string name="device_lineout">线路输出</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">蓝牙</string>
<string name="device_wireless">无线</string>
<string name="reverb">混响</string>
<string name="eq_preset">均衡器预设</string>
+ <string name="devices">设备</string>
+ <string name="virtualizer">虚拟均衡器</string>
+ <string name="treble">三倍</string>
+ <string name="bass">低音</string>
+ <string name="rename">重命名</string>
+ <string name="remove_custom_preset_warning_message">您确定想要移除 %1$s ?</string>
</resources>
diff --git a/res/values-zh-rHK/cm_strings.xml b/res/values-zh-rHK/cm_strings.xml
index 249acde..4725c99 100644
--- a/res/values-zh-rHK/cm_strings.xml
+++ b/res/values-zh-rHK/cm_strings.xml
@@ -15,7 +15,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">正常</string>
<string name="classical">古典音樂</string>
<string name="dance">舞曲</string>
@@ -26,9 +26,11 @@
<string name="jazz">爵士樂</string>
<string name="pop">流行音樂</string>
<string name="rock">搖滾</string>
- <string name="electronic">電子音樂</string>
+ <string name="ci_extreme">電子音樂</string>
<string name="small_speakers">小型喇叭</string>
- <string name="custom">自訂</string>
+ <string name="multimedia">多媒體</string>
+ <string name="user">自訂</string>
+ <string name="user_n">自訂 <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">無</string>
<string name="smallroom">小型房間</string>
<string name="mediumroom">中型房間</string>
@@ -45,4 +47,10 @@
<string name="device_wireless">無綫</string>
<string name="reverb">混響效果</string>
<string name="eq_preset">等化器預設</string>
+ <string name="devices">裝置</string>
+ <string name="virtualizer">虛擬器</string>
+ <string name="treble">高音</string>
+ <string name="bass">低音</string>
+ <string name="rename">重新命名</string>
+ <string name="remove_custom_preset_warning_message">您確定想要移除 %1$s?</string>
</resources>
diff --git a/res/values-zh-rTW/cm_strings.xml b/res/values-zh-rTW/cm_strings.xml
index 13bea9b..368b2f9 100644
--- a/res/values-zh-rTW/cm_strings.xml
+++ b/res/values-zh-rTW/cm_strings.xml
@@ -15,20 +15,20 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="normal">正常</string>
- <string name="classical">古典</string>
+ <string name="classical">古典音樂</string>
<string name="dance">舞曲</string>
<string name="flat">平淡</string>
<string name="folk">民謠</string>
<string name="heavy_metal">重金屬</string>
<string name="hip_hop">嘻哈</string>
<string name="jazz">爵士樂</string>
- <string name="pop">流行</string>
+ <string name="pop">流行音樂</string>
<string name="rock">搖滾</string>
- <string name="electronic">電子</string>
- <string name="small_speakers">小型揚聲器</string>
- <string name="custom">自訂</string>
+ <string name="ci_extreme">電子</string>
+ <string name="small_speakers">小型喇叭</string>
+ <string name="user">自訂</string>
<string name="none">無</string>
<string name="smallroom">小型房間</string>
<string name="mediumroom">中型房間</string>
@@ -39,11 +39,13 @@
<string name="power_on_prompt">按下右上方的電源鍵。</string>
<string name="effect_unavalable_for_speaker">效果不適用於擴音器模式。</string>
<string name="device_headset">耳機</string>
- <string name="device_speaker">揚聲器</string>
- <string name="device_lineout">線路輸出</string>
+ <string name="device_speaker">擴音器</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">藍牙</string>
<string name="device_wireless">無線裝置</string>
<string name="reverb">混響</string>
- <string name="eq_preset">預設等化器</string>
+ <string name="eq_preset">等化器預設</string>
+ <string name="devices">裝置</string>
+ <string name="rename">重新命名</string>
+ <string name="remove_custom_preset_warning_message">你確定要刪除 %1$s?</string>
</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
deleted file mode 100644
index 2da318f..0000000
--- a/res/values/attrs.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (c) 2013, The Linux Foundation. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--->
-
-<resources>
- <declare-styleable name="Knob">
- <attr name="label" format="string" />
- <attr name="background" format="integer" />
- <attr name="foreground" format="integer" />
- </declare-styleable>
-</resources>
diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml
index 16d24ff..bea5314 100644
--- a/res/values/cm_strings.xml
+++ b/res/values/cm_strings.xml
@@ -14,8 +14,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<resources>
- <string name="app_name_cm" translatable="false">AudioFX</string>
+<resources xmlns:xliff="rn:oasis:names:tc:xliff:document:1.2">
+ <string name="snack_bar_not_default">AudioFX is not your default effects control panel.</string>
+ <string name="snack_bar_not_default_set">Set default</string>
+ <string name="snack_bar_not_default_not_now">Not now</string>
+
+ <string name="qs_tile_content_description">Toggle AudioFX on/off for the current device</string>
+ <string name="qs_tile_label">AudioFX (%1$s)</string>
<string name="normal">Normal</string>
<string name="classical">Classical</string>
@@ -27,9 +32,11 @@
<string name="jazz">Jazz</string>
<string name="pop">Pop</string>
<string name="rock">Rock</string>
- <string name="electronic">Electronic</string>
+ <string name="ci_extreme">Electronic</string>
<string name="small_speakers">Small speakers</string>
- <string name="custom">Custom</string>
+ <string name="multimedia">Multimedia</string>
+ <string name="user">Custom</string>
+ <string name="user_n">Custom <xliff:g id="preset_num">%1$d</xliff:g></string>
<string name="none">None</string>
<string name="smallroom">Small room</string>
@@ -41,13 +48,32 @@
<string name="power_on_prompt">Press the power button on the top-right.</string>
<string name="effect_unavalable_for_speaker">Effect not available for Speaker mode.</string>
-
+
<string name="device_headset">Headset</string>
<string name="device_speaker">Speaker</string>
- <string name="device_lineout">Line out</string>
<string name="device_usb">USB</string>
<string name="device_bluetooth">Bluetooth</string>
<string name="device_wireless">Wireless</string>
+ <string name="device_line_out">Line out</string>
+
<string name="reverb">Reverb</string>
<string name="eq_preset">Equalizer preset</string>
+
+ <string name="devices">Devices</string>
+
+ <string name="virtualizer">Virtualizer</string>
+ <string name="treble">Treble</string>
+ <string name="bass">Bass</string>
+
+ <string name="rename">Rename</string>
+ <string name="remove_custom_preset_warning_message">Are you sure you want to remove %1$s?</string>
+
+ <string name="app_name" translatable="false">AudioFX</string>
+ <string name="app_title" translatable="false">@string/app_name</string>
+
+ <string name="powered_by_maxx_audio" translatable="false">Powered by MaxxAudio</string>
+ <string name="mode_dts" translatable="false">with DTS Sound&#8482;</string>
+ <string name="powered_by">powered by</string>
+
+
</resources>
diff --git a/res/values/color.xml b/res/values/colors.xml
index 2814058..2a88cd4 100644
--- a/res/values/color.xml
+++ b/res/values/colors.xml
@@ -35,30 +35,50 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<color name="reverb_label_text_color">#ff808080</color>
<color name="highlight">#cc8f8f8f</color>
- <color name="lowlight">#ccf4fcff</color>
- <color name="grey">#9e9e9e</color>
+ <color name="lowlight">#558f8f8f</color>
+ <color name="grey">#80e7e7e7</color>
<color name="disabled">#80525252</color>
<color name="disabled_gallery">#888888</color>
<color name="disabled_knob">#575757</color>
- <color name="primary">#607D8B</color>
- <color name="primary_dark">#455A64</color>
- <color name="accent">#78909C</color>
-
- <color name="white">#fafafa</color>
- <color name="black">#212121</color>
+ <color name="white">#ffffffff</color>
+ <color name="color_grey">#90dedede</color>
+ <color name="black">#ff000000</color>
<color name="grid_lines">#22ffffff</color>
<color name="cb">#88ffffff</color>
<color name="freq_hl">#2000ddff</color>
<color name="freq_hl2">#4033b5e5</color>
- <color name="eq_red">#f44336</color>
- <color name="eq_green">#8bc34a</color>
- <color name="eq_yellow">#ff9800</color>
+ <color name="eq_red">#80ff0000</color>
+ <color name="eq_green">#80aaeaaa</color>
+ <color name="eq_yellow">#80f0ff00</color>
<color name="eq_holo_bright">#8000ddff</color>
<color name="eq_holo_blue">#8033b5e5</color>
<color name="eq_holo_dark">#800099cc</color>
<color name="cb_shader">#ffffffff</color>
<color name="cb_shader_alpha">#22ffffff</color>
- <color name="window_background">@color/black</color>
+ <color name="window_background">#ff000000</color>
+
+ <color name="band_freq_label">#ffffffff</color>
+ <color name="band_bar_color_1">#FFCCCCCC</color>
+ <color name="band_bar_color_2">#FFDDDDDD</color>
+
+ <color name="preset_custom">#CE5B4C</color>
+ <color name="preset_normal">#CB6139</color>
+ <color name="preset_classical">#BE963F</color>
+ <color name="preset_dance">#BEBD3F</color>
+ <color name="preset_flat">#84B74E</color>
+ <color name="preset_folk">#80B74F</color>
+ <color name="preset_metal">#65B759</color>
+ <color name="preset_hiphop">#5CB797</color>
+ <color name="preset_jazz">#5B82B7</color>
+ <color name="preset_pop">#585DCA</color>
+ <color name="preset_rock">#9A62CB</color>
+ <color name="preset_electronic">#C862C5</color>
+ <color name="preset_small_speakers">#CB629A</color>
+ <color name="band_bar_color_selected">#ffffffff</color>
+ <color name="knob_container_background">#323437</color>
+ <color name="disabled_eq">#ff6c6c6c</color>
+ <color name="radial_knob_arc_bg">#4e5052</color>
+ <color name="radial_knob_arc_bg_disabled">#6c6c6c</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index ab9f0b8..93019de 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -17,12 +17,41 @@
<resources>
<dimen name="eq_slider_margin">5dip</dimen>
<dimen name="eq_slider_height">180dip</dimen>
- <dimen name="eq_text_height">20dip</dimen>
+
+ <!-- size of frequency labels below bars -->
+ <dimen name="eq_label_text_size">9sp</dimen>
+
+ <!-- size of selected frequency/db text sizes [both right now ] -->
+ <dimen name="eq_selected_box_height">15sp</dimen>
+
+ <!-- extra room at the bottom of the eq bar to never shrink below -->
+ <dimen name="eq_bar_bottom_grab_space">20dp</dimen>
+
+ <!-- extra space above floating selected bar db -->
+ <dimen name="eq_bar_top_padding">10dp</dimen>
+
+ <dimen name="preset_text_size">30sp</dimen>
+ <dimen name="preset_text_padding">4dp</dimen>
<dimen name="action_bar_switch_padding">16dip</dimen>
<dimen name="action_bar_button_width">96dip</dimen>
<dimen name="action_bar_button_height">34dip</dimen>
- <dimen name="eq_bar_width">20dp</dimen>
- <dimen name="eq_label_text_size">9dp</dimen>
+
+ <dimen name="eq_bar_width">24dp</dimen>
+ <dimen name="separator_width">4dp</dimen>
+
+ <dimen name="knob_height">150dp</dimen>
+ <dimen name="knob_width">100dp</dimen>
+ <dimen name="knob_container_height_small">180dp</dimen>
+ <dimen name="knob_container_height_expanded">200dp</dimen>
+ <dimen name="drag_area_max">200dp</dimen>
+ <dimen name="knob_container_padding_bottom">8dp</dimen>
+
+ <dimen name="radial_rect_padding">11dp</dimen>
+ <dimen name="radial_text_size">18sp</dimen>
+ <dimen name="radial_knob_stroke">22dp</dimen>
+
+ <dimen name="action_bar_dts_switch_padding">48dp</dimen>
+
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 143efa5..08a22fb 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -15,17 +15,17 @@
-->
<resources>
- <string name="app_name">MusicFX</string>
-
<!-- ControlPanelMusic strings -->
<string name="no_effects">Effects not available.</string>
- <string name="eq_dialog_title">Equalizer</string>
+ <string name="main_toggle_effects_title">Audio effects</string>
+ <string name="eq_dialog_title">AudioFX</string>
<string name="headset_plug">Plug in headphones for these effects.</string>
<string name="bass_boost_strength">Bass boost</string>
<string name="virtualizer_strength">Surround sound</string>
+ <string name="pr_title">Reverb:</string>
+ <string name="pr_summary">Additional room reverberation effects</string>
+ <string name="pr_dialog_title">Reverb preset</string>
<string name="setup">Setup</string>
- <string name="ci_extreme">FX booster</string>
- <string name="user">User</string>
<!-- title of control panel picker dialog [CHAR LIMIT=30] -->
<string name="picker_title">Music effects control panel"</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 35b8f31..319ed7f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -16,26 +16,28 @@
<resources>
<style name="AppTheme" parent="android:Theme.Material">
- <item name="android:colorPrimary">@color/primary</item>
- <item name="android:colorPrimaryDark">@color/primary_dark</item>
- <item name="android:colorAccent">@color/accent</item>
<item name="android:windowBackground">@color/window_background</item>
</style>
- <style name="Widget.Material.SeekBar.Vertical" parent="@android:Widget.Holo.SeekBar">
- <item name="android:indeterminateOnly">false</item>
- <item name="android:progressDrawable">@drawable/scrubber_progress_vertical_holo_dark</item>
- <item name="android:colorPrimary">@color/primary</item>
- <item name="android:colorPrimaryDark">@color/primary_dark</item>
- <item name="android:colorAccent">@color/accent</item>
-<!-- not public <item name="android:indeterminateDrawable">@android:drawable/scrubber_progress_horizontal_holo_dark</item> -->
- <item name="android:minWidth">33dip</item>
- <item name="android:maxWidth">33dip</item>
- <item name="android:thumb">@drawable/scrubber_control_selector_holo</item>
- <item name="android:thumbOffset">16dip</item>
- <item name="android:focusable">true</item>
- <item name="android:paddingLeft">0dip</item>
- <item name="android:paddingRight">0dip</item>
- <item name="android:paddingTop">16dip</item>
- <item name="android:paddingBottom">16dip</item>
+
+ <style name="AppThemeV2" parent="android:Theme.Material">
+ <item name="android:actionBarStyle">@style/ActionBar</item>
+ </style>
+
+ <style name="ActionBar" parent="android:Widget.Material.ActionBar.Solid">
+ <item name="android:titleTextStyle">@style/AppThemeV2.ActionBar.TitleTextStyle</item>
+ <item name="android:subtitleTextStyle">@style/AppThemeV2.ActionBar.SubtitleTextStyle</item>
+ </style>
+
+ <style name="AppThemeV2.ActionBar.TitleTextStyle" parent="@android:style/TextAppearance.Material.Widget.ActionBar.Title">
+ <item name="android:textColor">@color/white</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:fontFamily">sans-serif</item>
+ <item name="android:textStyle">bold</item>
+ </style>
+
+ <style name="AppThemeV2.ActionBar.SubtitleTextStyle" parent="@android:style/TextAppearance.Material.Widget.ActionBar.Subtitle">
+ <item name="android:textSize">10sp</item>
+ <item name="android:fontFamily">sans-serif</item>
</style>
+
</resources>
diff --git a/res/values/vpi__attrs.xml b/res/values/vpi__attrs.xml
new file mode 100644
index 0000000..3115872
--- /dev/null
+++ b/res/values/vpi__attrs.xml
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 Jake Wharton
+ Copyright (C) 2011 Patrik Åkerfeldt
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <declare-styleable name="ViewPagerIndicator">
+ <!-- Style of the circle indicator. -->
+ <attr name="vpiCirclePageIndicatorStyle" format="reference"/>
+ <!-- Style of the icon indicator's views. -->
+ <attr name="vpiIconPageIndicatorStyle" format="reference"/>
+ <!-- Style of the line indicator. -->
+ <attr name="vpiLinePageIndicatorStyle" format="reference"/>
+ <!-- Style of the title indicator. -->
+ <attr name="vpiTitlePageIndicatorStyle" format="reference"/>
+ <!-- Style of the tab indicator's tabs. -->
+ <attr name="vpiTabPageIndicatorStyle" format="reference"/>
+ <!-- Style of the underline indicator. -->
+ <attr name="vpiUnderlinePageIndicatorStyle" format="reference"/>
+ </declare-styleable>
+
+ <attr name="centered" format="boolean" />
+ <attr name="selectedColor" format="color" />
+ <attr name="strokeWidth" format="dimension" />
+ <attr name="unselectedColor" format="color" />
+
+ <declare-styleable name="CirclePageIndicator">
+ <!-- Whether or not the indicators should be centered. -->
+ <attr name="centered" />
+ <!-- Color of the filled circle that represents the current page. -->
+ <attr name="fillColor" format="color" />
+ <!-- Color of the filled circles that represents pages. -->
+ <attr name="pageColor" format="color" />
+ <!-- Orientation of the indicator. -->
+ <attr name="android:orientation"/>
+ <!-- Radius of the circles. This is also the spacing between circles. -->
+ <attr name="radius" format="dimension" />
+ <!-- Whether or not the selected indicator snaps to the circles. -->
+ <attr name="snap" format="boolean" />
+ <!-- Color of the open circles. -->
+ <attr name="strokeColor" format="color" />
+ <!-- Width of the stroke used to draw the circles. -->
+ <attr name="strokeWidth" />
+ <!-- View background -->
+ <attr name="android:background"/>
+ </declare-styleable>
+
+ <declare-styleable name="LinePageIndicator">
+ <!-- Whether or not the indicators should be centered. -->
+ <attr name="centered" />
+ <!-- Color of the unselected lines that represent the pages. -->
+ <attr name="unselectedColor" />
+ <!-- Color of the selected line that represents the current page. -->
+ <attr name="selectedColor" />
+ <!-- Width of each indicator line. -->
+ <attr name="lineWidth" format="dimension" />
+ <!-- Width of each indicator line's stroke. -->
+ <attr name="strokeWidth" />
+ <!-- Width of the gap between each indicator line. -->
+ <attr name="gapWidth" format="dimension" />
+ <!-- View background -->
+ <attr name="android:background"/>
+ </declare-styleable>
+
+ <declare-styleable name="TitlePageIndicator">
+ <!-- Screen edge padding. -->
+ <attr name="clipPadding" format="dimension" />
+ <!-- Color of the footer line and indicator. -->
+ <attr name="footerColor" format="color" />
+ <!-- Height of the footer line. -->
+ <attr name="footerLineHeight" format="dimension" />
+ <!-- Style of the indicator. Default is triangle. -->
+ <attr name="footerIndicatorStyle">
+ <enum name="none" value="0" />
+ <enum name="triangle" value="1" />
+ <enum name="underline" value="2" />
+ </attr>
+ <!-- Height of the indicator above the footer line. -->
+ <attr name="footerIndicatorHeight" format="dimension" />
+ <!-- Left and right padding of the underline indicator. -->
+ <attr name="footerIndicatorUnderlinePadding" format="dimension" />
+ <!-- Padding between the bottom of the title and the footer. -->
+ <attr name="footerPadding" format="dimension" />
+ <!-- Position of the line. -->
+ <attr name="linePosition">
+ <enum name="bottom" value="0"/>
+ <enum name="top" value="1"/>
+ </attr>
+ <!-- Color of the selected title. -->
+ <attr name="selectedColor" />
+ <!-- Whether or not the selected item is displayed as bold. -->
+ <attr name="selectedBold" format="boolean" />
+ <!-- Color of regular titles. -->
+ <attr name="android:textColor" />
+ <!-- Size of title text. -->
+ <attr name="android:textSize" />
+ <!-- Padding between titles when bumping into each other. -->
+ <attr name="titlePadding" format="dimension" />
+ <!-- Padding between titles and the top of the View. -->
+ <attr name="topPadding" format="dimension" />
+ <!-- View background -->
+ <attr name="android:background"/>
+ </declare-styleable>
+
+ <declare-styleable name="UnderlinePageIndicator">
+ <!-- Whether or not the selected indicator fades. -->
+ <attr name="fades" format="boolean" />
+ <!-- Length of the delay to fade the indicator. -->
+ <attr name="fadeDelay" format="integer" />
+ <!-- Length of the indicator fade to transparent. -->
+ <attr name="fadeLength" format="integer" />
+ <!-- Color of the selected line that represents the current page. -->
+ <attr name="selectedColor" />
+ <!-- View background -->
+ <attr name="android:background"/>
+ </declare-styleable>
+</resources> \ No newline at end of file
diff --git a/res/values/vpi__colors.xml b/res/values/vpi__colors.xml
new file mode 100644
index 0000000..a61b75f
--- /dev/null
+++ b/res/values/vpi__colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 Jake Wharton
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <color name="vpi__background_holo_dark">#ff000000</color>
+ <color name="vpi__background_holo_light">#fff3f3f3</color>
+ <color name="vpi__bright_foreground_holo_dark">@color/vpi__background_holo_light</color>
+ <color name="vpi__bright_foreground_holo_light">@color/vpi__background_holo_dark</color>
+ <color name="vpi__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
+ <color name="vpi__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
+ <color name="vpi__bright_foreground_inverse_holo_dark">@color/vpi__bright_foreground_holo_light</color>
+ <color name="vpi__bright_foreground_inverse_holo_light">@color/vpi__bright_foreground_holo_dark</color>
+</resources> \ No newline at end of file
diff --git a/res/values/vpi__defaults.xml b/res/values/vpi__defaults.xml
new file mode 100644
index 0000000..1a52917
--- /dev/null
+++ b/res/values/vpi__defaults.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 Jake Wharton
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <bool name="default_circle_indicator_centered">true</bool>
+ <color name="default_circle_indicator_fill_color">#ffFFFFFF</color>
+ <color name="default_circle_indicator_page_color">#ffcccccc</color>
+ <integer name="default_circle_indicator_orientation">0</integer>
+ <dimen name="default_circle_indicator_radius">3dp</dimen>
+ <bool name="default_circle_indicator_snap">false</bool>
+ <color name="default_circle_indicator_stroke_color">#ffcccccc</color>
+ <dimen name="default_circle_indicator_stroke_width">0dp</dimen>
+
+ <dimen name="default_line_indicator_line_width">12dp</dimen>
+ <dimen name="default_line_indicator_gap_width">4dp</dimen>
+ <dimen name="default_line_indicator_stroke_width">1dp</dimen>
+ <color name="default_line_indicator_selected_color">#FF33B5E5</color>
+ <color name="default_line_indicator_unselected_color">#FFBBBBBB</color>
+ <bool name="default_line_indicator_centered">true</bool>
+
+ <dimen name="default_title_indicator_clip_padding">4dp</dimen>
+ <color name="default_title_indicator_footer_color">#FF33B5E5</color>
+ <dimen name="default_title_indicator_footer_line_height">2dp</dimen>
+ <integer name="default_title_indicator_footer_indicator_style">2</integer>
+ <dimen name="default_title_indicator_footer_indicator_height">4dp</dimen>
+ <dimen name="default_title_indicator_footer_indicator_underline_padding">20dp</dimen>
+ <dimen name="default_title_indicator_footer_padding">7dp</dimen>
+ <integer name="default_title_indicator_line_position">0</integer>
+ <color name="default_title_indicator_selected_color">#FFFFFFFF</color>
+ <bool name="default_title_indicator_selected_bold">true</bool>
+ <color name="default_title_indicator_text_color">#BBFFFFFF</color>
+ <dimen name="default_title_indicator_text_size">15dp</dimen>
+ <dimen name="default_title_indicator_title_padding">5dp</dimen>
+ <dimen name="default_title_indicator_top_padding">7dp</dimen>
+
+ <bool name="default_underline_indicator_fades">true</bool>
+ <integer name="default_underline_indicator_fade_delay">300</integer>
+ <integer name="default_underline_indicator_fade_length">400</integer>
+ <color name="default_underline_indicator_selected_color">#FF33B5E5</color>
+</resources> \ No newline at end of file
diff --git a/src/org/cyanogenmod/audiofx/ActivityMusic.java b/src/org/cyanogenmod/audiofx/ActivityMusic.java
deleted file mode 100644
index 883b127..0000000
--- a/src/org/cyanogenmod/audiofx/ActivityMusic.java
+++ /dev/null
@@ -1,789 +0,0 @@
-/*
- * Copyright (C) 2014 The CyanogenMod Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.cyanogenmod.audiofx;
-
-import android.app.ActionBar;
-import android.app.Activity;
-import android.content.*;
-import android.graphics.drawable.ColorDrawable;
-import android.media.audiofx.AudioEffect;
-import android.media.audiofx.AudioEffect.Descriptor;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.*;
-import android.widget.AdapterView.OnItemSelectedListener;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import org.cyanogenmod.audiofx.widget.EqualizerSurface;
-import org.cyanogenmod.audiofx.widget.Gallery;
-import org.cyanogenmod.audiofx.widget.InterceptableLinearLayout;
-import org.cyanogenmod.audiofx.widget.Knob;
-import org.cyanogenmod.audiofx.widget.Knob.OnKnobChangeListener;
-
-import java.util.UUID;
-
-/**
- *
- */
-public class ActivityMusic extends Activity {
-
- private final static String TAG = "AudioFXActivityMusic";
- private final static boolean DEBUG = false;
-
- /**
- * Max number of EQ bands supported
- */
- private final static int EQUALIZER_MAX_BANDS = 32;
-
- /**
- * Indicates if Virtualizer effect is supported.
- */
- private boolean mVirtualizerSupported;
- private boolean mVirtualizerIsHeadphoneOnly;
- /**
- * Indicates if BassBoost effect is supported.
- */
- private boolean mBassBoostSupported;
- /**
- * Indicates if Equalizer effect is supported.
- */
- private boolean mEqualizerSupported;
- /**
- * Indicates if Preset Reverb effect is supported.
- */
- private boolean mPresetReverbSupported;
- private ServiceConnection mServiceConnection;
-
- // Equalizer fields
- private int mNumberEqualizerBands;
- private int mEQCustomPresetPosition = 1;
- private int mEQPreset;
- private String[] mEQPresetNames;
- private String[] mReverbPresetNames;
-
- private int mPRPreset;
-
- private boolean mEQAnimatingToUserPos = false;
-
- private ViewGroup mContentEffectsViewGroup;
- private EqualizerSurface mEqualizerSurface;
- private Gallery mEqGallery;
- private Gallery mReverbGallery;
- private Knob mVirtualizerKnob;
- private Knob mBassKnob;
-
- private boolean mKnobsAvailable = false;
- private Switch mToggleSwitch;
-
- private boolean mStandalone = false;
- private boolean mStateChangeUpdate = false;
-
- private Toast mCurrentToast;
-
- HeadsetService mService;
-
- private String mCurrentDevice = "speaker"; // the sensible default
-
- private static final int[] mReverbPresetRSids = {
- R.string.none, R.string.smallroom, R.string.mediumroom, R.string.largeroom,
- R.string.mediumhall, R.string.largehall, R.string.plate
- };
-
- private Context mContext;
-
- private int mAudioSession = AudioEffect.ERROR_BAD_VALUE;
-
- private static final int MSG_UPDATE_EQ = 1;
- private static final int MSG_UPDATE_SERVICE = 2;
- private static final int MSG_UPDATE_EQ_ANIMATE = 3;
- Handler mHandler = new Handler() {
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case MSG_UPDATE_EQ:
- equalizerUpdateDisplayInternal(false);
- break;
- case MSG_UPDATE_SERVICE:
- if (mService != null) {
- mService.update();
- }
- break;
- case MSG_UPDATE_EQ_ANIMATE:
- equalizerUpdateDisplayInternal(true);
- break;
- }
- }
- };
-
- // Broadcast receiver to handle wired and Bluetooth A2dp headset events
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(final Context context, final Intent intent) {
- final String action = intent.getAction();
-
- if (action.equals(HeadsetService.ACTION_UPDATE_PREFERENCES)) {
- if (mCurrentDeviceOverride == false) { // the user has selected a device, don't interrupt them.
- if (mService != null) {
- mCurrentDevice = mService.getAudioOutputRouting();
- }
- }
-
- updateUI(true);
- mStateChangeUpdate = true;
- getActionBar().setSelectedNavigationItem(getCurrentDeviceIndex());
- equalizerSetPreset(mEQPreset);
- equalizerUpdateDisplay(true);
- }
- }
- };
- private ArrayAdapter<String> mNavBarDeviceAdapter;
-
- private boolean mCurrentDeviceOverride = false;
-
- @Override
- public void onCreate(final Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- startService(new Intent(this, HeadsetService.class));
-
- // Init context to be used in listeners
- mContext = this;
- // Receive intent
- // get calling intent
- final Intent intent = getIntent();
- mAudioSession = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION,
- AudioEffect.ERROR_BAD_VALUE);
- Log.v(TAG, "audio session: " + mAudioSession);
-
- // check for errors
- if (getCallingPackage() == null) {
- mStandalone = true;
- } else {
- mStandalone = false;
- }
- setResult(RESULT_OK);
-
- // query available effects
- final Descriptor[] effects = AudioEffect.queryEffects();
-
- // Determine available/supported effects
- if (DEBUG) Log.v(TAG, "Available effects:");
- for (final Descriptor effect : effects) {
- if (DEBUG) Log.v(TAG, effect.name.toString() + ", type: " + effect.type.toString());
-
- if (effect.type.equals(AudioEffect.EFFECT_TYPE_VIRTUALIZER)) {
- mVirtualizerSupported = true;
- if (effect.uuid.equals(UUID.fromString("1d4033c0-8557-11df-9f2d-0002a5d5c51b"))
- || effect.uuid.equals(UUID.fromString("e6c98a16-22a3-11e2-b87b-f23c91aec05e"))
- || effect.uuid.equals(UUID.fromString("d3467faa-acc7-4d34-acaf-0002a5d5c51b"))) {
- mVirtualizerIsHeadphoneOnly = true;
- }
- } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_BASS_BOOST)) {
- mBassBoostSupported = true;
- } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_EQUALIZER)) {
- mEqualizerSupported = true;
- } else if (effect.type.equals(AudioEffect.EFFECT_TYPE_PRESET_REVERB)) {
- mPresetReverbSupported = true;
- }
- }
-
- setContentView(R.layout.music_main);
-
- mContentEffectsViewGroup = (ViewGroup) findViewById(R.id.contentSoundEffects);
-
- // fix up labels
- TextView reverbLabel = (TextView) findViewById(R.id.reverb_label);
- reverbLabel.setText("- " + reverbLabel.getText() + " -");
-
- TextView eqPresetLabel = (TextView) findViewById(R.id.eq_preset_label);
- eqPresetLabel.setText("- " + eqPresetLabel.getText() + " -");
-
- // setup actionbar on off switch
- mToggleSwitch = new Switch(this);
- mToggleSwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(final CompoundButton buttonView,
- final boolean isChecked) {
- // set parameter and state
- getPrefs().edit().putBoolean("audiofx.global.enable", isChecked).apply();
-
- updateUI(true);
- setInterception(isChecked);
- updateService();
- }
- });
-
- // setup action bar
- String[] navigationBarDevices = new String[HeadsetService.DEFAULT_AUDIO_DEVICES.length];
- for (int i = 0; i < navigationBarDevices.length; i++) {
- navigationBarDevices[i] = localizeDevice(HeadsetService.DEFAULT_AUDIO_DEVICES[i]);
- }
-
- mNavBarDeviceAdapter = new ArrayAdapter<String>(getBaseContext(), android.R.layout.simple_spinner_dropdown_item,
- navigationBarDevices);
- ActionBar.OnNavigationListener navigationListener = new ActionBar.OnNavigationListener() {
- @Override
- public boolean onNavigationItemSelected(int itemPosition, long itemId) {
- if (mStateChangeUpdate) {
- mStateChangeUpdate = false;
- } else {
- mCurrentDeviceOverride = true;
- mCurrentDevice = HeadsetService.DEFAULT_AUDIO_DEVICES[itemPosition];
- }
- updateUI(true);
- equalizerSetPreset(mEQPreset);
- equalizerUpdateDisplay(true);
- mBassKnob.setValue(Integer.valueOf(getPrefs().getString("audiofx.bass.strength", "0")));
- mVirtualizerKnob.setValue(Integer.valueOf(getPrefs().getString("audiofx.virtualizer.strength", "0")));
- return true;
- }
- };
-
- ActionBar ab = getActionBar();
- final ActionBar.LayoutParams params = new ActionBar.LayoutParams(
- ActionBar.LayoutParams.WRAP_CONTENT,
- ActionBar.LayoutParams.WRAP_CONTENT,
- Gravity.CENTER_VERTICAL | Gravity.END);
-
- ab.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
- ab.setListNavigationCallbacks(mNavBarDeviceAdapter, navigationListener);
- ab.setBackgroundDrawable(new ColorDrawable(getResources()
- .getColor(R.color.action_bar_background)));
- mStateChangeUpdate = true;
- ab.setSelectedNavigationItem(getCurrentDeviceIndex());
-
- ab.setCustomView(mToggleSwitch, params);
- ab.setDisplayShowTitleEnabled(false);
- ab.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
-
- // initialize views
- mEqualizerSurface = (EqualizerSurface) findViewById(R.id.frequencyResponse);
- mEqGallery = (Gallery) findViewById(R.id.eqPresets);
- mReverbGallery = (Gallery) findViewById(R.id.reverb_gallery);
- mVirtualizerKnob = (Knob) findViewById(R.id.vIStrengthKnob);
- mBassKnob = (Knob) findViewById(R.id.bBStrengthKnob);
-
- // setup equalizer presets
- final int numPresets = Integer.parseInt(getSharedPreferences("global", 0)
- .getString("equalizer.number_of_presets", "0"));
- mEQPresetNames = new String[numPresets + 3];
-
- String[] presetNames = getSharedPreferences("global", 0).getString("equalizer.preset_names", "").split("\\|");
- for (short i = 0; i < numPresets; i++) {
- mEQPresetNames[i] = localizePresetName(presetNames[i]);
- }
- mEQPresetNames[numPresets] = getString(R.string.electronic);
- mEQPresetNames[numPresets + 1] = getString(R.string.small_speakers);
- mEQPresetNames[numPresets + 2] = getString(R.string.custom);
- mEQCustomPresetPosition = numPresets + 2;
-
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.equalizer_presets,
- mEQPresetNames);
-
- mEqGallery.setAdapter(adapter);
- mEqGallery.setSelection(mEQPreset);
- mEqGallery.setOnItemSelectedListener(new Gallery.OnItemSelectedListener() {
- @Override
- public void onItemSelected(int position) {
- mEQPreset = position;
- if (!mEQAnimatingToUserPos) {
- equalizerSetPreset(position);
- } else if (mEQAnimatingToUserPos && mEQPreset == mEQCustomPresetPosition) {
- mEQAnimatingToUserPos = false;
- }
- }
- });
-
- // setup equalizer
- mNumberEqualizerBands = Integer.parseInt(getSharedPreferences("global", 0)
- .getString("equalizer.number_of_bands", "5"));
- final int[] centerFreqs = getCenterFreqs();
- final int[] bandLevelRange = getBandLevelRange();
- float[] centerFreqsKHz = new float[centerFreqs.length];
- for (int i = 0; i < centerFreqs.length; i++) {
- centerFreqsKHz[i] = (float) centerFreqs[i] / 1000.0f;
- }
- mEqualizerSurface.setCenterFreqs(centerFreqsKHz);
- mEqualizerSurface.setBandLevelRange(bandLevelRange[0] / 100, bandLevelRange[1] / 100);
- final EqualizerSurface.BandUpdatedListener listener = new EqualizerSurface.BandUpdatedListener() {
-
- @Override
- public void onBandUpdated(int band, float dB) {
- if (mEQPreset != mEQCustomPresetPosition && !mEQAnimatingToUserPos) {
- equalizerCopyToCustom();
- mEQAnimatingToUserPos = true;
- mEqGallery.setAnimationDuration(1000);
- mEqGallery.setSelection(mEQCustomPresetPosition, true);
- } else {
- equalizerBandUpdate(band, (int) (dB * 100));
- }
- }
-
- float[] animatingLevels;
-
- @Override
- public void onBandAnimating(int band, float dB) {
- if (animatingLevels == null) {
- animatingLevels = mEqualizerSurface.softCopyLevels();
- }
- animatingLevels[band] = dB;
- if (mService != null) {
- mService.setEqualizerLevels(animatingLevels);
- }
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
-
- @Override
- public void onBandAnimationCompleted() {
- if (mService != null) {
- mService.setEqualizerLevels(animatingLevels = null);
- }
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- };
- mEqualizerSurface.registerBandUpdatedListener(listener);
-
- // setup virtualizer knob
- mVirtualizerKnob.setMax(OpenSLESConstants.VIRTUALIZER_MAX_STRENGTH -
- OpenSLESConstants.VIRTUALIZER_MIN_STRENGTH);
- mVirtualizerKnob.setOnKnobChangeListener(new OnKnobChangeListener() {
- // Update the parameters while Knob changes and set the
- // effect parameter.
- @Override
- public void onValueChanged(final Knob knob, final int value,
- final boolean fromUser) {
- if (fromUser) {
- // set parameter and state
- getPrefs().edit().putBoolean("audiofx.virtualizer.enable", true).apply();
- getPrefs().edit().putString("audiofx.virtualizer.strength", String.valueOf(value)).apply();
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
-
- @Override
- public boolean onSwitchChanged(final Knob knob, boolean on) {
- if (!mKnobsAvailable) {
- showHeadsetMsg();
- return false;
- }
-// knob.setOn(getPrefs().getBoolean("audiofx.virtualizer.enable", true));
-// knob.setOn(on);
- return true;
- }
-
- @Override
- public void onAnimationFinished(boolean endValue) {
- getPrefs().edit().putBoolean("audiofx.virtualizer.enable", endValue).apply();
-// updateService();
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- });
-
- // setup bass knob
- mBassKnob.setMax(OpenSLESConstants.BASSBOOST_MAX_STRENGTH
- - OpenSLESConstants.BASSBOOST_MIN_STRENGTH);
- mBassKnob.setOnKnobChangeListener(new OnKnobChangeListener() {
- // Update the parameters while SeekBar changes and set the
- // effect parameter.
- @Override
- public void onValueChanged(final Knob knob, final int value,
- final boolean fromUser) {
- if (fromUser) {
- // set parameter and state
- getPrefs().edit().putBoolean("audiofx.bass.enable", true).apply();
- getPrefs().edit().putString("audiofx.bass.strength", String.valueOf(value)).apply();
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- }
-
- @Override
- public boolean onSwitchChanged(final Knob knob, boolean on) {
- if (!mKnobsAvailable) {
- showHeadsetMsg();
- return false;
- }
-// knob.setOn(on);
- return true;
- }
-
- @Override
- public void onAnimationFinished(boolean endValue) {
- getPrefs().edit().putBoolean("audiofx.bass.enable", endValue).apply();
-// updateService();
- mHandler.sendEmptyMessage(MSG_UPDATE_SERVICE);
- }
- });
-
-
- // setup reverb presets
- mReverbPresetNames = new String[mReverbPresetRSids.length];
- for (short i = 0; i < mReverbPresetRSids.length; ++i) {
- mReverbPresetNames[i] = getString(mReverbPresetRSids[i]);
- }
-
- ArrayAdapter<String> reverbAdapter = new ArrayAdapter<String>(this,
- R.layout.equalizer_presets, mReverbPresetNames);
- mReverbGallery.setAdapter(reverbAdapter);
- mReverbGallery.setOnItemSelectedListener(new OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- if (position != mPRPreset) {
- presetReverbSetPreset(position);
- }
- mPRPreset = position;
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- mReverbGallery.setSelection(mPRPreset);
-
-
- }
-
- private SharedPreferences getPrefs() {
- return getSharedPreferences(mCurrentDevice, 0);
- }
-
- private final String localizePresetName(final String name) {
- final String[] names = {
- "Normal", "Classical", "Dance", "Flat", "Folk",
- "Heavy Metal", "Hip Hop", "Jazz", "Pop", "Rock"
- };
- final int[] ids = {
- R.string.normal, R.string.classical, R.string.dance, R.string.flat, R.string.folk,
- R.string.heavy_metal, R.string.hip_hop, R.string.jazz, R.string.pop, R.string.rock
- };
-
- for (int i = names.length - 1; i >= 0; --i) {
- if (names[i].equals(name)) {
- return getString(ids[i]);
- }
- }
- return name;
- }
-
- private final String localizeDevice(String device) {
- return getString(mContext.getResources().getIdentifier("device_" + device, "string", getPackageName()));
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- updateUI(false);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- if (mServiceConnection == null) {
- mServiceConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder binder) {
- mService = ((HeadsetService.LocalBinder) binder).getService();
- if (!mCurrentDeviceOverride) {
- mCurrentDevice = mService.getAudioOutputRouting();
- }
- updateUI(true);
-
- mStateChangeUpdate = true;
- getActionBar().setSelectedNavigationItem(getCurrentDeviceIndex());
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
- };
- }
- Intent serviceIntent = new Intent(this, HeadsetService.class);
- bindService(serviceIntent, mServiceConnection, 0);
-
- final IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(HeadsetService.ACTION_UPDATE_PREFERENCES);
- registerReceiver(mReceiver, intentFilter);
-
- equalizerUpdateDisplay(true);
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- // clear the toast
- if (mCurrentToast != null) {
- mCurrentToast.cancel();
- mCurrentToast = null;
- }
-
- unbindService(mServiceConnection);
-
- // Unregister for broadcast intents. (These affect the visible UI,
- // so we only care about them while we're in the foreground.)
- unregisterReceiver(mReceiver);
- }
-
- private void updateUI(boolean fromNavbar) {
- if (!fromNavbar) {
- mStateChangeUpdate = true;
- getActionBar().setSelectedNavigationItem(getCurrentDeviceIndex());
- }
-
- boolean isSpeaker = mCurrentDevice.equals("speaker");
-
- final boolean isEnabled = getPrefs().getBoolean("audiofx.global.enable", isSpeaker);
- mKnobsAvailable = !isSpeaker;
-
- mToggleSwitch.setChecked(isEnabled);
-
- if (mVirtualizerSupported) {
- mVirtualizerKnob.setOn(getPrefs().getBoolean("audiofx.virtualizer.enable", false), false);
- mVirtualizerKnob.setEnabled(isEnabled && mKnobsAvailable);
- } else {
- mVirtualizerKnob.setVisibility(View.GONE);
- }
- if (mBassBoostSupported) {
- mBassKnob.setOn(getPrefs().getBoolean("audiofx.bass.enable", true), false);
- mBassKnob.setEnabled(isEnabled && mKnobsAvailable);
- } else {
- mBassKnob.setVisibility(View.GONE);
- }
- if (mEqualizerSupported) {
- String preset;
- if (isSpeaker) {
- preset = String.valueOf(mNumberEqualizerBands + 2);
- } else {
- preset = "3";
- }
- mEQPreset = Integer.valueOf(getPrefs().getString("audiofx.eq.preset", preset));
- mEqGallery.setEnabled(isEnabled);
- mEqGallery.setSelection(mEQPreset);
- }
- if (mPresetReverbSupported) {
- mPRPreset = Integer.valueOf(getPrefs().getString("audiofx.reverb.preset", "0"));
- mReverbGallery.setSelection(mPRPreset, true);
- mReverbGallery.setEnabled(isEnabled);
- }
-
- setInterception(isEnabled);
- }
-
- private void updateUI() {
- updateUI(false);
- }
-
- private int getCurrentDeviceIndex() {
- for (int i = 0; i < HeadsetService.DEFAULT_AUDIO_DEVICES.length; i++) {
- if (HeadsetService.DEFAULT_AUDIO_DEVICES[i].equals(mCurrentDevice)) {
- return i;
- }
- }
- return 0;
- }
-
- private void setInterception(boolean isEnabled) {
- final InterceptableLinearLayout ill =
- (InterceptableLinearLayout) findViewById(R.id.contentSoundEffects);
- ill.setInterception(!isEnabled);
- if (isEnabled) {
- ill.setOnClickListener(null);
- } else {
- ill.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // clear the toast
- if (mCurrentToast != null) {
- mCurrentToast.cancel();
- mCurrentToast = null;
- }
- mCurrentToast = Toast.makeText(mContext,
- getString(R.string.power_on_prompt), Toast.LENGTH_SHORT);
- mCurrentToast.setGravity(Gravity.CENTER, 0, 0);
- mCurrentToast.show();
- }
- });
- }
- }
-
- private int[] getBandLevelRange() {
- String savedCenterFreqs = getSharedPreferences("global", 0).getString("equalizer.band_level_range", null);
- if (savedCenterFreqs == null || savedCenterFreqs.isEmpty()) {
- return new int[]{-1500, 1500};
- } else {
- String[] split = savedCenterFreqs.split(";");
- int[] freqs = new int[split.length];
- for (int i = 0; i < split.length; i++) {
- freqs[i] = Integer.valueOf(split[i]);
- }
- return freqs;
- }
- }
-
- private int[] getCenterFreqs() {
- String savedCenterFreqs = getSharedPreferences("global", 0).getString("equalizer.center_freqs",
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands));
- String[] split = savedCenterFreqs.split(";");
- int[] freqs = new int[split.length];
- for (int i = 0; i < split.length; i++) {
- freqs[i] = Integer.valueOf(split[i]);
- }
- return freqs;
- }
-
- /**
- * Updates the EQ by getting the parameters.
- */
- private void equalizerUpdateDisplay(boolean animate) {
- mHandler.removeMessages(animate ? MSG_UPDATE_EQ_ANIMATE : MSG_UPDATE_EQ);
- mHandler.sendEmptyMessageDelayed(animate ? MSG_UPDATE_EQ_ANIMATE : MSG_UPDATE_EQ, 100);
- }
-
- private void equalizerUpdateDisplayInternal(boolean animate) {
- String levelsString = null;
- float[] floats;
-
- if (mEQPreset == mEQCustomPresetPosition) {
- // load custom preset for current device
- // here mEQValues needs to be pre-populated with the user's preset values.
- String[] customEq = getPrefs().getString("audiofx.eq.bandlevels.custom",
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands)).split(";");
- floats = new float[mNumberEqualizerBands];
- for (int band = 0; band < floats.length; band++) {
- final float level = Float.parseFloat(customEq[band]);
- floats[band] = level / 100.0f;
- }
- if (animate) {
- mEqualizerSurface.setBands(floats);
- } else {
- for (int band = 0; band < mNumberEqualizerBands; band++) {
- mEqualizerSurface.setBand(band, (float) floats[band] / 100.0f);
- }
- }
- } else {
- // try to load preset
- levelsString = getSharedPreferences("global", 0).getString("equalizer.preset." + mEQPreset,
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands));
- String[] bandLevels = levelsString.split(";");
- floats = new float[bandLevels.length];
- for (int band = 0; band < bandLevels.length; band++) {
- final float level = Float.parseFloat(bandLevels[band]);
- floats[band] = level / 100.0f;
- if (!animate) {
- mEqualizerSurface.setBand(band, (float) level / 100.0f);
- }
- }
- if (animate) {
- mEqualizerSurface.setBands(floats);
- }
- }
- }
-
- /**
- * Called when user starts touch eq on a preset
- */
- private void equalizerCopyToCustom() {
- if (DEBUG) Log.d(TAG, "equalizerCopyToCustom()");
- StringBuilder bandLevels = new StringBuilder();
- for (int band = 0; band < mNumberEqualizerBands; band++) {
- final float level = mEqualizerSurface.getBand(band);
- bandLevels.append(level * 100);
- bandLevels.append(";");
- }
- // remove trailing ";"
- bandLevels.deleteCharAt(bandLevels.length() - 1);
- getPrefs().edit().putString("audiofx.eq.bandlevels.custom", bandLevels.toString()).apply();
- getPrefs().edit().putString("audiofx.eq.preset", String.valueOf(mEQCustomPresetPosition)).apply();
- }
-
- private void equalizerBandUpdate(final int band, final int level) {
- if (DEBUG) Log.d(TAG, "equalizerBandUpdate(band: " + band + ", level: " + level + ")");
-
- String[] currentCustomLevels = getPrefs().getString("audiofx.eq.bandlevels.custom",
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands)).split(";");
-
- currentCustomLevels[band] = String.valueOf(level);
- // save
- StringBuilder builder = new StringBuilder();
- for (int i = 0; i < mNumberEqualizerBands; i++) {
- builder.append(currentCustomLevels[i]);
- builder.append(";");
- }
- builder.deleteCharAt(builder.length() - 1);
- getPrefs().edit().putString("audiofx.eq.bandlevels", builder.toString()).apply();
- getPrefs().edit().putString("audiofx.eq.bandlevels.custom", builder.toString()).apply();
-
- updateService();
- }
-
- private void updateService() {
- mHandler.removeMessages(MSG_UPDATE_SERVICE);
- mHandler.sendEmptyMessageDelayed(MSG_UPDATE_SERVICE, 100);
- }
-
- private void equalizerSetPreset(final int preset) {
- if (DEBUG) Log.d(TAG, "equalizerSetPreset(" + preset + ")");
-
- mEQPreset = preset;
- getPrefs().edit().putString("audiofx.eq.preset", String.valueOf(preset)).apply();
-
- String newLevels = null;
- if (preset == mEQCustomPresetPosition) {
- // load custom if possible
- newLevels = getPrefs().getString("audiofx.eq.bandlevels.custom",
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands));
- } else {
- newLevels = getSharedPreferences("global", 0).getString("equalizer.preset." + preset,
- HeadsetService.getZeroedBandsString(mNumberEqualizerBands));
- }
- getPrefs().edit().putString("audiofx.eq.bandlevels", newLevels).apply();
- equalizerUpdateDisplay(true);
-
- updateService();
- }
-
-
- private void presetReverbSetPreset(final int preset) {
- getPrefs().edit().putString("audiofx.reverb.preset", String.valueOf(preset)).apply();
- updateService();
- }
-
- private void showHeadsetMsg() {
- // clear the toast
- if (mCurrentToast != null) {
- mCurrentToast.cancel();
- mCurrentToast = null;
- }
-
- final Context context = getApplicationContext();
- final int duration = Toast.LENGTH_SHORT;
-
- mCurrentToast = Toast.makeText(context, getString(R.string.effect_unavalable_for_speaker), duration);
- mCurrentToast.setGravity(Gravity.CENTER, mCurrentToast.getXOffset() / 2, mCurrentToast.getYOffset() / 2);
- mCurrentToast.show();
- }
-
-}
diff --git a/src/org/cyanogenmod/audiofx/BootReceiver.java b/src/org/cyanogenmod/audiofx/BootReceiver.java
deleted file mode 100644
index b032310..0000000
--- a/src/org/cyanogenmod/audiofx/BootReceiver.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.cyanogenmod.audiofx;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-
-/**
- * Created by roman on 5/12/14.
- */
-public class BootReceiver extends BroadcastReceiver {
- public void onReceive(Context context, Intent intent) {
- context.startService(new Intent(context, HeadsetService.class));
- }
-}
diff --git a/src/org/cyanogenmod/audiofx/HeadsetService.java b/src/org/cyanogenmod/audiofx/HeadsetService.java
deleted file mode 100644
index 98bf20e..0000000
--- a/src/org/cyanogenmod/audiofx/HeadsetService.java
+++ /dev/null
@@ -1,708 +0,0 @@
-/*
- * Copyright (C) 2014 The CyanogenMod Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.cyanogenmod.audiofx;
-
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.media.AudioManager;
-import android.media.AudioPatch;
-import android.media.AudioPort;
-import android.media.AudioSystem;
-import android.media.audiofx.AudioEffect;
-import android.media.audiofx.BassBoost;
-import android.media.audiofx.Equalizer;
-import android.media.audiofx.PresetReverb;
-import android.media.audiofx.Virtualizer;
-import android.os.Binder;
-import android.os.IBinder;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.Arrays;
-
-import cyanogenmod.media.AudioSessionInfo;
-import cyanogenmod.media.CMAudioManager;
-
-/**
- * <p>This calls listen to events that affect DSP function and responds to them.</p>
- * <ol>
- * <li>new audio session declarations</li>
- * <li>headset plug / unplug events</li>
- * <li>preference update events.</li>
- * </ol>
- *
- * @author alankila
- */
-public class HeadsetService extends Service {
-
- public static final String ACTION_UPDATE_PREFERENCES = "org.cyanogenmod.audiofx.UPDATE_PREFS";
- public static final String[] DEFAULT_AUDIO_DEVICES = new String[]{
- "headset", "speaker", "usb", "bluetooth", "wireless", "lineout"
- };
-
- static String getZeroedBandsString(int length) {
- StringBuffer buff = new StringBuffer();
- for (int i = 0; i < length; i++) {
- buff.append("0;");
- }
- buff.deleteCharAt(buff.length() - 1);
- return buff.toString();
- }
-
- /**
- * Helper class representing the full complement of effects attached to one
- * audio session.
- *
- * @author alankila
- */
- private static class EffectSet {
- /**
- * Session-specific equalizer
- */
- private final Equalizer mEqualizer;
- /**
- * Session-specific bassboost
- */
- private final BassBoost mBassBoost;
- /**
- * Session-specific virtualizer
- */
- private final Virtualizer mVirtualizer;
-
- private final PresetReverb mPresetReverb;
-
- private short mEqNumPresets = -1;
- private short mEqNumBands = -1;
-
- public EffectSet(int sessionId) {
- mEqualizer = new Equalizer(0, sessionId);
- mBassBoost = new BassBoost(0, sessionId);
- mVirtualizer = new Virtualizer(0, sessionId);
- mPresetReverb = new PresetReverb(0, sessionId);
- }
-
- /*
- * Take lots of care to not poke values that don't need
- * to be poked- this can cause audible pops.
- */
-
- public void enableEqualizer(boolean enable) {
- if (enable != mEqualizer.getEnabled()) {
- if (!enable) {
- for (short i = 0; i < getNumEqualizerBands(); i++) {
- mEqualizer.setBandLevel(i, (short) 0);
- }
- }
- mEqualizer.setEnabled(enable);
- }
- }
-
- public void setEqualizerLevels(short[] levels) {
- if (mEqualizer.getEnabled()) {
- for (short i = 0; i < levels.length; i++) {
- if (mEqualizer.getBandLevel(i) != levels[i]) {
- mEqualizer.setBandLevel(i, levels[i]);
- }
- }
- }
- }
-
- public short getNumEqualizerBands() {
- if (mEqNumBands < 0) {
- mEqNumBands = mEqualizer.getNumberOfBands();
- }
- return mEqNumBands;
- }
-
- public short getNumEqualizerPresets() {
- if (mEqNumPresets < 0) {
- mEqNumPresets = mEqualizer.getNumberOfPresets();
- }
- return mEqNumPresets;
- }
-
- public void enableBassBoost(boolean enable) {
- if (enable != mBassBoost.getEnabled()) {
- if (!enable) {
- mBassBoost.setStrength((short) 1);
- mBassBoost.setStrength((short) 0);
- }
- mBassBoost.setEnabled(enable);
- }
- }
-
- public void setBassBoostStrength(short strength) {
- if (mBassBoost.getEnabled() && mBassBoost.getRoundedStrength() != strength) {
- mBassBoost.setStrength(strength);
- }
- }
-
- public void enableVirtualizer(boolean enable) {
- if (enable != mVirtualizer.getEnabled()) {
- if (!enable) {
- mVirtualizer.setStrength((short) 1);
- mVirtualizer.setStrength((short) 0);
- }
- mVirtualizer.setEnabled(enable);
- }
- }
-
- public void setVirtualizerStrength(short strength) {
- if (mVirtualizer.getEnabled() && mVirtualizer.getRoundedStrength() != strength) {
- mVirtualizer.setStrength(strength);
- }
- }
-
- public void enableReverb(boolean enable) {
- if (enable != mPresetReverb.getEnabled()) {
- if (!enable) {
- mPresetReverb.setPreset((short) 0);
- }
- mPresetReverb.setEnabled(enable);
- }
- }
-
- public void setReverbPreset(short preset) {
- if (mPresetReverb.getEnabled() && mPresetReverb.getPreset() != preset) {
- mPresetReverb.setPreset(preset);
- }
- }
-
- public void release() {
- mEqualizer.release();
- mBassBoost.release();
- mVirtualizer.release();
- mPresetReverb.release();
- }
- }
-
- protected static final String TAG = HeadsetService.class.getSimpleName();
- public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-
-
- private void addSession(int sessionId) {
- if (sessionId == 0) {
- return;
- }
- if (DEBUG) Log.i(TAG, String.format("New audio session: %d", sessionId));
-
- synchronized (mAudioSessionsL) {
- if (mAudioSessionsL.indexOfKey(sessionId) < 0) {
- mAudioSessionsL.put(sessionId, new EffectSet(sessionId));
- }
- updateLocked();
- }
- }
-
- private void removeSession(int sessionId) {
- if (sessionId == 0) {
- return;
- }
- if (DEBUG) Log.i(TAG, String.format("Audio session removed: %d", sessionId));
-
- synchronized (mAudioSessionsL) {
- EffectSet gone = mAudioSessionsL.removeReturnOld(sessionId);
- if (gone != null) {
- gone.release();
- }
- }
- }
-
- public void addSession(AudioSessionInfo info) {
- if (info.getStream() == AudioManager.STREAM_MUSIC &&
- (info.getFlags() < 0 || (info.getFlags() & 0x8) > 0 || (info.getFlags() & 0x10) > 0) &&
- (info.getChannelMask() < 0 || info.getChannelMask() > 1)) {
-
- // Never auto-attach is someone is recording! We don't want to
- // interfere with any sort of
- // loopback mechanisms.
- final boolean recording = AudioSystem.isSourceActive(0)
- || AudioSystem.isSourceActive(6);
- if (recording) {
- Log.w(TAG, "Recording in progress, not performing auto-attach!");
- return;
- }
- addSession(info.getSessionId());
- }
- }
-
- public void removeSession(AudioSessionInfo info) {
- if (info.getStream() == AudioManager.STREAM_MUSIC) {
- removeSession(info.getSessionId());
- }
- }
-
- public class LocalBinder extends Binder {
- public HeadsetService getService() {
- return HeadsetService.this;
- }
- }
-
- private final LocalBinder mBinder = new LocalBinder();
-
- /**
- * Known audio sessions and their associated audioeffect suites.
- */
- private final SparseArray<EffectSet> mAudioSessionsL = new SparseArray<EffectSet>();
-
- AudioPortListener mAudioPortListener;
-
- /**
- * Has DSPManager assumed control of equalizer levels?
- */
- private float[] mOverriddenEqualizerLevels;
-
- /**
- * Update audio parameters when preferences have been updated.
- */
- private final BroadcastReceiver mPreferenceUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.i(TAG, "Preferences updated.");
- update();
- }
- };
-
- private class AudioPortListener implements AudioManager.OnAudioPortUpdateListener {
- private boolean mUseBluetooth;
- private boolean mUseHeadset;
- private boolean mUseUSB;
- private boolean mUseWifiDisplay;
- private boolean mUseSpeaker;
- private boolean mUseLineOut;
-
- private final Context mContext;
-
- public AudioPortListener(Context context) {
- mContext = context;
- }
-
- @Override
- public void onAudioPortListUpdate(AudioPort[] portList) {
- final boolean prevUseHeadset = mUseHeadset;
- final boolean prevUseBluetooth = mUseBluetooth;
- final boolean prevUseUSB = mUseUSB;
- final boolean prevUseWireless = mUseWifiDisplay;
- final boolean prevUseSpeaker = mUseSpeaker;
- final boolean prevUseLineOut = mUseLineOut;
-
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- int device = am.getDevicesForStream(AudioManager.STREAM_MUSIC);
- mUseBluetooth = (device & AudioManager.DEVICE_OUT_BLUETOOTH_A2DP) != 0
- || (device & AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) != 0
- || (device & AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER) != 0
- || (device & AudioManager.DEVICE_OUT_BLUETOOTH_SCO) != 0
- || (device & AudioManager.DEVICE_OUT_BLUETOOTH_SCO_CARKIT) != 0
- || (device & AudioManager.DEVICE_OUT_BLUETOOTH_SCO_HEADSET) != 0;
-
- mUseHeadset = (device & AudioManager.DEVICE_OUT_WIRED_HEADPHONE) != 0
- || (device & AudioManager.DEVICE_OUT_WIRED_HEADSET) != 0;
-
- mUseLineOut = (device & AudioManager.DEVICE_OUT_LINE) != 0;
-
- mUseUSB = (device & AudioManager.DEVICE_OUT_USB_ACCESSORY) != 0
- || (device & AudioManager.DEVICE_OUT_USB_DEVICE) != 0;
-
- mUseWifiDisplay = false; //TODO add support for wireless display..
-
- mUseSpeaker = (device & AudioManager.DEVICE_OUT_SPEAKER) != 0;
-
- Log.i(TAG, "Headset=" + mUseHeadset + "; Bluetooth="
- + mUseBluetooth + " ; USB=" + mUseUSB + "; Speaker=" + mUseSpeaker +
- "; Line out=" + mUseLineOut);
-
- if (prevUseHeadset != mUseHeadset
- || prevUseBluetooth != mUseBluetooth
- || prevUseUSB != mUseUSB
- || prevUseWireless != mUseWifiDisplay
- || prevUseSpeaker != mUseSpeaker
- || prevUseLineOut != mUseLineOut) {
-
- update();
-
- Intent i = new Intent(ACTION_UPDATE_PREFERENCES);
- mContext.sendBroadcast(i);
- }
- }
-
- @Override
- public void onAudioPatchListUpdate(AudioPatch[] patchList) {
-
- }
-
- @Override
- public void onServiceDied() {
-
- }
-
- public String getInternalAudioOutputRouting() {
- if (mUseSpeaker) {
- return "speaker";
- }
- if (mUseBluetooth) {
- return "bluetooth";
- }
- if (mUseHeadset) {
- return "headset";
- }
- if (mUseUSB) {
- return "usb";
- }
- if (mUseWifiDisplay) {
- return "wireless";
- }
- if (mUseLineOut) {
- return "lineout";
- }
- return "speaker";
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.i(TAG, "Starting service.");
-
- registerReceiver(mPreferenceUpdateReceiver,
- new IntentFilter(ACTION_UPDATE_PREFERENCES));
-
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- am.registerAudioPortUpdateListener(mAudioPortListener = new AudioPortListener(this));
-
- saveDefaults();
- }
-
-
- /**
- * maps {@link AudioEffect#EXTRA_CONTENT_TYPE} to an AudioManager.STREAM_* item
- */
- private static int mapContentTypeToStream(int contentType) {
- switch (contentType) {
- case AudioEffect.CONTENT_TYPE_VOICE:
- return AudioManager.STREAM_VOICE_CALL;
- case AudioEffect.CONTENT_TYPE_GAME:
- // explicitly don't support game effects right now
- return -1;
- case AudioEffect.CONTENT_TYPE_MOVIE:
- case AudioEffect.CONTENT_TYPE_MUSIC:
- default:
- return AudioManager.STREAM_MUSIC;
- }
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (intent != null && intent.getAction() != null) {
- if (DEBUG) {
- Log.i(TAG, "onStartCommand() called with " + "intent = [" + intent + "], flags = ["
- + flags + "], startId = [" + startId + "], extras = [" +
- (intent.getExtras() == null ? "null" : intent.getExtras().toString())
- + "]");
- }
- String action = intent.getAction();
- int sessionId = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION, 0);
- String pkg = intent.getStringExtra(AudioEffect.EXTRA_PACKAGE_NAME);
- int stream = mapContentTypeToStream(
- intent.getIntExtra(AudioEffect.EXTRA_CONTENT_TYPE,
- AudioEffect.CONTENT_TYPE_MUSIC));
-
- if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)) {
- if (DEBUG) {
- Log.i(TAG, String.format("New audio session: %d package: %s contentType=%d",
- sessionId, pkg, stream));
- }
- addSession(sessionId);
-
- } else if (action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
-
- removeSession(sessionId);
-
- } else if (action.equals(CMAudioManager.ACTION_AUDIO_SESSIONS_CHANGED)) {
-
- final AudioSessionInfo info = (AudioSessionInfo) intent.getParcelableExtra(
- CMAudioManager.EXTRA_SESSION_INFO);
- if (info != null && info.getSessionId() > 0) {
- boolean added = intent.getBooleanExtra(CMAudioManager.EXTRA_SESSION_ADDED,
- false);
- if (added) {
- addSession(info);
- } else {
- removeSession(info);
- }
- }
- }
- }
- return START_STICKY;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- Log.i(TAG, "Stopping service.");
-
- unregisterReceiver(mPreferenceUpdateReceiver);
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return mBinder;
- }
-
- /**
- * Gain temporary control over the global equalizer.
- * Used by DSPManager when testing a new equalizer setting.
- *
- * @param levels
- */
- public void setEqualizerLevels(float[] levels) {
- mOverriddenEqualizerLevels = levels;
- update();
- }
-
- /**
- * There appears to be no way to find out what the current actual audio routing is.
- * For instance, if a wired headset is plugged in, the following objects/classes are involved:
- * </p>
- * <ol>
- * <li>wiredaccessoryobserver</li>
- * <li>audioservice</li>
- * <li>audiosystem</li>
- * <li>audiopolicyservice</li>
- * <li>audiopolicymanager</li>
- * </ol>
- * <p>Once the decision of new routing has been made by the policy manager, it is relayed to
- * audiopolicyservice, which waits for some time to let application buffers drain, and then
- * informs it to hardware. The full chain is:</p>
- * <ol>
- * <li>audiopolicymanager</li>
- * <li>audiopolicyservice</li>
- * <li>audiosystem</li>
- * <li>audioflinger</li>
- * <li>audioeffect (if any)</li>
- * </ol>
- * <p>However, the decision does not appear to be relayed to java layer, so we must
- * make a guess about what the audio output routing is.</p>
- *
- * @return string token that identifies configuration to use
- */
- public String getAudioOutputRouting() {
- if (mAudioPortListener != null) {
- return mAudioPortListener.getInternalAudioOutputRouting();
- }
- return "speaker";
- }
-
- public EffectSet getEffects(int session) {
- synchronized (mAudioSessionsL) {
- return mAudioSessionsL.get(session);
- }
- }
-
- private void saveDefaults() {
- EffectSet temp;
- try {
- temp = new EffectSet(0);
- } catch (Exception e) {
- // this is really bad- likely the media stack is broken.
- // disable ourself if we get into this state, as the service
- // will restart itself repeatedly!
- Log.e(TAG, e.getMessage(), e);
- stopSelf();
- return;
- }
-
- SharedPreferences prefs = getSharedPreferences("global", 0);
-
- final int numBands = temp.getNumEqualizerBands();
- final int numPresets = temp.getNumEqualizerPresets();
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString("equalizer.number_of_presets", String.valueOf(numPresets)).apply();
- editor.putString("equalizer.number_of_bands", String.valueOf(numBands)).apply();
-
- // range
- short[] rangeShortArr = temp.mEqualizer.getBandLevelRange();
-
-
- editor.putString("equalizer.band_level_range", rangeShortArr[0] + ";" + rangeShortArr[1]).apply();
-
- // center freqs
- StringBuilder centerFreqs = new StringBuilder();
- // audiofx.global.centerfreqs
- for (short i = 0; i < numBands; i++) {
- centerFreqs.append(temp.mEqualizer.getCenterFreq(i));
- centerFreqs.append(";");
-
- }
- centerFreqs.deleteCharAt(centerFreqs.length() - 1);
- editor.putString("equalizer.center_freqs", centerFreqs.toString()).apply();
-
- // populate preset names
- StringBuilder presetNames = new StringBuilder();
- for (int i = 0; i < numPresets; i++) {
- String presetName = temp.mEqualizer.getPresetName((short) i);
- presetNames.append(presetName);
- presetNames.append("|");
-
- // populate preset band values
- StringBuilder presetBands = new StringBuilder();
- temp.mEqualizer.usePreset((short) i);
-
- for (int j = 0; j < numBands; j++) {
- // loop through preset bands
- presetBands.append(temp.mEqualizer.getBandLevel((short) j));
- presetBands.append(";");
- }
- presetBands.deleteCharAt(presetBands.length() - 1);
- editor.putString("equalizer.preset." + i, presetBands.toString()).apply();
- }
- presetNames.deleteCharAt(presetNames.length() - 1);
- editor.putString("equalizer.preset_names", presetNames.toString()).apply();
- temp.release();
-
- // add ci-extreme
- StringBuilder ciExtremeBuilder = new StringBuilder("0;800;400;100;1000");
- if (numBands > 5) {
- int extraBands = numBands - 5;
- for (int i = 0; i < extraBands; i++) {
- ciExtremeBuilder.insert(0, "0;");
- }
- }
- editor.putString("equalizer.preset." + numPresets, ciExtremeBuilder.toString()).apply();
-
- // add small-speaker
- StringBuilder ssBuilder = new StringBuilder("-170;270;50;-220;200");
- if (numBands > 5) {
- int extraBands = numBands - 5;
- for (int i = 0; i < extraBands; i++) {
- ssBuilder.insert(0, "0;");
- }
- }
- editor.putString("equalizer.preset." + (numPresets + 1), ssBuilder.toString()).apply();
- editor.commit();
-
- // Enable for the speaker by default
- if (!getSharedPrefsFile("speaker").exists()) {
- SharedPreferences spk = getSharedPreferences("speaker", 0);
- spk.edit().putBoolean("audiofx.global.enable", true).apply();
- spk.edit().putString("audiofx.eq.preset", String.valueOf(numPresets + 1)).apply();
- }
- }
-
- /**
- * Push new configuration to audio stack.
- */
- void update() {
- synchronized (mAudioSessionsL) {
- updateLocked();
- }
- }
-
- private void updateLocked() {
- final String mode = getAudioOutputRouting();
- SharedPreferences preferences = getSharedPreferences(
- mode, 0);
-
- if (DEBUG) Log.i(TAG, "Selected configuration: " + mode);
-
- for (int i = 0; i < mAudioSessionsL.size(); i++) {
- updateDsp(preferences, mAudioSessionsL.valueAt(i));
- }
- }
-
- private void updateDsp(SharedPreferences prefs, EffectSet session) {
- final boolean globalEnabled = prefs.getBoolean("audiofx.global.enable", false);
-
- try {
- session.enableBassBoost(globalEnabled && prefs.getBoolean("audiofx.bass.enable", false));
- session.setBassBoostStrength(Short.valueOf(prefs
- .getString("audiofx.bass.strength", "0")));
-
- } catch (Exception e) {
- Log.e(TAG, "Error enabling bass boost!", e);
- }
-
- try {
- short preset = Short.decode(prefs.getString("audiofx.reverb.preset",
- String.valueOf(PresetReverb.PRESET_NONE)));
- session.enableReverb(globalEnabled && (preset > 0));
- session.setReverbPreset(preset);
-
- } catch (Exception e) {
- Log.e(TAG, "Error enabling reverb preset", e);
- }
-
- try {
- session.enableEqualizer(globalEnabled);
- final int customPresetPos = session.getNumEqualizerPresets() + 2;
- final int preset = Integer.valueOf(prefs.getString("audiofx.eq.preset",
- String.valueOf(customPresetPos)));
- final int bands = session.getNumEqualizerBands();
-
- /*
- * Equalizer state is in a single string preference with all values
- * separated by ;
- */
- String[] levels = null;
- short[] equalizerLevels = null;
-
- if (mOverriddenEqualizerLevels != null) {
-
- } else if (preset == customPresetPos) {
- if (DEBUG) Log.i(TAG, "loading custom band levels");
- levels = prefs.getString("audiofx.eq.bandlevels.custom",
- getZeroedBandsString(bands)).split(";");
- } else {
- if (DEBUG) Log.i(TAG, "loading preset band levels");
- levels = getSharedPreferences("global", 0).getString("equalizer.preset." + preset,
- getZeroedBandsString(bands)).split(";");
- }
-
- if (levels != null) {
- if (DEBUG) Log.i(TAG, "band levels applied: " + Arrays.toString(levels));
- equalizerLevels = new short[levels.length];
- for (int i = 0; i < levels.length; i++) {
- equalizerLevels[i] = (short) (Float.parseFloat(levels[i]));
- }
- } else if (mOverriddenEqualizerLevels != null) {
- equalizerLevels = new short[mOverriddenEqualizerLevels.length];
- for (int i = 0; i < mOverriddenEqualizerLevels.length; i++) {
- equalizerLevels[i] = (short) mOverriddenEqualizerLevels[i];
- }
- }
- if (equalizerLevels != null) {
- session.setEqualizerLevels(equalizerLevels);
- }
-
-
- } catch (Exception e) {
- Log.e(TAG, "Error enabling equalizer!", e);
- }
-
- try {
- session.enableVirtualizer(globalEnabled
- && prefs.getBoolean("audiofx.virtualizer.enable", false));
- session.setVirtualizerStrength(Short.valueOf(prefs.getString(
- "audiofx.virtualizer.strength", "0")));
-
- } catch (Exception e) {
- Log.e(TAG, "Error enabling virtualizer!");
- }
- }
-}
diff --git a/src/org/cyanogenmod/audiofx/OpenSLESConstants.java b/src/org/cyanogenmod/audiofx/OpenSLESConstants.java
deleted file mode 100644
index 2131b55..0000000
--- a/src/org/cyanogenmod/audiofx/OpenSLESConstants.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2010-2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.cyanogenmod.audiofx;
-
-/**
- * OpenSL ES constants class
- */
-public final class OpenSLESConstants {
- private OpenSLESConstants() {
- // Empty constructor
- }
-
- /**
- * Minimum volume level in millibel (mb).
- */
- public static final short SL_MILLIBEL_MIN = -9600;
- /**
- * This value is used when equalizer setting is not defined.
- */
- public static final short SL_EQUALIZER_UNDEFINED = (short) 0xFFFF;
-
- /**
- * The minimum bass boost strength in o/oo.
- */
- public static final short BASSBOOST_MIN_STRENGTH = 0;
- /**
- * The maximum bass boost strength in o/oo.
- */
- public static final short BASSBOOST_MAX_STRENGTH = 1000;
-
- /**
- * The minimum reverb room level in mb.
- */
- public static final short REVERB_MIN_ROOM_LEVEL = SL_MILLIBEL_MIN;
- /**
- * The maximum reverb room level in mb.
- */
- public static final short REVERB_MAX_ROOM_LEVEL = 0;
- /**
- * The minimum reverb room HF level in mb.
- */
- public static final short REVERB_MIN_ROOM_HF_LEVEL = SL_MILLIBEL_MIN;
- /**
- * The maximum reverb room HF level in mb.
- */
- public static final short REVERB_MAX_ROOM_HF_LEVEL = 0;
- /**
- * The minimum reverb decay time in ms.
- */
- public static final short REVERB_MIN_DECAY_TIME = 100;
- /**
- * The maximum reverb decay time in ms.
- */
- // XXX: OpenSL ES is normally 20000 but can only support 7000 for now
- public static final short REVERB_MAX_DECAY_TIME = 7000;
- /**
- * The minimum reverb decay HF ratio in o/oo.
- */
- public static final short REVERB_MIN_DECAY_HF_RATIO = 100;
- /**
- * The maximum reverb decay HF ratio in o/oo.
- */
- public static final short REVERB_MAX_DECAY_HF_RATIO = 2000;
- /**
- * The minimum reverb level in mb.
- */
- public static final short REVERB_MIN_REVERB_LEVEL = SL_MILLIBEL_MIN;
- /**
- * The maximum reverb level in mb.
- */
- public static final short REVERB_MAX_REVERB_LEVEL = 2000;
- /**
- * The minimum reverb diffusion in o/oo.
- */
- public static final short REVERB_MIN_DIFFUSION = 0;
- /**
- * The maximum reverb diffusion in o/oo.
- */
- public static final short REVERB_MAX_DIFFUSION = 1000;
- /**
- * The minimum reverb density in o/oo.
- */
- public static final short REVERB_MIN_DENSITY = 0;
- /**
- * The maximum reverb density in o/oo.
- */
- public static final short REVERB_MAX_DENSITY = 1000;
-
- /**
- * The minimum virtualizer strength in o/oo.
- */
- public static final short VIRTUALIZER_MIN_STRENGTH = 0;
- /**
- * The maximum virtualizer strength in o/oo.
- */
- public static final short VIRTUALIZER_MAX_STRENGTH = 1000;
-
- /**
- * The minimum volume effect level in millibel (mb).
- */
- public static final short VOLUME_MIN_LEVEL = SL_MILLIBEL_MIN;
- /**
- * The minimum volume stereo position in o/oo.
- */
- public static final short VOLUME_MIN_STEREO_POSITION = -1000;
- /**
- * The maximum volume stereo position in o/oo.
- */
- public static final short VOLUME_MAX_STEREO_POSITION = 1000;
-}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/AudioFxApplication.java b/src/org/cyanogenmod/audiofx/audiofx/AudioFxApplication.java
new file mode 100644
index 0000000..fa47637
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/AudioFxApplication.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cyngn.audiofx;
+
+import android.app.Application;
+import android.util.Log;
+
+import com.cyanogen.ambient.analytics.AnalyticsServices;
+import com.cyanogen.ambient.analytics.Event;
+import com.cyanogen.ambient.common.api.AmbientApiClient;
+
+public class AudioFxApplication extends Application {
+
+ private static final String TAG = AudioFxApplication.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ private AmbientApiClient mClient;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mClient = new AmbientApiClient.Builder(this)
+ .addApi(AnalyticsServices.API)
+ .build();
+ mClient.connect();
+ }
+
+ public void sendEvent(Event event) {
+ if (DEBUG) {
+ Log.i(TAG, "sendEvent() called with event = [" + event + "]");
+ }
+ AnalyticsServices.AnalyticsApi.sendEvent(mClient, event);
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/Compatibility.java b/src/org/cyanogenmod/audiofx/audiofx/Compatibility.java
index c0e72c2..313c480 100644
--- a/src/org/cyanogenmod/audiofx/Compatibility.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/Compatibility.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.cyanogenmod.audiofx;
+package com.cyngn.audiofx;
import android.app.Activity;
import android.app.IntentService;
@@ -30,6 +30,8 @@ import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
+import com.cyngn.audiofx.activity.ActivityMusic;
+import com.cyngn.audiofx.stats.UserSession;
import java.util.List;
@@ -64,8 +66,8 @@ public class Compatibility {
Intent i = new Intent(getIntent());
i.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE);
- String defPackage = pref.getString("defaultpanelpackage", null);
- String defName = pref.getString("defaultpanelname", null);
+ String defPackage = pref.getString(Constants.MUSICFX_DEFAULT_PACKAGE_KEY, null);
+ String defName = pref.getString(Constants.MUSICFX_DEFAULT_PANEL_KEY, null);
log("read " + defPackage + "/" + defName + " as default");
if (defPackage == null || defName == null) {
Log.e(TAG, "no default set!");
@@ -79,6 +81,8 @@ public class Compatibility {
} else {
i.setComponent(new ComponentName(defPackage, defName));
}
+
+ i.putExtra(ActivityMusic.EXTRA_CALLING_PACKAGE, getCallingPackage());
startActivity(i);
finish();
}
@@ -149,9 +153,9 @@ public class Compatibility {
Intent i = new Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL);
List<ResolveInfo> ris = mPackageManager.queryIntentActivities(i, PackageManager.GET_DISABLED_COMPONENTS);
log("found: " + ris.size());
- SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE);
- String savedDefPackage = pref.getString("defaultpanelpackage", null);
- String savedDefName = pref.getString("defaultpanelname", null);
+ SharedPreferences pref = Constants.getMusicFxPrefs(this);
+ String savedDefPackage = pref.getString(Constants.MUSICFX_DEFAULT_PACKAGE_KEY, null);
+ String savedDefName = pref.getString(Constants.MUSICFX_DEFAULT_PANEL_KEY, null);
log("saved default: " + savedDefName);
for (ResolveInfo foo: ris) {
if (foo.activityInfo.name.equals(Compatibility.Redirector.class.getName())) {
@@ -206,10 +210,10 @@ public class Compatibility {
// Write the selected default to the prefs so that the Redirector activity
// knows which one to use.
- SharedPreferences pref = getSharedPreferences("musicfx", MODE_PRIVATE);
+ SharedPreferences pref = Constants.getMusicFxPrefs(this);
Editor ed = pref.edit();
- ed.putString("defaultpanelpackage", defPackage);
- ed.putString("defaultpanelname", defName);
+ ed.putString(Constants.MUSICFX_DEFAULT_PACKAGE_KEY, defPackage);
+ ed.putString(Constants.MUSICFX_DEFAULT_PANEL_KEY, defName);
ed.commit();
log("wrote " + defPackage + "/" + defName + " as default");
}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/Constants.java b/src/org/cyanogenmod/audiofx/audiofx/Constants.java
new file mode 100644
index 0000000..c1d5475
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/Constants.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cyngn.audiofx;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import com.cyngn.audiofx.eq.EqUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Constants {
+
+ // current pref version, bump to rebuild prefs
+ public static final int CURRENT_PREFS_INT_VERSION = 2;
+
+ // effect type identifiers
+ public static final int EFFECT_TYPE_ANDROID = 1;
+ public static final int EFFECT_TYPE_MAXXAUDIO = 2;
+ public static final int EFFECT_TYPE_DTS = 3;
+
+ // global settings
+ public static final String AUDIOFX_GLOBAL_FILE = "global";
+
+ public static final String DEVICE_SPEAKER = "speaker";
+ public static final String DEVICE_HEADSET = "headset";
+ public static final String DEVICE_LINE_OUT = "lineout";
+ public static final String DEVICE_PREFIX_USB = "usb";
+ public static final String DEVICE_PREFIX_CAST = "wireless";
+ public static final String DEVICE_PREFIX_BLUETOOTH = "bluetooth";
+
+ public static final String SAVED_DEFAULTS = "saved_defaults";
+
+ public static final String AUDIOFX_GLOBAL_USE_DTS = "audiofx.global.use_dts";
+ public static final String AUDIOFX_GLOBAL_HAS_DTS = "audiofx.global.has_dts";
+ public static final String AUDIOFX_GLOBAL_ENABLE_DTS = "audiofx.global.dts.enable";
+ public static final String AUDIOFX_GLOBAL_HAS_MAXXAUDIO = "audiofx.global.hasmaxxaudio";
+ public static final String AUDIOFX_GLOBAL_HAS_BASSBOOST = "audiofx.global.hasbassboost";
+ public static final String AUDIOFX_GLOBAL_HAS_VIRTUALIZER = "audiofx.global.hasvirtualizer";
+ public static final String AUDIOFX_GLOBAL_PREFS_VERSION_INT = "audiofx.global.prefs.version";
+
+ // per-device settings
+ public static final boolean DEVICE_DEFAULT_GLOBAL_ENABLE = false;
+
+ /**
+ * not really global enable, but really the device global enable...
+ */
+ public static final String DEVICE_AUDIOFX_GLOBAL_ENABLE = "audiofx.global.enable";
+ public static final String DEVICE_AUDIOFX_BASS_ENABLE = "audiofx.bass.enable";
+ public static final String DEVICE_AUDIOFX_BASS_STRENGTH = "audiofx.bass.strength";
+ public static final String DEVICE_AUDIOFX_REVERB_PRESET = "audiofx.reverb.preset";
+ public static final String DEVICE_AUDIOFX_VIRTUALIZER_ENABLE = "audiofx.virtualizer.enable";
+ public static final String DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH = "audiofx.virtualizer.strength";
+ public static final String DEVICE_AUDIOFX_TREBLE_ENABLE = "audiofx.treble.enable";
+ public static final String DEVICE_AUDIOFX_TREBLE_STRENGTH = "audiofx.treble.strength";
+ public static final String DEVICE_AUDIOFX_MAXXVOLUME_ENABLE = "audiofx.maxxvolume.enable";
+
+ public static final String DEVICE_AUDIOFX_EQ_PRESET = "audiofx.eq.preset";
+ public static final String DEVICE_AUDIOFX_EQ_PRESET_LEVELS = "audiofx.eq.preset.levels";
+
+ // eq
+ public static final String EQUALIZER_NUMBER_OF_PRESETS = "equalizer.number_of_presets";
+ public static final String EQUALIZER_NUMBER_OF_BANDS = "equalizer.number_of_bands";
+ public static final String EQUALIZER_BAND_LEVEL_RANGE = "equalizer.band_level_range";
+ public static final String EQUALIZER_CENTER_FREQS = "equalizer.center_freqs";
+ public static final String EQUALIZER_PRESET = "equalizer.preset.";
+ public static final String EQUALIZER_PRESET_NAMES = "equalizer.preset_names";
+
+ // musicfx constants
+ public static final String MUSICFX_PREF_NAME = "musicfx";
+ public static final String MUSICFX_DEFAULT_PACKAGE_KEY = "defaultpanelpackage";
+ public static final String MUSICFX_DEFAULT_PANEL_KEY = "defaultpanelname";
+
+ public static SharedPreferences getMusicFxPrefs(Context context) {
+ return context.getSharedPreferences(MUSICFX_PREF_NAME, Context.MODE_PRIVATE);
+ }
+
+ public static SharedPreferences getGlobalPrefs(Context context) {
+ return context.getSharedPreferences(AUDIOFX_GLOBAL_FILE, 0);
+ }
+
+ public static List<Preset> getCustomPresets(Context ctx, int bands) {
+ ArrayList<Preset> presets = new ArrayList<Preset>();
+ final SharedPreferences presetPrefs = ctx.getSharedPreferences("custom_presets", 0);
+ String[] presetNames = presetPrefs.getString("preset_names", "").split("\\|");
+
+ for (int i = 0; i < presetNames.length; i++) {
+ String storedPresetString = presetPrefs.getString(presetNames[i], null);
+ if (storedPresetString == null) {
+ continue;
+ }
+ Preset.CustomPreset p = Preset.CustomPreset.fromString(storedPresetString);
+ presets.add(p);
+ }
+
+ return presets;
+ }
+
+ public static void saveCustomPresets(Context ctx, List<Preset> presets) {
+ final SharedPreferences.Editor presetPrefs = ctx.getSharedPreferences("custom_presets", 0).edit();
+ presetPrefs.clear();
+
+ StringBuffer presetNames = new StringBuffer();
+ for (int i = 0; i < presets.size(); i++) {
+ final Preset preset = presets.get(i);
+ if (preset instanceof Preset.CustomPreset
+ && !(preset instanceof Preset.PermCustomPreset)) {
+ Preset.CustomPreset p = (Preset.CustomPreset) preset;
+ presetNames.append(p.getName());
+ presetNames.append("|");
+
+ presetPrefs.putString(p.getName(), p.toString());
+ }
+ }
+ if (presetNames.length() > 0) {
+ presetNames.deleteCharAt(presetNames.length() - 1);
+ }
+
+ presetPrefs.putString("preset_names", presetNames.toString());
+ presetPrefs.commit();
+ }
+
+ public static int[] getBandLevelRange(Context context) {
+ String savedCenterFreqs = context.getSharedPreferences("global", 0).getString("equalizer.band_level_range", null);
+ if (savedCenterFreqs == null || savedCenterFreqs.isEmpty()) {
+ return new int[]{-1500, 1500};
+ } else {
+ String[] split = savedCenterFreqs.split(";");
+ int[] freqs = new int[split.length];
+ for (int i = 0; i < split.length; i++) {
+ freqs[i] = Integer.valueOf(split[i]);
+ }
+ return freqs;
+ }
+ }
+
+ public static int[] getCenterFreqs(Context context, int eqBands) {
+ String savedCenterFreqs = context.getSharedPreferences("global", 0).getString("equalizer.center_freqs",
+ EqUtils.getZeroedBandsString(eqBands));
+ String[] split = savedCenterFreqs.split(";");
+ int[] freqs = new int[split.length];
+ for (int i = 0; i < split.length; i++) {
+ freqs[i] = Integer.valueOf(split[i]);
+ }
+ return freqs;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/Preset.java b/src/org/cyanogenmod/audiofx/audiofx/Preset.java
new file mode 100644
index 0000000..e284658
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/Preset.java
@@ -0,0 +1,236 @@
+package com.cyngn.audiofx;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.cyngn.audiofx.eq.EqUtils;
+
+public class Preset implements Parcelable {
+
+ protected String mName;
+ protected final float[] mLevels;
+
+ private Preset(String name, float[] levels) {
+ this.mName = name;
+ mLevels = new float[levels.length];
+ for (int i = 0; i < levels.length; i++) {
+ mLevels[i] = levels[i];
+ }
+ }
+
+ public float[] getLevels() {
+ return mLevels;
+ }
+
+ public float getBandLevel(int band) {
+ return mLevels[band];
+ }
+
+ @Override
+ public String toString() {
+ return mName + "|" + EqUtils.floatLevelsToString(mLevels);
+ }
+
+ private static Preset fromString(String input) {
+ final String[] split = input.split("\\|");
+ if (split == null || split.length != 2) {
+ return null;
+ }
+ float[] levels = EqUtils.stringBandsToFloats(split[1]);
+ return new Preset(split[0], levels);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof Preset) {
+ Preset other = (Preset) o;
+
+ if (this.mLevels.length != ((Preset) o).mLevels.length) {
+ return false;
+ }
+
+ for(int i = 0; i < mLevels.length; i++) {
+ if (mLevels[i] != other.mLevels[i]) {
+ return false;
+ }
+ }
+
+ return other.mName.equals(mName);
+ }
+ return super.equals(o);
+ }
+
+ private Preset(Parcel in) {
+ if (in.readInt() == 1) {
+ mName = in.readString();
+ }
+ mLevels = new float[in.readInt()];
+ in.readFloatArray(mLevels);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mName != null ? 1 : 0);
+ if (mName != null) {
+ dest.writeString(mName);
+ }
+ dest.writeInt(mLevels.length);
+ dest.writeFloatArray(mLevels);
+ }
+
+ public static final Parcelable.Creator<Preset> CREATOR = new Parcelable.Creator<Preset>() {
+ @Override
+ public Preset createFromParcel(Parcel in) {
+ return new Preset(in);
+ }
+
+ @Override
+ public Preset[] newArray(int size) {
+ return new Preset[size];
+ }
+ };
+
+ public String getName() {
+ return mName;
+ }
+
+ public static class StaticPreset extends Preset {
+ public StaticPreset(String name, float[] levels) {
+ super(name, levels);
+ }
+ }
+
+ public static class CustomPreset extends Preset {
+
+ private boolean mLocked;
+
+ public CustomPreset(String name, float[] levels, boolean locked) {
+ super(name, levels);
+ mLocked = locked;
+ }
+
+ public boolean isLocked() {
+ return mLocked;
+ }
+
+ public void setLocked(boolean locked) {
+ mLocked = locked;
+ }
+
+ public void setName(String name) {
+ mName = name;
+ }
+
+ public void setLevel(int band, float level) {
+ mLevels[band] = level;
+ }
+
+ public void setLevels(float[] levels) {
+ for (int i = 0; i < levels.length; i++) {
+ mLevels[i] = levels[i];
+ }
+ }
+
+ public float getLevel(int band) {
+ return mLevels[band];
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof CustomPreset) {
+ return super.equals(o) && mLocked == ((CustomPreset) o).mLocked;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + "|" + mLocked;
+ }
+
+ public static CustomPreset fromString(String input) {
+ final String[] split = input.split("\\|");
+ if (split == null || split.length != 3) {
+ return null;
+ }
+ float[] levels = EqUtils.stringBandsToFloats(split[1]);
+ return new CustomPreset(split[0], levels, Boolean.valueOf(split[2]));
+ }
+
+ public static final Parcelable.Creator<CustomPreset> CREATOR
+ = new Parcelable.Creator<CustomPreset>() {
+ @Override
+ public CustomPreset createFromParcel(Parcel in) {
+ return new CustomPreset(in);
+ }
+
+ @Override
+ public CustomPreset[] newArray(int size) {
+ return new CustomPreset[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mLocked ? 1 : 0);
+ }
+
+ protected CustomPreset(Parcel in) {
+ super(in);
+ mLocked = in.readInt() == 1;
+ }
+
+ }
+
+ public static class PermCustomPreset extends CustomPreset {
+
+ public PermCustomPreset(String name, float[] levels) {
+ super(name, levels, false);
+ }
+
+ @Override
+ public String toString() {
+ return mName + "|" + EqUtils.floatLevelsToString(mLevels);
+ }
+
+ public static PermCustomPreset fromString(String input) {
+ final String[] split = input.split("\\|");
+ if (split == null || split.length != 2) {
+ return null;
+ }
+ float[] levels = EqUtils.stringBandsToFloats(split[1]);
+ return new PermCustomPreset(split[0], levels);
+ }
+
+ protected PermCustomPreset(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<PermCustomPreset> CREATOR = new Creator<PermCustomPreset>() {
+ @Override
+ public PermCustomPreset createFromParcel(Parcel in) {
+ return new PermCustomPreset(in);
+ }
+
+ @Override
+ public PermCustomPreset[] newArray(int size) {
+ return new PermCustomPreset[size];
+ }
+ };
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/activity/ActivityMusic.java b/src/org/cyanogenmod/audiofx/audiofx/activity/ActivityMusic.java
new file mode 100644
index 0000000..f75273d
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/activity/ActivityMusic.java
@@ -0,0 +1,198 @@
+package com.cyngn.audiofx.activity;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewStub;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import com.cyanogen.ambient.analytics.Event;
+import com.cyngn.audiofx.AudioFxApplication;
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.fragment.AudioFxFragment;
+import com.cyngn.audiofx.knobs.KnobCommander;
+import com.cyngn.audiofx.service.AudioFxService;
+import com.cyngn.audiofx.stats.AppState;
+import com.cyngn.audiofx.stats.UserSession;
+
+public class ActivityMusic extends Activity {
+
+ private static final String TAG = ActivityMusic.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final String TAG_AUDIOFX = "audiofx";
+ public static final String EXTRA_CALLING_PACKAGE = "audiofx::extra_calling_package";
+
+ private CheckBox mCurrentDeviceToggle;
+ MasterConfigControl mConfig;
+ String mCallingPackage;
+
+ private boolean mWaitingForService = true;
+ private SharedPreferences.OnSharedPreferenceChangeListener mServiceReadyObserver;
+
+ private CompoundButton.OnCheckedChangeListener mGlobalEnableToggleListener
+ = new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(final CompoundButton buttonView,
+ final boolean isChecked) {
+ if (UserSession.getInstance() != null) {
+ UserSession.getInstance().deviceEnabledDisabled();
+ }
+ mConfig.setCurrentDeviceEnabled(isChecked);
+ }
+ };
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ if (DEBUG)
+ Log.i(TAG, "onCreate() called with "
+ + "savedInstanceState = [" + savedInstanceState + "]");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mCallingPackage = getIntent().getStringExtra(EXTRA_CALLING_PACKAGE);
+ Log.i(TAG, "calling package: " + mCallingPackage);
+
+ mConfig = MasterConfigControl.getInstance(this);
+
+ final SharedPreferences globalPrefs = Constants.getGlobalPrefs(this);
+
+ mWaitingForService = !defaultsSetup();
+ if (mWaitingForService) {
+ Log.w(TAG, "waiting for service.");
+ mServiceReadyObserver = new SharedPreferences.OnSharedPreferenceChangeListener() {
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
+ String key) {
+ if (key.equals(Constants.SAVED_DEFAULTS) && defaultsSetup()) {
+ sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
+ mConfig.onResetDefaults();
+ init(savedInstanceState);
+
+ mWaitingForService = false;
+ invalidateOptionsMenu();
+ mServiceReadyObserver = null;
+ }
+ }
+ };
+ globalPrefs.registerOnSharedPreferenceChangeListener(mServiceReadyObserver);
+ startService(new Intent(ActivityMusic.this, AudioFxService.class));
+ // TODO add loading fragment if service initialization takes too long
+ } else {
+ init(savedInstanceState);
+ }
+ }
+
+ private boolean defaultsSetup() {
+ final int targetVersion = Constants.CURRENT_PREFS_INT_VERSION;
+ final SharedPreferences prefs = Constants.getGlobalPrefs(this);
+ final int currentVersion = prefs.getInt(Constants.AUDIOFX_GLOBAL_PREFS_VERSION_INT, 0);
+ final boolean defaultsSaved = prefs.getBoolean(Constants.SAVED_DEFAULTS, false);
+ return defaultsSaved && currentVersion >= targetVersion;
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ // should null it out if one was there, compat redirector with package will go through onCreate
+ mCallingPackage = intent.getStringExtra(EXTRA_CALLING_PACKAGE);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mServiceReadyObserver != null) {
+ Constants.getGlobalPrefs(this)
+ .unregisterOnSharedPreferenceChangeListener(mServiceReadyObserver);
+ mServiceReadyObserver = null;
+ }
+ super.onDestroy();
+ }
+
+ private void init(Bundle savedInstanceState) {
+ mConfig = MasterConfigControl.getInstance(this);
+
+ ActionBar ab = getActionBar();
+ ab.setTitle(R.string.app_title);
+ ab.setDisplayShowTitleEnabled(true);
+
+ final View extraView = LayoutInflater.from(this)
+ .inflate(R.layout.action_bar_custom_components, null);
+ ActionBar.LayoutParams lp = new ActionBar.LayoutParams(ActionBar.LayoutParams.WRAP_CONTENT,
+ ActionBar.LayoutParams.WRAP_CONTENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+ ab.setCustomView(extraView, lp);
+ ab.setDisplayShowCustomEnabled(true);
+
+ mCurrentDeviceToggle = (CheckBox) ab.getCustomView().findViewById(R.id.global_toggle);
+ mCurrentDeviceToggle.setOnCheckedChangeListener(mGlobalEnableToggleListener);
+
+ if (savedInstanceState == null && findViewById(R.id.main_fragment) != null) {
+ getFragmentManager()
+ .beginTransaction()
+ .add(R.id.main_fragment, new AudioFxFragment(), TAG_AUDIOFX)
+ .commit();
+ }
+ applyOemDecor();
+ }
+
+ private void applyOemDecor() {
+ ActionBar ab = getActionBar();
+ if (mConfig.hasMaxxAudio()) {
+ ab.setSubtitle(R.string.powered_by_maxx_audio);
+ } else if (mConfig.hasDts()) {
+ final ViewStub stub = (ViewStub) ab.getCustomView().findViewById(R.id.logo_stub);
+ stub.setLayoutResource(R.layout.action_bar_dts_logo);
+ stub.inflate();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ if (DEBUG) Log.i(TAG, "onResume() called with " + "");
+ super.onResume();
+
+ // initiate a new session
+ new UserSession(mCallingPackage);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (DEBUG) Log.d(TAG, "Session: " + UserSession.getInstance());
+
+ final Event.Builder builder = new Event.Builder("session", "ended");
+ UserSession.getInstance().append(builder);
+ AppState.appendState(mConfig, KnobCommander.getInstance(this), builder);
+ ((AudioFxApplication) getApplicationContext()).sendEvent(builder.build());
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (DEBUG) Log.i(TAG, "onConfigurationChanged() called with "
+ + "newConfig = [" + newConfig + "]");
+ if (newConfig.orientation != getResources().getConfiguration().orientation) {
+ mCurrentDeviceToggle = null;
+ }
+ }
+
+ public void setGlobalToggleChecked(boolean checked) {
+ if (mCurrentDeviceToggle != null) {
+ mCurrentDeviceToggle.setOnCheckedChangeListener(null);
+ mCurrentDeviceToggle.setChecked(checked);
+ mCurrentDeviceToggle.setOnCheckedChangeListener(mGlobalEnableToggleListener);
+ }
+ }
+
+ public CompoundButton getGlobalSwitch() {
+ return mCurrentDeviceToggle;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/ControlPanelPicker.java b/src/org/cyanogenmod/audiofx/audiofx/activity/ControlPanelPicker.java
index 1c6eaaf..a9fd876 100644
--- a/src/org/cyanogenmod/audiofx/ControlPanelPicker.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/activity/ControlPanelPicker.java
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-package org.cyanogenmod.audiofx;
+package com.cyngn.audiofx.activity;
import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.internal.app.AlertController.AlertParams.OnPrepareListViewListener;
-import org.cyanogenmod.audiofx.Compatibility.Service;
+import com.cyngn.audiofx.Compatibility;
+import com.cyngn.audiofx.Compatibility.Service;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
@@ -31,11 +32,8 @@ import android.database.Cursor;
import android.database.MatrixCursor;
import android.media.audiofx.AudioEffect;
import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ListView;
+import com.cyngn.audiofx.R;
import java.util.List;
@@ -81,9 +79,9 @@ public class ControlPanelPicker extends AlertActivity implements OnClickListener
p.mOnClickListener = mItemClickListener;
p.mLabelColumn = "title";
p.mIsSingleChoice = true;
- p.mPositiveButtonText = getString(com.android.internal.R.string.ok);
+ p.mPositiveButtonText = getString(getOkStringResId());
p.mPositiveButtonListener = this;
- p.mNegativeButtonText = getString(com.android.internal.R.string.cancel);
+ p.mNegativeButtonText = getString(getCancelStringResId());
p.mOnPrepareListViewListener = this;
p.mTitle = getString(R.string.picker_title);
p.mCheckedItem = defpanelidx;
@@ -91,6 +89,14 @@ public class ControlPanelPicker extends AlertActivity implements OnClickListener
setupAlert();
}
+ private int getOkStringResId() {
+ return getResources().getIdentifier("ok", "string", "android");
+ }
+
+ private int getCancelStringResId() {
+ return getResources().getIdentifier("cancel", "string", "android");
+ }
+
private DialogInterface.OnClickListener mItemClickListener =
new DialogInterface.OnClickListener() {
diff --git a/src/org/cyanogenmod/audiofx/audiofx/activity/EqualizerManager.java b/src/org/cyanogenmod/audiofx/audiofx/activity/EqualizerManager.java
new file mode 100644
index 0000000..03e9853
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/activity/EqualizerManager.java
@@ -0,0 +1,634 @@
+package com.cyngn.audiofx.activity;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.widget.CompoundButton;
+
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.eq.EqUtils;
+import com.cyngn.audiofx.service.AudioFxService;
+import com.cyngn.audiofx.stats.UserSession;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+public class EqualizerManager {
+
+ private static final String TAG = EqualizerManager.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final MasterConfigControl mConfig;
+ private final Context mContext;
+
+ private float mMinFreq;
+ private float mMaxFreq;
+
+ private float mMinDB;
+ private float mMaxDB;
+ private int mNumBands;
+ private CompoundButton.OnCheckedChangeListener mLockChangeListener;
+
+ /*
+ * presets from the library custom preset.
+ */
+ private int mPredefinedPresets;
+ private float[] mCenterFreqs;
+ private float[] mGlobalLevels;
+
+ private AtomicBoolean mAnimatingToCustom = new AtomicBoolean(false);
+
+ // whether we are in between presets, animating them and such
+ private boolean mChangingPreset = false;
+
+ private int mCurrentPreset;
+
+ private final ArrayList<Preset> mEqPresets = new ArrayList<Preset>();
+ private int mEQCustomPresetPosition;
+
+ private String mZeroedBandString;
+
+ private static final int MSG_SAVE_PRESETS = 1;
+ private static final int MSG_SEND_EQ_OVERRIDE = 2;
+
+ private Handler mHandler = new Handler(new Handler.Callback() {
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SAVE_PRESETS:
+ Constants.saveCustomPresets(mContext, mEqPresets);
+ break;
+ case MSG_SEND_EQ_OVERRIDE:
+ mConfig.overrideEqLevels((short)msg.arg1, (short) msg.arg2);
+ break;
+ }
+ return true;
+ }}, true);
+
+ public EqualizerManager(Context context, MasterConfigControl config) {
+ mContext = context;
+ mConfig = config;
+
+ applyDefaults();
+ }
+
+ public void applyDefaults() {
+ mEqPresets.clear();
+ // setup eq
+ int bands = Integer.parseInt(getGlobalPref("equalizer.number_of_bands", "5"));
+ final int[] centerFreqs = Constants.getCenterFreqs(mContext, bands);
+ final int[] bandLevelRange = Constants.getBandLevelRange(mContext);
+
+ float[] centerFreqsKHz = new float[centerFreqs.length];
+ for (int i = 0; i < centerFreqs.length; i++) {
+ centerFreqsKHz[i] = (float) centerFreqs[i] / 1000.0f;
+ }
+
+ mMinDB = bandLevelRange[0] / 100;
+ mMaxDB = bandLevelRange[1] / 100;
+
+ mNumBands = centerFreqsKHz.length;
+ mGlobalLevels = new float[mNumBands];
+ for (int i = 0; i < mGlobalLevels.length; i++) {
+ mGlobalLevels[i] = 0;
+ }
+
+ mZeroedBandString = EqUtils.getZeroedBandsString(getNumBands());
+
+ mCenterFreqs = Arrays.copyOf(centerFreqsKHz, mNumBands);
+ System.arraycopy(centerFreqsKHz, 0, mCenterFreqs, 0, mNumBands);
+ mMinFreq = mCenterFreqs[0] / 2;
+ mMaxFreq = (float) Math.pow(mCenterFreqs[mNumBands - 1], 2) / mCenterFreqs[mNumBands - 2] / 2;
+
+ // setup equalizer presets
+ final int numPresets = Integer.parseInt(getGlobalPref("equalizer.number_of_presets", "0"));
+
+ if (numPresets > 0) {
+ // add library-provided presets
+ String[] presetNames = getGlobalPref("equalizer.preset_names", "").split("\\|");
+ mPredefinedPresets = presetNames.length + 1; // we consider first EQ to be part of predefined
+ for (int i = 0; i < numPresets; i++) {
+ mEqPresets.add(new Preset.StaticPreset(presetNames[i], getPersistedPresetLevels(i)));
+ }
+ } else {
+ mPredefinedPresets = 1; // custom is predefined
+ }
+ // add custom preset
+ mEqPresets.add(new Preset.PermCustomPreset(mContext.getString(R.string.user),
+ getPersistedCustomLevels()));
+ mEQCustomPresetPosition = mEqPresets.size() - 1;
+
+ // restore custom prefs
+ mEqPresets.addAll(Constants.getCustomPresets(mContext, mNumBands));
+
+ // setup default preset for speaker
+ mCurrentPreset = Integer.parseInt(getPref(Constants.DEVICE_AUDIOFX_EQ_PRESET, "0"));
+ if (mCurrentPreset > mEqPresets.size() - 1) {
+ mCurrentPreset = 0;
+ }
+ setPreset(mCurrentPreset);
+ }
+
+ public boolean isUserPreset() {
+ boolean result = mCurrentPreset >= mPredefinedPresets;
+ /*if (DEBUG) {
+ Log.i(TAG, "isUserPreset(), current preset: " + mCurrentPreset);
+ Log.i(TAG, "----> predefined presets: " + mPredefinedPresets);
+ Log.d(TAG, "----> RESULT: " + result);
+ }*/
+ return result;
+ }
+
+ public boolean isCustomPreset() {
+ return mCurrentPreset == mEQCustomPresetPosition;
+ }
+
+ public CompoundButton.OnCheckedChangeListener getLockChangeListener() {
+ if (mLockChangeListener == null) {
+ mLockChangeListener = new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isUserPreset()) {
+ ((Preset.CustomPreset) mEqPresets.get(mCurrentPreset)).setLocked(isChecked);
+ }
+ }
+ };
+ }
+ return mLockChangeListener;
+ }
+
+ public boolean isChangingPresets() {
+ return mChangingPreset;
+ }
+
+ public void setChangingPresets(boolean changing) {
+ if (mChangingPreset != changing) {
+ mChangingPreset = changing;
+ if (changing) {
+ mConfig.getCallbacks().notifyEqControlStateChanged(false, false, false, false);
+ } else {
+ updateEqControls();
+ }
+ }
+ }
+
+ public boolean isAnimatingToCustom() {
+ return mAnimatingToCustom.get();
+ }
+
+ public void setAnimatingToCustom(boolean animating) {
+ mAnimatingToCustom.set(animating);
+ if (!animating) {
+ // finished animation
+ updateEqControls();
+ }
+ }
+
+ private void savePresetsDelayed() {
+ mHandler.sendEmptyMessageDelayed(MSG_SAVE_PRESETS, 500);
+ }
+
+ public int indexOf(Preset p) {
+ return mEqPresets.indexOf(p);
+ }
+
+ void onPreDeviceChanged() {
+ // need to update the current preset based on the device here.
+ int newPreset = Integer.parseInt(getPref(Constants.DEVICE_AUDIOFX_EQ_PRESET, "0"));
+ if (newPreset > mEqPresets.size() - 1) {
+ newPreset = 0;
+ }
+
+ // this should be ready to go for callbacks to query the new device preset below
+ mCurrentPreset = newPreset;
+
+ }
+
+ void onPostDeviceChanged() {
+ setPreset(mCurrentPreset, false);
+ }
+
+ public Preset getCurrentPreset() {
+ return mEqPresets.get(mCurrentPreset);
+ }
+
+ /**
+ * Copy current config levels from the current preset into custom values since the user has
+ * initiated some change. Then update the current preset to 'custom'.
+ */
+ public int copyToCustom() {
+ updateGlobalLevels(mCurrentPreset);
+ if (DEBUG) {
+ Log.w(TAG, "using levels from preset: " + mCurrentPreset + ": " + Arrays.toString(mGlobalLevels));
+ }
+
+ String levels = EqUtils.floatLevelsToString(
+ EqUtils.convertDecibelsToMillibels(
+ mEqPresets.get(mCurrentPreset).getLevels()));
+ setGlobalPref("custom", levels);
+
+ ((Preset.PermCustomPreset) mEqPresets.get(mEQCustomPresetPosition)).setLevels(mGlobalLevels);
+ if (DEBUG)
+ Log.i(TAG, "copyToCustom() wrote current preset levels to index: " + mEQCustomPresetPosition);
+ setPreset(mEQCustomPresetPosition);
+ savePresetsDelayed();
+ return mEQCustomPresetPosition;
+ }
+
+ public int addPresetFromCustom() {
+ updateGlobalLevels(mEQCustomPresetPosition);
+ if (DEBUG) {
+ Log.w(TAG, "using levels from preset: " + mCurrentPreset + ": " + Arrays.toString(mGlobalLevels));
+ }
+
+ int writtenToIndex = addPreset(mGlobalLevels);
+ if (DEBUG)
+ Log.i(TAG, "addPresetFromCustom() wrote current preset levels to index: " + writtenToIndex);
+ setPreset(writtenToIndex);
+ savePresetsDelayed();
+ return writtenToIndex;
+ }
+
+ /**
+ * Loops through all presets. And finds the first preset that can be written to.
+ * If one is not found, then one is inserted, and that new index is returned.
+ * @return the index that the levels were copied to
+ */
+ private int addPreset(float[] levels) {
+ if (UserSession.getInstance() != null) {
+ UserSession.getInstance().presetCreated();
+ }
+
+ final int customPresets = Constants.getCustomPresets(mContext, mNumBands).size();
+ // format the name so it's like "Custom <N>", start with "Custom 2"
+ final String name = String.format(mContext.getString(R.string.user_n), customPresets + 2);
+
+ Preset.CustomPreset customPreset = new Preset.CustomPreset(name, levels, false);
+ mEqPresets.add(customPreset);
+
+ mConfig.getCallbacks().notifyPresetsChanged();
+
+ return mEqPresets.size() - 1;
+ }
+
+ /**
+ * Set a new level!
+ * <p/>
+ * This call will be propogated to all listeners registered with addEqStateChangeCallback().
+ *
+ * @param band the band index the band index which changed
+ * @param dB the new decibel value
+ * @param systemChange is this change generated by the system?
+ */
+ public void setLevel(final int band, final float dB, final boolean fromSystem) {
+ if (DEBUG) Log.i(TAG, "setLevel(" + band + ", " + dB + ", " + fromSystem + ")");
+
+ mGlobalLevels[band] = dB;
+
+ if (fromSystem && !mConfig.isUserDeviceOverride()) {
+ // quickly convert decibel to millibel and send away to the service
+ mHandler.obtainMessage(MSG_SEND_EQ_OVERRIDE, band, (short) (dB * 100)).sendToTarget();
+ }
+
+ mConfig.getCallbacks().notifyBandLevelChangeChanged(band, dB, fromSystem);
+
+ if (!fromSystem) { // user is touching
+ // persist
+
+ final Preset preset = mEqPresets.get(mCurrentPreset);
+ if (preset instanceof Preset.CustomPreset) {
+ if (mAnimatingToCustom.get()) {
+ if (DEBUG) {
+ Log.d(TAG, "setLevel() not persisting new custom band becuase animating.");
+ }
+ } else {
+ ((Preset.CustomPreset) preset).setLevel(band, dB);
+ if (preset instanceof Preset.PermCustomPreset) {
+ // store these as millibels
+ String levels = EqUtils.floatLevelsToString(
+ EqUtils.convertDecibelsToMillibels(
+ preset.getLevels()));
+ setGlobalPref("custom", levels);
+ }
+ }
+ // needs to be updated immediately here for the service.
+ final String levels = EqUtils.floatLevelsToString(preset.getLevels());
+ setPref(Constants.DEVICE_AUDIOFX_EQ_PRESET_LEVELS, levels);
+
+ mConfig.updateService(AudioFxService.EQ_CHANGED);
+ }
+ savePresetsDelayed();
+ }
+ }
+
+ /**
+ * Set a new preset index.
+ * <p/>
+ * This call will be propogated to all listeners registered with addEqStateChangeCallback().
+ *
+ * @param newPresetIndex the new preset index.
+ */
+ public void setPreset(final int newPresetIndex, boolean updateBackend) {
+ mCurrentPreset = newPresetIndex;
+ updateEqControls(); // do this before callback is propogated
+
+ mConfig.getCallbacks().notifyPresetChanged(newPresetIndex);
+
+ // persist
+ setPref(Constants.DEVICE_AUDIOFX_EQ_PRESET, String.valueOf(newPresetIndex));
+
+ // update mGlobalLevels
+ float[] newlevels = getPresetLevels(newPresetIndex);
+ for (int i = 0; i < newlevels.length; i++) {
+ setLevel(i, newlevels[i], true);
+ }
+
+ setPref(Constants.DEVICE_AUDIOFX_EQ_PRESET_LEVELS, EqUtils.floatLevelsToString(newlevels));
+
+ if (updateBackend) {
+ mConfig.updateService(AudioFxService.EQ_CHANGED);
+ }
+ }
+
+ public void setPreset(final int newPresetIndex) {
+ setPreset(newPresetIndex, true);
+ }
+
+ private void updateEqControls() {
+ final boolean userPreset = isUserPreset();
+ mConfig.getCallbacks().notifyEqControlStateChanged(mEQCustomPresetPosition == mCurrentPreset,
+ userPreset, userPreset, userPreset);
+ }
+
+ /**
+ * @return Get the current preset index
+ */
+ public int getCurrentPresetIndex() {
+ return mCurrentPreset;
+ }
+
+ /*===============
+ * eq methods
+ *===============*/
+
+ public float projectX(double freq) {
+ double pos = Math.log(freq);
+ double minPos = Math.log(mMinFreq);
+ double maxPos = Math.log(mMaxFreq);
+ return (float) ((pos - minPos) / (maxPos - minPos));
+ }
+
+ public double reverseProjectX(float pos) {
+ double minPos = Math.log(mMinFreq);
+ double maxPos = Math.log(mMaxFreq);
+ return Math.exp(pos * (maxPos - minPos) + minPos);
+ }
+
+ public float projectY(double dB) {
+ double pos = (dB - mMinDB) / (mMaxDB - mMinDB);
+ return (float) (1 - pos);
+ }
+
+ public static double lin2dB(double rho) {
+ return rho != 0 ? Math.log(rho) / Math.log(10) * 20 : -99.9;
+ }
+
+ public float getMinFreq() {
+ return mMinFreq;
+ }
+
+ public float getMaxFreq() {
+ return mMaxFreq;
+ }
+
+ public float getMinDB() {
+ return mMinDB;
+ }
+
+ public float getMaxDB() {
+ return mMaxDB;
+ }
+
+ public int getNumBands() {
+ return mNumBands;
+ }
+
+ public float getCenterFreq(int band) {
+ return mCenterFreqs[band];
+ }
+
+ public float[] getCenterFreqs() {
+ return mCenterFreqs;
+ }
+
+ public float[] getLevels() {
+ return mGlobalLevels;
+ }
+
+ public float getLevel(int band) {
+ return mGlobalLevels[band];
+ }
+
+ /*===============
+ * preset methods
+ *===============*/
+
+ public float[] getPersistedPresetLevels(int presetIndex) {
+ String newLevels = null;
+
+ if (mEqPresets.size() > presetIndex
+ && mEqPresets.get(presetIndex) instanceof Preset.PermCustomPreset) {
+ return getPersistedCustomLevels();
+ } else {
+ newLevels = getGlobalPref("equalizer.preset." + presetIndex, mZeroedBandString);
+ }
+
+ // stored as millibels, convert to decibels
+ float[] levels = EqUtils.stringBandsToFloats(newLevels);
+ return EqUtils.convertMillibelsToDecibels(levels);
+ }
+
+ private float[] getPersistedCustomLevels() {
+ String newLevels = getGlobalPref("custom", mZeroedBandString);
+ // stored as millibels, convert to decibels
+ float[] levels = EqUtils.stringBandsToFloats(newLevels);
+ return EqUtils.convertMillibelsToDecibels(levels);
+ }
+
+ /**
+ * Get preset levels in decibels for a given index
+ *
+ * @param presetIndex index which to fetch preset levels for
+ * @return an array of floats[] with the given index's preset levels
+ */
+ public float[] getPresetLevels(int presetIndex) {
+ return mEqPresets.get(presetIndex).getLevels();
+ }
+
+ /**
+ * Helper method which maps a preset index to a color value.
+ *
+ * @param index the preset index which to fetch a color for
+ * @return a color which is associated with this preset.
+ */
+ public int getAssociatedPresetColorHex(int index) {
+ int r = -1;
+ index = index % mEqPresets.size();
+ if (mEqPresets.get(index) instanceof Preset.CustomPreset) {
+ r = R.color.preset_custom;
+ } else {
+ switch (index) {
+ case 0:
+ r = R.color.preset_normal;
+ break;
+ case 1:
+ r = R.color.preset_classical;
+ break;
+ case 2:
+ r = R.color.preset_dance;
+ break;
+ case 3:
+ r = R.color.preset_flat;
+ break;
+ case 4:
+ r = R.color.preset_folk;
+ break;
+ case 5:
+ r = R.color.preset_metal;
+ break;
+ case 6:
+ r = R.color.preset_hiphop;
+ break;
+ case 7:
+ r = R.color.preset_jazz;
+ break;
+ case 8:
+ r = R.color.preset_pop;
+ break;
+ case 9:
+ r = R.color.preset_rock;
+ break;
+ case 10:
+ r = R.color.preset_electronic;
+ break;
+ case 11:
+ r = R.color.preset_small_speakers;
+ break;
+ default:
+ return r;
+ }
+ }
+ return mContext.getResources().getColor(r);
+ }
+
+ /**
+ * Get total number of presets
+ *
+ * @return int value with total number of presets
+ */
+ public int getPresetCount() {
+ return mEqPresets.size();
+ }
+
+ public Preset getPreset(int index) {
+ return mEqPresets.get(index);
+ }
+
+ public String getLocalizedPresetName(int index) {
+ // already localized
+ return localizePresetName(mEqPresets.get(index).getName());
+ }
+
+ private final String localizePresetName(final String name) {
+ // missing electronic, multimedia, small speakers, custom
+ final String[] names = {
+ "Normal", "Classical", "Dance", "Flat", "Folk",
+ "Heavy Metal", "Hip Hop", "Jazz", "Pop", "Rock",
+ "Electronic", "Small speakers", "Multimedia",
+ "Custom"
+ };
+ final int[] ids = {
+ R.string.normal, R.string.classical, R.string.dance, R.string.flat, R.string.folk,
+ R.string.heavy_metal, R.string.hip_hop, R.string.jazz, R.string.pop, R.string.rock,
+ R.string.ci_extreme, R.string.small_speakers, R.string.multimedia,
+ R.string.user
+ };
+
+ for (int i = names.length - 1; i >= 0; --i) {
+ if (names[i].equalsIgnoreCase(name)) {
+ return mContext.getString(ids[i]);
+ }
+ }
+ return name;
+ }
+
+ public boolean isEqualizerLocked() {
+ return getCurrentPreset() instanceof Preset.CustomPreset
+ && !(getCurrentPreset() instanceof Preset.PermCustomPreset)
+ && ((Preset.CustomPreset) getCurrentPreset()).isLocked();
+ }
+
+ public void renameCurrentPreset(String s) {
+ if (UserSession.getInstance() != null) {
+ UserSession.getInstance().presetRenamed();
+ }
+
+ if (isUserPreset()) {
+ ((Preset.CustomPreset) getCurrentPreset()).setName(s);
+ }
+
+ mConfig.getCallbacks().notifyPresetsChanged();
+
+ savePresetsDelayed();
+ }
+
+ public boolean removePreset(int index) {
+ if (UserSession.getInstance() != null) {
+ UserSession.getInstance().presetRemoved();
+ }
+
+ if (index > mEQCustomPresetPosition) {
+ mEqPresets.remove(index);
+ mConfig.getCallbacks().notifyPresetsChanged();
+
+ if (mCurrentPreset == index) {
+ if (DEBUG) {
+ Log.w(TAG, "removePreset() called on current preset, changing preset");
+ }
+ updateGlobalLevels(mCurrentPreset - 1);
+ setPreset(mCurrentPreset - 1);
+ }
+ savePresetsDelayed();
+ return true;
+ }
+ return false;
+ }
+
+ private void updateGlobalLevels(int presetIndexToCopy) {
+ final float[] presetLevels = getPresetLevels(presetIndexToCopy);
+ for (int i = 0; i < mGlobalLevels.length; i++) {
+ mGlobalLevels[i] = presetLevels[i];
+ }
+ }
+
+ // I AM SO LAZY!
+ private String getGlobalPref(String key, String defValue) {
+ return mConfig.getGlobalPrefs().getString(key, defValue);
+ }
+
+ private void setGlobalPref(String key, String value) {
+ mConfig.getGlobalPrefs().edit().putString(key, value).apply();
+ }
+
+ private String getPref(String key, String defValue) {
+ return mConfig.getPrefs().getString(key, defValue);
+ }
+
+ private void setPref(String key, String value) {
+ mConfig.getPrefs().edit().putString(key, value).apply();
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/activity/MasterConfigControl.java b/src/org/cyanogenmod/audiofx/audiofx/activity/MasterConfigControl.java
new file mode 100644
index 0000000..d83d0de
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/activity/MasterConfigControl.java
@@ -0,0 +1,367 @@
+package com.cyngn.audiofx.activity;
+
+import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP;
+import static android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO;
+import static android.media.AudioDeviceInfo.TYPE_DOCK;
+import static android.media.AudioDeviceInfo.TYPE_IP;
+import static android.media.AudioDeviceInfo.TYPE_LINE_ANALOG;
+import static android.media.AudioDeviceInfo.TYPE_LINE_DIGITAL;
+import static android.media.AudioDeviceInfo.TYPE_USB_ACCESSORY;
+import static android.media.AudioDeviceInfo.TYPE_USB_DEVICE;
+import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES;
+import static android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET;
+import static android.media.AudioDeviceInfo.convertDeviceTypeToInternalDevice;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.SharedPreferences;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.IBinder;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.service.AudioFxService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Master configuration class for AudioFX.
+ *
+ * Contains the main hub where data is stored for the current eq graph (which there should be
+ * one of, thus only once instance of this class exists).
+ *
+ * Anyone can obtain an instance of this class. If one does not exist, a new one is created.
+ * Immediately before the new instance creation happens, some defaults are pre-populated
+ * with MasterConfigControl.saveDefaults(). That method doesn't ever have to be directly called.
+ */
+public class MasterConfigControl {
+
+ private static final String TAG = MasterConfigControl.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final boolean SERVICE_DEBUG = false;
+
+ private final Context mContext;
+
+ private AudioFxService.LocalBinder mService;
+ private ServiceConnection mServiceConnection;
+ private int mServiceRefCount = 0;
+
+ private AudioDeviceInfo mCurrentDevice;
+ private AudioDeviceInfo mUserDeviceOverride;
+
+ private final StateCallbacks mCallbacks;
+ private final EqualizerManager mEqManager;
+ private final AudioManager mAudioManager;
+
+ private static MasterConfigControl sInstance;
+ private boolean mShouldBindToService = false;
+
+ public static MasterConfigControl getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new MasterConfigControl(context);
+ }
+ return sInstance;
+ }
+
+ private MasterConfigControl(Context context) {
+ mContext = context.getApplicationContext();
+
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+
+ mCallbacks = new StateCallbacks(this);
+ mEqManager = new EqualizerManager(context, this);
+ }
+
+ public void onResetDefaults() {
+ mEqManager.applyDefaults();
+ }
+
+ public synchronized boolean bindService() {
+ boolean conn = true;
+ if (SERVICE_DEBUG) Log.i(TAG, "bindService() refCount=" + mServiceRefCount);
+ if (mServiceConnection == null && mServiceRefCount == 0) {
+ mServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder binder) {
+ if (SERVICE_DEBUG) Log.i(TAG, "onServiceConnected refCount=" + mServiceRefCount);
+ mService = ((AudioFxService.LocalBinder) binder);
+ LocalBroadcastManager.getInstance(mContext).registerReceiver(
+ mDeviceChangeReceiver,
+ new IntentFilter(AudioFxService.ACTION_DEVICE_OUTPUT_CHANGED));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (SERVICE_DEBUG) Log.w(TAG, "onServiceDisconnected refCount =" + mServiceRefCount);
+ LocalBroadcastManager.getInstance(mContext).unregisterReceiver(
+ mDeviceChangeReceiver);
+ mService = null;
+ }
+ };
+
+ Intent serviceIntent = new Intent(mContext, AudioFxService.class);
+ conn = mContext.bindService(serviceIntent, mServiceConnection,
+ Context.BIND_AUTO_CREATE);
+ }
+ if (conn) {
+ mServiceRefCount++;
+ }
+ return mServiceRefCount > 0;
+ }
+
+ public synchronized void unbindService() {
+ if (SERVICE_DEBUG) Log.i(TAG, "unbindService() called refCount=" + mServiceRefCount);
+ if (mServiceRefCount > 0) {
+ mServiceRefCount--;
+ if (mServiceRefCount == 0) {
+ mContext.unbindService(mServiceConnection);
+ mService = null;
+ mServiceConnection = null;
+ }
+ }
+ }
+
+ public boolean checkService() {
+ if (mService == null && mServiceRefCount == 0 && mShouldBindToService) {
+ Log.e(TAG, "Service went away, rebinding");
+ bindService();
+ }
+ return mService != null;
+ }
+
+ private final BroadcastReceiver mDeviceChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int device = intent.getIntExtra("device", -1);
+ Log.d(TAG, "deviceChanged: " + device);
+ if (device > -1) {
+ AudioDeviceInfo info = getDeviceById(device);
+ if (info != null) {
+ setCurrentDevice(info, false);
+ }
+ }
+ }
+ };
+
+ public void updateService(int flags) {
+ if (checkService()) {
+ mService.update(flags);
+ }
+ }
+
+ public StateCallbacks getCallbacks() {
+ return mCallbacks;
+ }
+
+ public EqualizerManager getEqualizerManager() {
+ return mEqManager;
+ }
+
+ public synchronized void setCurrentDeviceEnabled(boolean isChecked) {
+ getPrefs().edit().putBoolean(Constants.DEVICE_AUDIOFX_GLOBAL_ENABLE, isChecked).apply();
+ getCallbacks().notifyGlobalToggle(isChecked);
+ updateService(AudioFxService.ALL_CHANGED);
+ }
+
+ public synchronized boolean isCurrentDeviceEnabled() {
+ return getPrefs().getBoolean(Constants.DEVICE_AUDIOFX_GLOBAL_ENABLE, false);
+ }
+
+ public synchronized SharedPreferences getGlobalPrefs() {
+ return mContext.getSharedPreferences(Constants.AUDIOFX_GLOBAL_FILE, 0);
+ }
+
+ /**
+ * Update the current device used when querying any device-specific values such as the current
+ * preset, or the user's custom eq preset settings.
+ *
+ * @param audioOutputRouting the new device key
+ */
+ public synchronized void setCurrentDevice(AudioDeviceInfo device, final boolean userSwitch) {
+
+ final AudioDeviceInfo current = getCurrentDevice();
+
+ Log.d(TAG, "setCurrentDevice name=" + (current == null ? null : current.getProductName()) +
+ " fromUser=" + userSwitch +
+ " cur=" + (current == null ? null : current.getType()) +
+ " new=" + (device == null ? null : device.getType()));
+
+ if (userSwitch) {
+ mUserDeviceOverride = device;
+ } else {
+ if (device != null) {
+ mCurrentDevice = device;
+ }
+ mUserDeviceOverride = null;
+ }
+
+ mEqManager.onPreDeviceChanged();
+
+ mCallbacks.notifyDeviceChanged(device, userSwitch);
+
+ mEqManager.onPostDeviceChanged();
+ }
+
+ public AudioDeviceInfo getSystemDevice() {
+ if (mCurrentDevice == null) {
+ final int forMusic = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
+ for (AudioDeviceInfo ai : getConnectedDevices()) {
+ if ((convertDeviceTypeToInternalDevice(ai.getType()) & forMusic) > 0) {
+ return ai;
+ }
+ }
+ }
+ return mCurrentDevice;
+ }
+
+ public boolean isUserDeviceOverride() {
+ return mUserDeviceOverride != null;
+ }
+
+ public AudioDeviceInfo getCurrentDevice() {
+ if (isUserDeviceOverride()) {
+ return mUserDeviceOverride;
+ }
+ return getSystemDevice();
+ }
+
+ public AudioDeviceInfo getDeviceById(int id) {
+ for (AudioDeviceInfo ai : mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
+ if (ai.getId() == id) {
+ return ai;
+ }
+ }
+ return null;
+ }
+
+ public List<AudioDeviceInfo> getConnectedDevices(int... filter) {
+ final List<AudioDeviceInfo> devices = new ArrayList<AudioDeviceInfo>();
+ for (AudioDeviceInfo ai : mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
+ if (filter.length == 0) {
+ devices.add(ai);
+ } else {
+ for (int i = 0; i < filter.length; i++) {
+ if (ai.getType() == filter[i]) {
+ devices.add(ai);
+ continue;
+ }
+ }
+ }
+ }
+ return devices;
+ }
+
+ public String getCurrentDeviceIdentifier() {
+ return getDeviceIdentifierString(getCurrentDevice());
+ }
+
+ public SharedPreferences getPrefs() {
+ return mContext.getSharedPreferences(getCurrentDeviceIdentifier(), 0);
+ }
+
+ public boolean hasDts() {
+ return getGlobalPrefs().getBoolean(Constants.AUDIOFX_GLOBAL_HAS_DTS, false);
+ }
+
+ public boolean hasMaxxAudio() {
+ return getGlobalPrefs().getBoolean(Constants.AUDIOFX_GLOBAL_HAS_MAXXAUDIO, false);
+ }
+
+ public boolean getMaxxVolumeEnabled() {
+ return getPrefs().getBoolean(Constants.DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, false);
+ }
+
+ public boolean hasBassBoost() {
+ return getGlobalPrefs().getBoolean(Constants.AUDIOFX_GLOBAL_HAS_BASSBOOST, false);
+ }
+
+ public boolean hasVirtualizer() {
+ return getGlobalPrefs().getBoolean(Constants.AUDIOFX_GLOBAL_HAS_VIRTUALIZER, false);
+ }
+
+ public void setMaxxVolumeEnabled(boolean enable) {
+ getPrefs().edit().putBoolean(Constants.DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, enable).apply();
+ updateService(AudioFxService.VOLUME_BOOST_CHANGED);
+ }
+
+ void overrideEqLevels(short band, short level) {
+ if (checkService()) {
+ mService.setOverrideLevels(band, level);
+ }
+ }
+
+ public static String getDeviceDisplayString(Context context, AudioDeviceInfo info) {
+ int type = info == null ? -1 : info.getType();
+ switch (type) {
+ case TYPE_WIRED_HEADSET:
+ case TYPE_WIRED_HEADPHONES:
+ return context.getString(com.cyngn.audiofx.R.string.device_headset);
+ case TYPE_LINE_ANALOG:
+ case TYPE_LINE_DIGITAL:
+ return context.getString(com.cyngn.audiofx.R.string.device_line_out);
+ case TYPE_BLUETOOTH_SCO:
+ case TYPE_BLUETOOTH_A2DP:
+ case TYPE_USB_DEVICE:
+ case TYPE_USB_ACCESSORY:
+ case TYPE_DOCK:
+ case TYPE_IP:
+ return info.getProductName().toString();
+ default:
+ return context.getString(com.cyngn.audiofx.R.string.device_speaker);
+ }
+ }
+
+ private static String appendProductName(AudioDeviceInfo info, String prefix) {
+ StringBuilder nm = new StringBuilder(prefix);
+ if (info != null && info.getProductName() != null) {
+ nm.append("-").append(info.getProductName().toString().replaceAll("\\W+", ""));
+ }
+ return nm.toString();
+ }
+
+ private static String appendDeviceAddress(AudioDeviceInfo info, String prefix) {
+ StringBuilder nm = new StringBuilder(prefix);
+ if (info != null && info.getAddress() != null) {
+ nm.append("-").append(info.getAddress().replace(":", ""));
+ }
+ return nm.toString();
+ }
+
+ public static String getDeviceIdentifierString(AudioDeviceInfo info) {
+ int type = info == null ? -1 : info.getType();
+ switch (type) {
+ case TYPE_WIRED_HEADSET:
+ case TYPE_WIRED_HEADPHONES:
+ return Constants.DEVICE_HEADSET;
+ case TYPE_LINE_ANALOG:
+ case TYPE_LINE_DIGITAL:
+ return Constants.DEVICE_LINE_OUT;
+ case TYPE_BLUETOOTH_SCO:
+ case TYPE_BLUETOOTH_A2DP:
+ return appendDeviceAddress(info, Constants.DEVICE_PREFIX_BLUETOOTH);
+ case TYPE_USB_DEVICE:
+ case TYPE_USB_ACCESSORY:
+ case TYPE_DOCK:
+ return appendProductName(info, Constants.DEVICE_PREFIX_USB);
+ case TYPE_IP:
+ return appendProductName(info, Constants.DEVICE_PREFIX_CAST);
+ default:
+ return Constants.DEVICE_SPEAKER;
+ }
+ }
+
+ /**
+ * Set whether to automatically attempt to bind to the service.
+ * @param bindToService
+ */
+ public void setAutoBindToService(boolean bindToService) {
+ mShouldBindToService = bindToService;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/activity/StateCallbacks.java b/src/org/cyanogenmod/audiofx/audiofx/activity/StateCallbacks.java
new file mode 100644
index 0000000..0aa7379
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/activity/StateCallbacks.java
@@ -0,0 +1,154 @@
+
+package com.cyngn.audiofx.activity;
+
+import android.media.AudioDeviceInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StateCallbacks {
+
+ private static final String TAG = "StateCallbacks";
+
+ private final MasterConfigControl mConfig;
+
+ private final List<EqUpdatedCallback> mEqUpdateCallbacks = new ArrayList<EqUpdatedCallback>();
+
+ private final List<DeviceChangedCallback> mDeviceChangedCallbacks = new ArrayList<DeviceChangedCallback>();
+
+ private final List<EqControlStateCallback> mEqControlStateCallbacks = new ArrayList<EqControlStateCallback>();
+
+ StateCallbacks(MasterConfigControl config) {
+ mConfig = config;
+ }
+
+ /**
+ * Implement this callback to receive any changes called to the
+ * MasterConfigControl instance
+ */
+ public interface EqUpdatedCallback {
+ /**
+ * A band level has been changed
+ *
+ * @param band the band index which changed
+ * @param dB the new decibel value
+ * @param fromSystem whether the event was from the system or from the
+ * user
+ */
+ public void onBandLevelChange(int band, float dB, boolean fromSystem);
+
+ /**
+ * The preset has been set
+ *
+ * @param newPresetIndex the new preset index.
+ */
+ public void onPresetChanged(int newPresetIndex);
+
+ public void onPresetsChanged();
+ }
+
+ public void addEqUpdatedCallback(EqUpdatedCallback callback) {
+ synchronized (mEqUpdateCallbacks) {
+ mEqUpdateCallbacks.add(callback);
+ }
+ }
+
+ public void removeEqUpdatedCallback(EqUpdatedCallback callback) {
+ synchronized (mEqUpdateCallbacks) {
+ mEqUpdateCallbacks.remove(callback);
+ }
+ }
+
+ void notifyPresetsChanged() {
+ synchronized (mEqUpdateCallbacks) {
+ for (final EqUpdatedCallback callback : mEqUpdateCallbacks) {
+ callback.onPresetsChanged();
+ }
+ }
+ }
+
+ void notifyPresetChanged(final int index) {
+ synchronized (mEqUpdateCallbacks) {
+ for (final EqUpdatedCallback callback : mEqUpdateCallbacks) {
+ callback.onPresetChanged(index);
+ }
+ }
+ }
+
+ void notifyBandLevelChangeChanged(final int band, final float dB, final boolean fromSystem) {
+ synchronized (mEqUpdateCallbacks) {
+ for (final EqUpdatedCallback callback : mEqUpdateCallbacks) {
+ callback.onBandLevelChange(band, dB, fromSystem);
+ }
+ }
+ }
+
+ /**
+ * Callback for changes to visibility and state of the EQ
+ */
+ public interface EqControlStateCallback {
+ public void updateEqState(boolean saveVisible, boolean removeVisible,
+ boolean renameVisible, boolean unlockVisible);
+ }
+
+ public void addEqControlStateCallback(EqControlStateCallback callback) {
+ synchronized (mEqControlStateCallbacks) {
+ mEqControlStateCallbacks.add(callback);
+ }
+ }
+
+ public synchronized void removeEqControlStateCallback(EqControlStateCallback callback) {
+ synchronized (mEqControlStateCallbacks) {
+ mEqControlStateCallbacks.remove(callback);
+ }
+ }
+
+ void notifyEqControlStateChanged(boolean saveVisible, boolean removeVisible,
+ boolean renameVisible, boolean unlockVisible) {
+ synchronized (mEqControlStateCallbacks) {
+ for (final EqControlStateCallback callback : mEqControlStateCallbacks) {
+ callback.updateEqState(saveVisible, removeVisible, renameVisible, unlockVisible);
+ }
+ }
+ }
+
+ /**
+ * Register this callback to receive notification when the output device
+ * changes.
+ */
+ public interface DeviceChangedCallback {
+ public void onDeviceChanged(AudioDeviceInfo device, boolean userChange);
+ public void onGlobalDeviceToggle(boolean on);
+
+ }
+
+ public void addDeviceChangedCallback(DeviceChangedCallback callback) {
+ synchronized (mDeviceChangedCallbacks) {
+ mDeviceChangedCallbacks.add(callback);
+ callback.onDeviceChanged(mConfig.getCurrentDevice(), false);
+ }
+ }
+
+ public synchronized void removeDeviceChangedCallback(DeviceChangedCallback callback) {
+ synchronized (mDeviceChangedCallbacks) {
+ mDeviceChangedCallbacks.remove(callback);
+ }
+ }
+
+ void notifyGlobalToggle(boolean on) {
+ synchronized (mDeviceChangedCallbacks) {
+ for (DeviceChangedCallback callback : mDeviceChangedCallbacks) {
+ callback.onGlobalDeviceToggle(on);
+ }
+
+ }
+ }
+
+ void notifyDeviceChanged(final AudioDeviceInfo newDevice, final boolean fromUser) {
+ synchronized (mDeviceChangedCallbacks) {
+ for (final DeviceChangedCallback callback : mDeviceChangedCallbacks) {
+ callback.onDeviceChanged(newDevice, fromUser);
+ }
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/backends/AndroidEffects.java b/src/org/cyanogenmod/audiofx/audiofx/backends/AndroidEffects.java
new file mode 100644
index 0000000..090eb73
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/backends/AndroidEffects.java
@@ -0,0 +1,185 @@
+package com.cyngn.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.media.audiofx.AudioEffect;
+import android.media.audiofx.BassBoost;
+import android.media.audiofx.PresetReverb;
+import android.media.audiofx.Virtualizer;
+import android.util.Log;
+
+import com.cyngn.audiofx.Constants;
+
+/**
+ * EffectSet which comprises standard Android effects
+ */
+class AndroidEffects extends EffectSetWithAndroidEq {
+
+ /**
+ * Session-specific bassboost
+ */
+ private BassBoost mBassBoost;
+
+ /**
+ * Session-specific virtualizer
+ */
+ private Virtualizer mVirtualizer;
+
+ /**
+ * Session-specific reverb
+ */
+ private PresetReverb mPresetReverb;
+
+ public AndroidEffects(int sessionId, AudioDeviceInfo deviceInfo) {
+ super(sessionId, deviceInfo);
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+
+ mBassBoost = new BassBoost(100, mSessionId);
+ mVirtualizer = new Virtualizer(100, mSessionId);
+ mPresetReverb = new PresetReverb(100, mSessionId);
+ }
+
+ @Override
+ public void release() {
+ super.release();
+
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.release();
+ }
+ } catch (Exception e) {
+ // ignored;
+ }
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.release();
+ }
+ } catch (Exception e) {
+ // ignored
+ }
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.release();
+ }
+ } catch (Exception e) {
+ // ignored
+ }
+ mBassBoost = null;
+ mVirtualizer = null;
+ mPresetReverb = null;
+ }
+
+ @Override
+ public synchronized void setDevice(AudioDeviceInfo deviceInfo) {
+ super.setDevice(deviceInfo);
+ }
+
+ @Override
+ public void setGlobalEnabled(boolean globalEnabled) {
+ super.setGlobalEnabled(globalEnabled);
+
+ if (!globalEnabled) {
+ // disable everything. it will get explictly enabled
+ // individually when necessary.
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable virtualizer!", e);
+ }
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable bass boost!", e);
+ }
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.setEnabled(false);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to disable reverb!", e);
+ }
+ }
+ }
+
+ @Override
+ public boolean hasVirtualizer() {
+ return mVirtualizer != null && mVirtualizer.getStrengthSupported();
+ }
+
+ @Override
+ public boolean hasBassBoost() {
+ return mBassBoost != null && mBassBoost.getStrengthSupported();
+ }
+
+ @Override
+ public void enableBassBoost(boolean enable) {
+ try {
+ if (mBassBoost != null) {
+ mBassBoost.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " bass boost!", e);
+ }
+ }
+
+ @Override
+ public void setBassBoostStrength(short strength) {
+ setParameterSafe(mBassBoost, BassBoost.PARAM_STRENGTH, strength);
+ }
+
+ @Override
+ public void enableVirtualizer(boolean enable) {
+ try {
+ if (mVirtualizer != null) {
+ mVirtualizer.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " virtualizer!", e);
+ }
+ }
+
+ @Override
+ public void setVirtualizerStrength(short strength) {
+ setParameterSafe(mVirtualizer, Virtualizer.PARAM_STRENGTH, strength);
+ }
+
+ @Override
+ public void enableReverb(boolean enable) {
+ try {
+ if (mPresetReverb != null) {
+ mPresetReverb.setEnabled(enable);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to " + (enable ? "enable" : "disable") + " preset reverb!", e);
+ }
+
+ }
+
+ @Override
+ public void setReverbPreset(short preset) {
+ setParameterSafe(mPresetReverb, PresetReverb.PARAM_PRESET, preset);
+ }
+
+ @Override
+ public int getBrand() {
+ return Constants.EFFECT_TYPE_ANDROID;
+ }
+
+ private void setParameterSafe(AudioEffect e, int p, short v) {
+ if (e == null) {
+ return;
+ }
+ try {
+ e.setParameter(p, v);
+ } catch (Exception ex) {
+ Log.e(TAG, "Failed to set param " + p + " for effect " + e.getDescriptor().name, ex);
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSet.java b/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSet.java
new file mode 100644
index 0000000..47ae894
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSet.java
@@ -0,0 +1,235 @@
+package com.cyngn.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.util.Log;
+
+/**
+ * Helper class representing the full complement of effects attached to one
+ * audio session.
+ */
+public abstract class EffectSet {
+
+ protected static final String TAG = "AudioFx-EffectSet";
+
+ protected final int mSessionId;
+
+ protected boolean mGlobalEnabled;
+
+ private AudioDeviceInfo mDeviceInfo;
+
+ private boolean mMarkedForDeath = false;
+
+ public EffectSet(int sessionId, AudioDeviceInfo deviceInfo) {
+ mSessionId = sessionId;
+ mDeviceInfo = deviceInfo;
+ try {
+ onCreate();
+ } catch (Exception e) {
+ Log.e(TAG, "error creating" + this + ", releasing and throwing!");
+ release();
+ throw e;
+ }
+ }
+
+ /**
+ * Called to do subclass-first initialization in case
+ * an implementation has ordering restrictions.
+ *
+ * This call is wrapped in a try/catch - if an exception is thrown here,
+ * a release will immediately be called.
+ */
+ protected void onCreate() { }
+
+ /**
+ * Destroy all effects in this set.
+ *
+ * Attempting to use this object after calling release is
+ * undefined behavior.
+ */
+ public void release() { }
+
+ /**
+ * Returns the enumerated brand of this implementation
+ * @return brandId
+ */
+ public abstract int getBrand();
+
+ /**
+ * Called when the user toggles the engine on or off. If the
+ * implementation has a built-in bypass mode, this is where
+ * to use it.
+ *
+ * @param globalEnabled
+ */
+ public void setGlobalEnabled(boolean globalEnabled) {
+ mGlobalEnabled = globalEnabled;
+ }
+
+ public boolean isGlobalEnabled() {
+ return mGlobalEnabled;
+ }
+
+ /**
+ * Called when the output device has changed. All cached
+ * data should be cleared at this point.
+ *
+ * @param deviceInfo
+ */
+ public void setDevice(AudioDeviceInfo deviceInfo) {
+ mDeviceInfo = deviceInfo;
+ }
+
+ /**
+ * Return the current active output device
+ * @return deviceInfo
+ */
+ public AudioDeviceInfo getDevice() {
+ return mDeviceInfo;
+ }
+
+ /**
+ * Begin bulk-update of parameters. This can be used if the
+ * implementation supports operation in a transactional/atomic
+ * manner. Parameter changes will immediately follow this call
+ * and should be committed to the backend when the subsequent
+ * commitUpdate() is called.
+ *
+ * Optional.
+ *
+ * @return status - false on failure
+ */
+ public boolean beginUpdate() { return true; }
+
+ /**
+ * Commit accumulated updates to the backend. See above.
+ *
+ * begin/commit are used when a large number of parameters need
+ * to be sent to the backend, such as in the case of a device
+ * switch or preset change. This can increase performance and
+ * reduce click/pop issues.
+ *
+ * Optional.
+ *
+ * @return status - false on failure
+ */
+ public boolean commitUpdate() { return true; }
+
+ /* ---- Top level effects begin here ---- */
+
+ // required effects
+ public abstract boolean hasVirtualizer();
+
+ public abstract boolean hasBassBoost();
+
+ // optional effects
+ public boolean hasTrebleBoost() {
+ return false;
+ }
+
+ public boolean hasVolumeBoost() {
+ return false;
+ }
+
+ public boolean hasReverb() {
+ return false;
+ }
+
+ public abstract void enableEqualizer(boolean enable);
+
+ /**
+ * @param levels in decibels
+ */
+ public abstract void setEqualizerLevelsDecibels(float[] levels);
+
+ public abstract short getNumEqualizerBands();
+
+ /**
+ * @param band
+ * @param level in millibels
+ */
+ public abstract void setEqualizerBandLevel(short band, float level);
+
+ /**
+ * @return level in millibels
+ */
+ public abstract int getEqualizerBandLevel(short band);
+
+ public abstract String getEqualizerPresetName(short preset);
+
+ public abstract void useEqualizerPreset(short preset);
+
+ public abstract short getNumEqualizerPresets();
+
+ public abstract short[] getEqualizerBandLevelRange();
+
+ /**
+ * @param band
+ * @return center frequency of the band in millihertz
+ */
+ public abstract int getCenterFrequency(short band);
+
+ public abstract void enableBassBoost(boolean enable);
+
+ /**
+ * @param strength with range [0-1000]
+ */
+ public abstract void setBassBoostStrength(short strength);
+
+ public abstract void enableVirtualizer(boolean enable);
+
+ /**
+ * @param strength with range [0-1000]
+ */
+ public abstract void setVirtualizerStrength(short strength);
+
+ public void enableReverb(boolean enable) {
+ return;
+ }
+
+ public void setReverbPreset(short preset) {
+ return;
+ }
+
+ public void enableTrebleBoost(boolean enable) {
+ return;
+ }
+
+ /**
+ * @param strength with range [0-100]
+ */
+ public void setTrebleBoostStrength(short strength) {
+ return;
+ }
+
+ public void enableVolumeBoost(boolean enable) {
+ return;
+ }
+
+ /**
+ * How long should we delay for when releasing the effects?
+ * This helps certain effect implementations when the
+ * app is reusing a session ID. By default this
+ * behavior is disabled.
+ */
+ public int getReleaseDelay() {
+ return 0;
+ }
+
+ public boolean isMarkedForDeath() {
+ return mMarkedForDeath;
+ }
+
+ public void setMarkedForDeath(boolean die) {
+ mMarkedForDeath = die;
+ }
+
+ @Override
+ public String toString() {
+ return "EffectSet (" + this.getClass().getSimpleName() + ")"
+ + " [ "
+ + " mSessionId: " + mSessionId
+ + " mDeviceInfo: " + mDeviceInfo
+ + " mGlobalEnabled: " + mGlobalEnabled
+ + " ]";
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSetWithAndroidEq.java b/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSetWithAndroidEq.java
new file mode 100644
index 0000000..81cd53c
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/backends/EffectSetWithAndroidEq.java
@@ -0,0 +1,123 @@
+package com.cyngn.audiofx.backends;
+
+import android.media.AudioDeviceInfo;
+import android.media.audiofx.Equalizer;
+import android.util.Log;
+
+import com.cyngn.audiofx.eq.EqUtils;
+
+/**
+ * Created by roman on 3/1/16.
+ */
+public abstract class EffectSetWithAndroidEq extends EffectSet {
+ /**
+ * Session-specific equalizer
+ */
+ private Equalizer mEqualizer;
+
+ private short mEqNumPresets = -1;
+ private short mEqNumBands = -1;
+
+ public EffectSetWithAndroidEq(int sessionId, AudioDeviceInfo deviceInfo) {
+ super(sessionId, deviceInfo);
+ }
+
+ @Override
+ protected void onCreate() {
+ mEqualizer = new Equalizer(100, mSessionId);
+ super.onCreate();
+
+ }
+
+ @Override
+ public synchronized void release() {
+ if (mEqualizer != null) {
+ mEqualizer.release();
+ mEqualizer = null;
+ }
+ super.release();
+ }
+
+ @Override
+ public void setGlobalEnabled(boolean globalEnabled) {
+ super.setGlobalEnabled(globalEnabled);
+
+ enableEqualizer(globalEnabled);
+ }
+
+ @Override
+ public void enableEqualizer(boolean enable) {
+ try {
+ mEqualizer.setEnabled(enable);
+ } catch (Exception e) {
+ Log.e(TAG, "enableEqualizer failed! enable=" + enable + " sessionId=" + mSessionId, e);
+ }
+ }
+
+ @Override
+ public void setEqualizerLevelsDecibels(float[] levels) {
+ final short[] equalizerLevels = EqUtils.convertDecibelsToMillibelsInShorts(levels);
+ for (short i = 0; i < equalizerLevels.length; i++) {
+ setBandLevelSafe(i, equalizerLevels[i]);
+ }
+ }
+
+ @Override
+ public short getNumEqualizerBands() {
+ if (mEqNumBands < 0) {
+ mEqNumBands = mEqualizer.getNumberOfBands();
+ }
+ return mEqNumBands;
+ }
+
+ @Override
+ public void setEqualizerBandLevel(short band, float level) {
+ setBandLevelSafe(band, (short)level);
+ }
+
+ @Override
+ public int getEqualizerBandLevel(short band) {
+ return mEqualizer.getBandLevel(band);
+ }
+
+ @Override
+ public String getEqualizerPresetName(short preset) {
+ return mEqualizer.getPresetName(preset);
+ }
+
+ @Override
+ public void useEqualizerPreset(short preset) {
+ mEqualizer.usePreset(preset);
+ }
+
+ @Override
+ public short getNumEqualizerPresets() {
+ if (mEqNumPresets < 0) {
+ mEqNumPresets = mEqualizer.getNumberOfPresets();
+ }
+ return mEqNumPresets;
+ }
+
+ @Override
+ public short[] getEqualizerBandLevelRange() {
+ return mEqualizer.getBandLevelRange();
+ }
+
+ @Override
+ public int getCenterFrequency(short band) {
+ return mEqualizer.getCenterFreq(band);
+ }
+
+ @Override
+ public synchronized void setDevice(AudioDeviceInfo deviceInfo) {
+ super.setDevice(deviceInfo);
+ }
+
+ private synchronized void setBandLevelSafe(short band, short level) {
+ try {
+ mEqualizer.setBandLevel(band, level);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to set eq band=" + band + " level=" + level, e);
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/backends/IEffectFactory.java b/src/org/cyanogenmod/audiofx/audiofx/backends/IEffectFactory.java
new file mode 100644
index 0000000..8e629b8
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/backends/IEffectFactory.java
@@ -0,0 +1,16 @@
+package com.cyngn.audiofx.backends;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+
+interface IEffectFactory {
+
+ /**
+ * Create a new EffectSet based on current stream parameters.
+ * @param context context to create the effect with
+ * @param sessionId session id to attach the effect to
+ * @param currentDevice current device that the effect should initially setup for
+ * @return an {@link EffectSet}
+ */
+ EffectSet createEffectSet(Context context, int sessionId, AudioDeviceInfo currentDevice);
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/eq/EqBarView.java b/src/org/cyanogenmod/audiofx/audiofx/eq/EqBarView.java
new file mode 100644
index 0000000..df697dd
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/eq/EqBarView.java
@@ -0,0 +1,208 @@
+package com.cyngn.audiofx.eq;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.activity.StateCallbacks;
+
+public class EqBarView extends FrameLayout implements StateCallbacks.EqUpdatedCallback {
+
+ private static final String TAG = EqBarView.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private EqualizerManager mEqManager;
+
+ private float mNormalWidth;
+ private float mParentHeight = -1;
+ private float mLastTouchX;
+ private float mLastTouchY;
+ private float mPosX;
+ private float mPosY = -1;
+ private boolean mUserInteracting;
+ private int mParentTop;
+ private Integer mIndex;
+ private float mInitialLevel;
+
+ public EqBarView(Context context) {
+ super(context);
+ init();
+ }
+
+ public EqBarView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public EqBarView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ private void init() {
+ mEqManager = MasterConfigControl.getInstance(mContext).getEqualizerManager();
+ mNormalWidth = getResources().getDimension(R.dimen.eq_bar_width);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ private EqContainerView.EqBandInfo getInfo() {
+ return (EqContainerView.EqBandInfo) getTag();
+ }
+
+ public void setParentHeight(float h, int top) {
+ mParentHeight = h;
+ mParentTop = top;
+ updateHeight();
+ }
+
+ void updateHeight() {
+ if (DEBUG) Log.d(TAG, "updateHeight()");
+
+ if (getInfo() != null) {
+ float level = mEqManager.getLevel(getIndex());
+ float yProjection = 1 - mEqManager.projectY(level);
+ float height = (yProjection * (mParentHeight));
+ mPosY = height;
+
+ if (DEBUG) {
+ Log.d(TAG, getIndex() + "level: " + level + ", yProjection: "
+ + yProjection + ", mPosY: " + mPosY);
+ }
+ updateHeight((int) mPosY);
+ } else {
+ if (DEBUG) Log.d(TAG, "could not updateHeight()");
+ }
+ }
+
+ public int getIndex() {
+ if (mIndex == null) {
+ mIndex = (getInfo()).mIndex;
+ }
+ return mIndex;
+ }
+
+ public boolean isUserInteracting() {
+ return mUserInteracting;
+ }
+
+ /* package */ void startInteraction(float x, float y) {
+
+ mLastTouchX = x;
+ mLastTouchY = y;
+ mUserInteracting = true;
+
+ if (DEBUG) Log.d(TAG, "initial level: " + mInitialLevel);
+ mInitialLevel = (1 - (mPosY / mParentHeight)) * (mEqManager.getMinDB() - mEqManager.getMaxDB())
+ - mEqManager.getMinDB();
+
+ updateWidth((int) (mNormalWidth * 2));
+ }
+
+ /* package */ void endInteraction() {
+ mUserInteracting = false;
+
+ updateWidth((int) mNormalWidth);
+ }
+
+ private void updateHeight(int h) {
+ if (!isInLayout()) {
+ final ViewGroup.LayoutParams params = getLayoutParams();
+ params.height = h;
+ setLayoutParams(params);
+ }
+ }
+
+ private void updateWidth(int w) {
+ final ViewGroup.LayoutParams params = getLayoutParams();
+ params.width = w;
+ setLayoutParams(params);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mEqManager.isEqualizerLocked()) {
+ return false;
+ }
+
+ final float x = event.getRawX();
+ final float y = event.getRawY() - mParentTop;
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ startInteraction(x, y);
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ // Calculate the distance moved
+ final float dx = x - mLastTouchX;
+ final float dy = y - mLastTouchY;
+
+ mPosX += dx;
+ mPosY -= dy;
+
+ // Remember this touch position for the next move event
+ mLastTouchX = x;
+ mLastTouchY = y;
+
+ int wy = (int) mParentHeight;
+ float level = (1 - (mPosY / wy)) * (mEqManager.getMinDB() - mEqManager.getMaxDB())
+ - mEqManager.getMinDB();
+
+ if (DEBUG) Log.d(TAG, "new level: " + level);
+ if (level < mEqManager.getMinDB()) {
+ level = mEqManager.getMinDB();
+ } else if (level > mEqManager.getMaxDB()) {
+ level = mEqManager.getMaxDB();
+ }
+
+ if (mInitialLevel != level) {
+ mEqManager.setLevel(getInfo().mIndex, level, false);
+ } else {
+ updateHeight();
+ }
+
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ endInteraction();
+ break;
+
+ }
+
+ return true;
+ }
+
+ public float getPosY() {
+ return mPosY;
+ }
+
+ @Override
+ public void onBandLevelChange(int band, float dB, boolean fromSystem) {
+ if (getInfo().mIndex != band) {
+ return;
+ }
+
+ updateHeight();
+ }
+
+ @Override
+ public void onPresetChanged(int newPresetIndex) {
+
+ }
+
+ @Override
+ public void onPresetsChanged() {
+
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/eq/EqContainerView.java b/src/org/cyanogenmod/audiofx/audiofx/eq/EqContainerView.java
new file mode 100644
index 0000000..51b58a6
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/eq/EqContainerView.java
@@ -0,0 +1,518 @@
+package com.cyngn.audiofx.eq;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewPropertyAnimator;
+import android.view.ViewTreeObserver;
+import android.widget.CheckBox;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.activity.StateCallbacks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class EqContainerView extends FrameLayout
+ implements StateCallbacks.EqUpdatedCallback, StateCallbacks.EqControlStateCallback {
+
+ private static final String TAG = EqContainerView.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private int mWidth;
+ private int mHeight;
+ private MasterConfigControl mConfig;
+ private EqualizerManager mEqManager;
+ private List<EqBandInfo> mBandInfo;
+ private List<EqBarView> mBarViews;
+ private List<Integer> mSelectedBands;
+
+ private CheckBox mLockBox;
+ private ImageView mRenameControl;
+ private ImageView mRemoveControl;
+ private ImageView mSaveControl;
+ private ViewGroup mControls;
+ private boolean mControlsVisible;
+
+ private boolean mSaveVisible;
+ private boolean mRemoveVisible;
+ private boolean mRenameVisible;
+ private boolean mUnlockVisible;
+
+ private int mSelectedBandColor;
+ private boolean mFirstLayout = true;
+
+ private Paint mTextPaint;
+ private Paint mFreqPaint;
+ private Paint mSelectedFreqPaint;
+ private Paint mCenterLinePaint;
+ private Path mDashPath;
+
+ private Handler mHandler;
+
+ private Runnable mVibrateRunnable = new Runnable() {
+ @Override
+ public void run() {
+ Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ v.vibrate(30);
+ }
+ };
+
+ private int mPaddingTop;
+ private int mPaddingBottom;
+ private int mBarWidth;
+ private int mBarSeparation;
+ private int mBarBottomGrabSpacePadding;
+
+ public void stopListening() {
+ for (EqBarView barView : mBarViews) {
+ barView.setTag(null);
+ mConfig.getCallbacks().removeEqUpdatedCallback(barView);
+ }
+ mConfig.getCallbacks().removeEqUpdatedCallback(this);
+ }
+
+ public void startListening() {
+ for (int i = 0; i < mBandInfo.size(); i++) {
+
+ final EqBarView eqBarView = mBarViews.get(i);
+ eqBarView.setTag(mBandInfo.get(i));
+ mConfig.getCallbacks().addEqUpdatedCallback(eqBarView);
+ }
+ mConfig.getCallbacks().addEqUpdatedCallback(this);
+ }
+
+ public static class EqBandInfo {
+ public int mIndex;
+
+ public String mFreq;
+ public String mDb;
+ public EqBarView mBar;
+ }
+
+ public EqContainerView(Context context) {
+ super(context);
+ init();
+ }
+
+ public EqContainerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public EqContainerView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void init() {
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+
+ mHandler = new Handler();
+
+ final Resources r = getResources();
+
+ mBarWidth = r.getDimensionPixelSize(R.dimen.eq_bar_width);
+ mBarSeparation = r.getDimensionPixelSize(R.dimen.separator_width);
+
+ mBarBottomGrabSpacePadding = r.getDimensionPixelSize(R.dimen.eq_bar_bottom_grab_space);
+ int freqTextSize = r.getDimensionPixelSize(R.dimen.eq_label_text_size);
+ int selectedBoxTextSize = r.getDimensionPixelSize(R.dimen.eq_selected_box_height);
+
+ int extraTopSpace = r.getDimensionPixelSize(R.dimen.eq_bar_top_padding);
+
+ mPaddingTop = selectedBoxTextSize + extraTopSpace;
+ mPaddingBottom = selectedBoxTextSize + mBarBottomGrabSpacePadding;
+
+ mConfig = MasterConfigControl.getInstance(mContext);
+ mEqManager = mConfig.getEqualizerManager();
+
+ mBarViews = new ArrayList<>();
+ mBandInfo = new ArrayList<>();
+ mSelectedBands = new ArrayList<>();
+
+ setWillNotDraw(false);
+
+ mSelectedBandColor = r.getColor(R.color.band_bar_color_selected);
+
+ mTextPaint = new Paint();
+ mTextPaint.setAntiAlias(true);
+ mTextPaint.setColor(Color.WHITE);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextPaint.setElegantTextHeight(true);
+ mTextPaint.setTextSize(selectedBoxTextSize);
+
+ mFreqPaint = new Paint();
+ mFreqPaint.setAntiAlias(true);
+ mFreqPaint.setColor(Color.WHITE);
+ mFreqPaint.setTextAlign(Paint.Align.CENTER);
+ mFreqPaint.setTextSize(freqTextSize);
+
+ mSelectedFreqPaint = new Paint(mFreqPaint);
+ mSelectedFreqPaint.setAntiAlias(true);
+ mSelectedFreqPaint.setTextSize(selectedBoxTextSize);
+
+ mCenterLinePaint = new Paint();
+ mCenterLinePaint.setColor(Color.WHITE);
+ mCenterLinePaint.setAntiAlias(true);
+ mCenterLinePaint.setPathEffect(new DashPathEffect(new float[]{6, 6}, 0));
+ mCenterLinePaint.setStyle(Paint.Style.STROKE);
+ mCenterLinePaint.setAntiAlias(true);
+
+ getViewTreeObserver().addOnGlobalLayoutListener(
+ new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ generateAndAddBars();
+ }
+ });
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return true;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ mControls = (ViewGroup) findViewById(R.id.eq_controls);
+
+ mLockBox = (CheckBox) findViewById(R.id.lock);
+ mLockBox.setOnCheckedChangeListener(mEqManager.getLockChangeListener());
+
+ mRenameControl = (ImageView) findViewById(R.id.rename);
+ mRemoveControl = (ImageView) findViewById(R.id.remove);
+ mSaveControl = (ImageView) findViewById(R.id.save);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ if (DEBUG) Log.d(TAG, "onAttachedToWindow()");
+ super.onAttachedToWindow();
+
+ mConfig.getCallbacks().addEqControlStateCallback(this);
+ onPresetChanged(mEqManager.getCurrentPresetIndex()); // update initial state
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
+ mConfig.getCallbacks().removeEqControlStateCallback(this);
+ super.onDetachedFromWindow();
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return false;
+ }
+
+ private void generateAndAddBars() {
+ if (mFirstLayout) {
+ mFirstLayout = false;
+ mBarViews.clear();
+
+ for (int i = 0; i < mEqManager.getNumBands(); i++) {
+ final EqBandInfo band = new EqBandInfo();
+ band.mIndex = i;
+ mBandInfo.add(band);
+
+ final EqBarView bar = new EqBarView(mContext);
+ band.mBar = bar;
+ bar.setTag(band);
+ bar.setOnTouchListener(new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (mEqManager.isEqualizerLocked()) {
+ return false;
+ }
+ switch (event.getActionMasked()) {
+
+ case MotionEvent.ACTION_DOWN:
+ startBarInteraction(bar);
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ stopBarInteraction(bar);
+ break;
+ }
+
+ return false;
+ }
+ });
+
+ // set correct initial alpha
+ if (i % 2 == 0) {
+ bar.setAlpha(0.6f);
+ } else {
+ bar.setAlpha(0.8f);
+ }
+ bar.setBackgroundColor(Color.WHITE);
+ bar.setElevation(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2,
+ getResources().getDisplayMetrics()));
+
+ addView(bar, getFrameParams(i));
+ bar.setParentHeight(mHeight, getTop());
+
+ final float freq = mEqManager.getCenterFreq(i);
+ String frequencyText = String.format(freq < 1000 ? "%.0f" : "%.0fk",
+ freq < 1000 ? freq : freq / 1000);
+ band.mFreq = frequencyText;
+ mBarViews.add(bar);
+ }
+ updateSelectedBands();
+ } else {
+ for (EqBarView barView : mBarViews) {
+ barView.setParentHeight(mHeight, getTop());
+ }
+ }
+ }
+
+ public EqBarView startTouchingBarUnder(MotionEvent event) {
+ EqBarView foundBar = findBar(event.getX(), event.getY(), mBarViews);
+ if (foundBar != null) {
+ foundBar.updateHeight();
+
+ foundBar.startInteraction(event.getRawX(), event.getRawY());
+ startBarInteraction(foundBar);
+ }
+ return foundBar;
+ }
+
+ public void startBarInteraction(EqBarView bar) {
+ setControlsVisible(false, false);
+ EqBandInfo band = (EqBandInfo) bar.getTag();
+ mSelectedBands.add(band.mIndex);
+ updateSelectedBands();
+ AsyncTask.execute(mVibrateRunnable);
+ }
+
+ public void stopBarInteraction(EqBarView bar) {
+ EqBandInfo band = (EqBandInfo) bar.getTag();
+ mSelectedBands.remove((Integer) band.mIndex);
+ updateSelectedBands();
+ setControlsVisible(mControlsVisible, true);
+ }
+
+ private EqBarView findBar(float x, float y, List<EqBarView> targets) {
+ final int count = targets.size();
+ for (int i = 0; i < count; i++) {
+ final EqBarView target = targets.get(i);
+ if (target.getRight() > x && target.getTop() < y
+ && target.getBottom() > y && target.getLeft() < x) {
+ return target;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ mWidth = w;
+ mHeight = h - mPaddingTop - mPaddingBottom;
+ generateAndAddBars();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ //---------------------------------------------------
+
+ if (mFirstLayout)
+ return;
+
+ int dashY = bottom - mPaddingBottom - (mHeight / 2);
+
+ final int widthOfBars = (mEqManager.getNumBands() * mBarWidth)
+ + ((mEqManager.getNumBands() - 1) * mBarSeparation);
+ final int freeSpace = mWidth - widthOfBars;
+
+ int mCurLeft = (freeSpace / 2);
+ final int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+
+ if (child instanceof EqBarView) {
+ final int childWidth = child.getMeasuredWidth();
+ final int childHeight = child.getMeasuredHeight();
+
+ int l = mCurLeft;
+ int r = l + mBarWidth;
+
+ mCurLeft += mBarWidth + mBarSeparation;
+
+ if (((EqBarView) child).isUserInteracting()) {
+ l -= childWidth / 4;
+ r += childWidth / 4;
+ }
+
+ final int layoutTop = top + mHeight - childHeight + mPaddingTop;
+ final int layoutBottom = layoutTop + childHeight
+ + mPaddingBottom - (mPaddingBottom - mBarBottomGrabSpacePadding);
+ child.layout(l, layoutTop, r, layoutBottom);
+ }
+ }
+
+ if (changed || mDashPath == null) {
+ mDashPath = new Path();
+ mDashPath.reset();
+ mDashPath.moveTo(freeSpace / 2, dashY);
+ mDashPath.lineTo(widthOfBars + (freeSpace / 2), dashY);
+ }
+
+ mControls.layout(
+ right - mControls.getMeasuredWidth() - mControls.getPaddingLeft(),
+ top + mControls.getPaddingTop(),
+ right - mControls.getPaddingRight(),
+ top + mControls.getMeasuredHeight() + mControls.getPaddingTop()
+ + mControls.getPaddingBottom()
+ );
+ }
+
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawPath(mDashPath, mCenterLinePaint);
+
+ for (int i = 0; i < mBandInfo.size(); i++) {
+ EqBandInfo info = mBandInfo.get(i);
+
+ final float x = info.mBar.getX() + (info.mBar.getWidth() / 2);
+ final boolean userInteracting = info.mBar.isUserInteracting();
+ if (userInteracting) {
+ canvas.drawText(
+ info.mDb,
+ x,
+ info.mBar.getY() - (mTextPaint.getTextSize() / 2),
+ mTextPaint);
+ }
+
+ Paint drawPaint = userInteracting ? mSelectedFreqPaint : mFreqPaint;
+
+ canvas.drawText(info.mFreq, x,
+ info.mBar.getBottom() + drawPaint.getTextSize(),
+ drawPaint);
+ }
+ }
+
+ private void updateSelectedBands() {
+ for (int i = 0; i < mEqManager.getNumBands(); i++) {
+ EqBandInfo tag = mBandInfo.get(i);
+ final EqBarView bar = (EqBarView) findViewWithTag(tag);
+ if (bar != null) {
+ final ViewPropertyAnimator barAnimation = bar.animate().withLayer();
+ if (mSelectedBands.isEmpty()) {
+ if (i % 2 == 0) {
+ barAnimation.alpha(0.6f);
+ } else {
+ barAnimation.alpha(0.8f);
+ }
+ } else if (mSelectedBands.contains(i)) {
+ barAnimation.alpha(1f);
+ bar.setBackgroundColor(mSelectedBandColor);
+ } else {
+ barAnimation.alpha(0.40f);
+ }
+ }
+ }
+ }
+
+ private FrameLayout.LayoutParams getFrameParams(int index) {
+ int width = getResources().getDimensionPixelSize(R.dimen.eq_bar_width);
+ int height = Math.round((1 - mEqManager.projectY(mEqManager.getLevel(index))) * mHeight);
+ FrameLayout.LayoutParams ll = new FrameLayout.LayoutParams(width, height);
+ ll.gravity = Gravity.TOP;
+ return ll;
+ }
+
+ @Override
+ public void onBandLevelChange(int band, float dB, boolean fromSystem) {
+ if (mFirstLayout) return;
+ mBandInfo.get(band).mDb = dB != 0 ? String.format("%+1.1f", dB) : "0.0";
+ invalidate();
+ }
+
+ @Override
+ public void onPresetChanged(int newPresetIndex) {
+ updateEqState();
+ if (mEqManager.isUserPreset()) {
+ mLockBox.setChecked(mEqManager.isEqualizerLocked());
+ }
+ }
+
+ @Override
+ public void updateEqState(boolean saveVisible, boolean removeVisible,
+ boolean renameVisible, boolean unlockVisible) {
+ mControlsVisible = mEqManager.isUserPreset() || mEqManager.isCustomPreset();
+ mSaveVisible = saveVisible;
+ mRemoveVisible = removeVisible;
+ mRenameVisible = renameVisible;
+ mUnlockVisible = unlockVisible;
+ updateEqState();
+ }
+
+ public void updateEqState() {
+ setControlsVisible(mControlsVisible && mSelectedBands.isEmpty(), false);
+
+ animateControl(mLockBox, mUnlockVisible);
+ animateControl(mRemoveControl, mRemoveVisible);
+ animateControl(mRenameControl, mRenameVisible);
+ animateControl(mSaveControl, mSaveVisible);
+ }
+
+ private void animateControl(final View v, boolean visible) {
+ if (visible) {
+ v.setVisibility(View.VISIBLE);
+ v.animate()
+ .alpha(1f)
+ .setDuration(350)
+ .withEndAction(null);
+ } else {
+ v.animate()
+ .alpha(0f)
+ .setDuration(350)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ v.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onPresetsChanged() {
+ }
+
+ public void setControlsVisible(boolean visible, boolean keepChange) {
+ if (keepChange) {
+ mControlsVisible = visible;
+ }
+
+ if (mControls != null) {
+ animateControl(mControls, visible);
+ }
+ }
+
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/eq/EqSwipeController.java b/src/org/cyanogenmod/audiofx/audiofx/eq/EqSwipeController.java
new file mode 100644
index 0000000..e96d944
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/eq/EqSwipeController.java
@@ -0,0 +1,133 @@
+package com.cyngn.audiofx.eq;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.preset.InfiniteViewPager;
+
+public class EqSwipeController extends LinearLayout {
+
+ /*
+ * x velocity max for deciding whether to try to grab a bar
+ */
+ private static final int X_VELOCITY_THRESH = 20;
+
+ private static final int MINIMUM_TIME_HOLD_TIME = 100;
+
+ EqContainerView mEq;
+ InfiniteViewPager mPager;
+ private VelocityTracker mVelocityTracker = null;
+ long mDownTime;
+ EqBarView mBar;
+ boolean mBarActive;
+ private ViewGroup mControls;
+
+ private final EqualizerManager mEqManager;
+ private float mDownPositionX;
+ private float mDownPositionY;
+
+ public EqSwipeController(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mEqManager = MasterConfigControl.getInstance(context).getEqualizerManager();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mEq = (EqContainerView) findViewById(R.id.eq_container);
+ mPager = (InfiniteViewPager) findViewById(R.id.pager);
+ mControls = (ViewGroup) findViewById(R.id.eq_controls);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ float x = event.getX();
+ float y = event.getY();
+
+ // don't intercept touches over the EQ controls
+ if (mControls.getRight() > x && mControls.getTop() < y
+ && mControls.getBottom() > y && mControls.getLeft() < x) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int index = event.getActionIndex();
+ int action = event.getActionMasked();
+ int pointerId = event.getPointerId(index);
+
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mDownPositionX = event.getRawX();
+ mDownPositionY = event.getRawY();
+ mDownTime = System.currentTimeMillis();
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ } else {
+ mVelocityTracker.clear();
+ }
+ mVelocityTracker.addMovement(event);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float xVelocity = mVelocityTracker.getXVelocity(pointerId);
+ float yVelocity = mVelocityTracker.getYVelocity(pointerId);
+
+ final float deltaX = mDownPositionX - event.getRawX();
+ final float deltaY = mDownPositionY - event.getRawY();
+ final float distanceSquared = deltaX * deltaX + deltaY * deltaY;
+
+ final ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
+ final int touchSlop = viewConfiguration.getScaledTouchSlop();
+
+ if (!mBarActive && !mEqManager.isChangingPresets()
+ && !mEqManager.isEqualizerLocked()
+ && Math.abs(xVelocity) < X_VELOCITY_THRESH
+ && System.currentTimeMillis() - mDownTime > MINIMUM_TIME_HOLD_TIME) {
+ if (distanceSquared < touchSlop * touchSlop) {
+ mBarActive = true;
+ mBar = mEq.startTouchingBarUnder(event);
+ }
+ }
+ }
+
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+
+ if (mBarActive) {
+ // reset state?
+ if (mBar != null) {
+ mEq.stopBarInteraction(mBar);
+ mBar.endInteraction();
+ }
+ }
+ mBar = null;
+ mBarActive = false;
+ break;
+ }
+ if (mBarActive && mBar != null) {
+ return mBar.onTouchEvent(event);
+ } else {
+ return mPager.onTouchEvent(event);
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/eq/EqUtils.java b/src/org/cyanogenmod/audiofx/audiofx/eq/EqUtils.java
new file mode 100644
index 0000000..30d546c
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/eq/EqUtils.java
@@ -0,0 +1,149 @@
+package com.cyngn.audiofx.eq;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import com.cyngn.audiofx.Preset;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class EqUtils {
+
+ private static final String TAG = EqUtils.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String DEFAULT_DELIMITER = ";";
+
+ public static String getZeroedBandsString(int length) {
+ return getZeroedBandsString(length, DEFAULT_DELIMITER);
+ }
+
+ public static float[] stringBandsToFloats(String input) {
+ return stringBandsToFloats(input, DEFAULT_DELIMITER);
+ }
+
+ public static String floatLevelsToString(float[] levels) {
+ return floatLevelsToString(levels, DEFAULT_DELIMITER);
+ }
+
+ public static short[] stringBandsToShorts(String input) {
+ return stringBandsToShorts(input, DEFAULT_DELIMITER);
+ }
+
+ public static String shortLevelsToString(short[] levels) {
+ return shortLevelsToString(levels, DEFAULT_DELIMITER);
+ }
+
+ public static String getZeroedBandsString(int length, final String delimiter) {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ buff.append("0").append(delimiter);
+ }
+ buff.deleteCharAt(buff.length() - 1);
+ return buff.toString();
+ }
+
+ public static String floatLevelsToString(float[] levels, final String delimiter) {
+ // save
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < levels.length; i++) {
+ builder.append(levels[i]);
+ builder.append(delimiter);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+
+
+ public static String shortLevelsToString(short[] levels, final String delimiter) {
+ // save
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < levels.length; i++) {
+ builder.append(levels[i]);
+ builder.append(delimiter);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+
+ public static String intLevelsToString(int[] levels, final String delimiter) {
+ // save
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < levels.length; i++) {
+ builder.append(levels[i]);
+ builder.append(delimiter);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+
+ public static <T> String levelsToString(T[] levels, final String delimiter) {
+ // save
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < levels.length; i++) {
+ builder.append(levels[i]);
+ builder.append(delimiter);
+ }
+ builder.deleteCharAt(builder.length() - 1);
+ return builder.toString();
+ }
+
+ public static short[] stringBandsToShorts(String input, final String delimiter) {
+ String[] levels = input.split(delimiter);
+
+ short[] equalizerLevels = new short[levels.length];
+ for (int i = 0; i < levels.length; i++) {
+ equalizerLevels[i] = (short) (Float.parseFloat(levels[i]));
+ }
+ return equalizerLevels;
+ }
+
+
+ public static float[] stringBandsToFloats(String input, final String delimiter) {
+ String[] levels = input.split(delimiter);
+
+ float[] equalizerLevels = new float[levels.length];
+ for (int i = 0; i < levels.length; i++) {
+ equalizerLevels[i] = (Float.parseFloat(levels[i]));
+ }
+ return equalizerLevels;
+ }
+
+ public static float[] convertDecibelsToMillibels(float[] decibels) {
+ if (DEBUG) Log.i(TAG, "++ convertDecibelsToMillibels(" + Arrays.toString(decibels) + ")");
+
+ float[] newvals = new float[decibels.length];
+ for (int i = 0; i < decibels.length; i++) {
+ newvals[i] = decibels[i] * 100;
+ }
+
+
+ if (DEBUG) Log.i(TAG, "-- convertDecibelsToMillibels(" + Arrays.toString(newvals) + ")");
+ return newvals;
+ }
+
+ public static short[] convertDecibelsToMillibelsInShorts(float[] decibels) {
+ if (DEBUG) Log.i(TAG, "++ convertDecibelsToMillibels(" + Arrays.toString(decibels) + ")");
+
+ short[] newvals = new short[decibels.length];
+ for (int i = 0; i < decibels.length; i++) {
+ newvals[i] = (short) (decibels[i] * 100);
+ }
+
+
+ if (DEBUG) Log.i(TAG, "-- convertDecibelsToMillibels(" + Arrays.toString(newvals) + ")");
+ return newvals;
+ }
+
+ public static float[] convertMillibelsToDecibels(float[] millibels) {
+ if (DEBUG) Log.i(TAG, "++ convertMillibelsToDecibels(" + Arrays.toString(millibels) + ")");
+ float[] newvals = new float[millibels.length];
+ for (int i = 0; i < millibels.length; i++) {
+ newvals[i] = millibels[i] / 100;
+ }
+ if (DEBUG) Log.i(TAG, "-- convertMillibelsToDecibels(" + Arrays.toString(newvals) + ")");
+ return newvals;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxBaseFragment.java b/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxBaseFragment.java
new file mode 100644
index 0000000..d487ff0
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxBaseFragment.java
@@ -0,0 +1,66 @@
+package com.cyngn.audiofx.fragment;
+
+import android.animation.Animator;
+import android.app.Fragment;
+import android.os.Bundle;
+import android.widget.CompoundButton;
+import com.cyngn.audiofx.activity.ActivityMusic;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+
+public class AudioFxBaseFragment extends Fragment {
+
+ MasterConfigControl mConfig;
+
+ AudioFxFragment mFrag;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mFrag = (AudioFxFragment) getParentFragment();
+
+ mConfig = MasterConfigControl.getInstance(getActivity());
+ }
+
+ public int getDisabledColor() {
+ return mFrag.getDisabledColor();
+ }
+
+ public int getCurrentBackgroundColor() {
+ return mFrag.mCurrentBackgroundColor;
+ }
+
+ public void animateBackgroundColorTo(Integer colorTo, Animator.AnimatorListener listener,
+ AudioFxFragment.ColorUpdateListener updateListener) {
+ if (mFrag != null) {
+ mFrag.animateBackgroundColorTo(colorTo, listener, updateListener);
+ }
+ }
+
+ /**
+ * Call to change the color and propogate it up to the activity, which will call
+ * {@link #updateFragmentBackgroundColors(int)}
+ *
+ * @param color
+ */
+ public void setBackgroundColor(int color, boolean cancelAnimated) {
+ if (mFrag != null) {
+ mFrag.updateBackgroundColors(color, cancelAnimated);
+ }
+ }
+
+ /**
+ * For sub class fragments to override and apply the color
+ *
+ * @param color the new color to apply to any colored elements
+ */
+ public void updateFragmentBackgroundColors(int color) {
+ }
+
+ /**
+ * For sub class fragments to override when they might need to update their enabled states
+ */
+ public void updateEnabledState() {
+
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxFragment.java b/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxFragment.java
new file mode 100644
index 0000000..2c9c5f5
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/fragment/AudioFxFragment.java
@@ -0,0 +1,489 @@
+package com.cyngn.audiofx.fragment;
+
+import android.animation.Animator;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.AudioDeviceInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CompoundButton;
+import com.cyngn.audiofx.Compatibility;
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.ActivityMusic;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.activity.StateCallbacks;
+import com.cyngn.audiofx.stats.UserSession;
+import com.cyngn.audiofx.widget.InterceptableLinearLayout;
+
+import java.util.List;
+import java.util.Map;
+
+public class AudioFxFragment extends Fragment implements StateCallbacks.DeviceChangedCallback {
+
+ private static final String TAG = AudioFxFragment.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final String TAG_EQUALIZER = "equalizer";
+ public static final String TAG_CONTROLS = "controls";
+
+ Handler mHandler;
+ int mCurrentBackgroundColor;
+
+ // whether we are in the middle of animating while switching devices
+ boolean mDeviceChanging;
+
+ private MenuItem mMenuDevices;
+
+ // current selected index
+ public int mSelectedPosition = 0;
+
+ EqualizerFragment mEqFragment;
+ ControlsFragment mControlFragment;
+
+ InterceptableLinearLayout mInterceptLayout;
+ private ValueAnimator mColorChangeAnimator;
+
+ private int mDisabledColor;
+
+ private MasterConfigControl mConfig;
+ private EqualizerManager mEqManager;
+
+ private AudioDeviceInfo mSystemDevice;
+ private AudioDeviceInfo mUserSelection;
+
+ private final Map<MenuItem, AudioDeviceInfo> mMenuItems = new ArrayMap<MenuItem, AudioDeviceInfo>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mConfig = MasterConfigControl.getInstance(getActivity());
+ mEqManager = mConfig.getEqualizerManager();
+
+ if (savedInstanceState != null) {
+ int user = savedInstanceState.getInt("user_device");
+ mUserSelection = mConfig.getDeviceById(user);
+ int system = savedInstanceState.getInt("system_device");
+ mSystemDevice = mConfig.getDeviceById(system);
+ }
+
+ mHandler = new Handler();
+ mDisabledColor = getResources().getColor(R.color.disabled_eq);
+
+ setHasOptionsMenu(true);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt("user_device", mUserSelection == null ? -1 : mUserSelection.getId());
+ outState.putInt("system_device", mSystemDevice == null ? -1 : mSystemDevice.getId());
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ }
+
+ private boolean showFragments() {
+ boolean createNewFrags = true;
+ final FragmentTransaction fragmentTransaction = getChildFragmentManager()
+ .beginTransaction();
+ if (mEqFragment == null) {
+ mEqFragment = (EqualizerFragment) getChildFragmentManager()
+ .findFragmentByTag(TAG_EQUALIZER);
+
+ if (mEqFragment != null) {
+ fragmentTransaction.show(mEqFragment);
+ }
+ }
+ if (mControlFragment == null) {
+ mControlFragment = (ControlsFragment) getChildFragmentManager()
+ .findFragmentByTag(TAG_CONTROLS);
+ if (mControlFragment != null) {
+ fragmentTransaction.show(mControlFragment);
+ }
+ }
+
+ if (mEqFragment != null && mControlFragment != null) {
+ createNewFrags = false;
+ }
+
+ fragmentTransaction.commit();
+
+ return createNewFrags;
+ }
+
+ @Override
+ public void onResume() {
+
+ mConfig.getCallbacks().addDeviceChangedCallback(this);
+ mConfig.bindService();
+ mConfig.setAutoBindToService(true);
+
+ updateEnabledState();
+
+ super.onResume();
+
+ mCurrentBackgroundColor = !mConfig.isCurrentDeviceEnabled()
+ ? mDisabledColor
+ : mEqManager.getAssociatedPresetColorHex(
+ mEqManager.getCurrentPresetIndex());
+ updateBackgroundColors(mCurrentBackgroundColor, false);
+
+ promptIfNotDefault();
+ }
+
+ private void promptIfNotDefault() {
+ final String audioFxPackageName = getActivity().getPackageName();
+
+ final SharedPreferences musicFxPrefs = Constants.getMusicFxPrefs(getActivity());
+ final String defaultPackage = musicFxPrefs.getString(Constants.MUSICFX_DEFAULT_PACKAGE_KEY,
+ audioFxPackageName);
+ final boolean notDefault = !defaultPackage.equals(audioFxPackageName);
+
+ if (notDefault) {
+ new AlertDialog.Builder(getActivity())
+ .setMessage(R.string.snack_bar_not_default)
+ .setNegativeButton(R.string.snack_bar_not_default_not_now,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ getActivity().finish();
+ }
+ })
+ .setPositiveButton(R.string.snack_bar_not_default_set,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent updateIntent = new Intent(getActivity(),
+ Compatibility.Service.class);
+ updateIntent.putExtra("defPackage", audioFxPackageName);
+ updateIntent.putExtra("defName", ActivityMusic.class.getName());
+ getActivity().startService(updateIntent);
+ dialog.dismiss();
+ }
+ })
+ .setCancelable(false)
+ .create()
+ .show();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ mConfig.setAutoBindToService(false);
+ mConfig.getCallbacks().removeDeviceChangedCallback(this);
+ super.onPause();
+ mConfig.unbindService();
+ }
+
+ public void updateBackgroundColors(Integer color, boolean cancelAnimated) {
+ if (cancelAnimated && mColorChangeAnimator != null) {
+ mColorChangeAnimator.cancel();
+ }
+ mCurrentBackgroundColor = color;
+ if (mEqFragment != null) {
+ mEqFragment.updateFragmentBackgroundColors(color);
+ }
+ if (mControlFragment != null) {
+ mControlFragment.updateFragmentBackgroundColors(color);
+ }
+ }
+
+ public void updateEnabledState() {
+ boolean currentDeviceEnabled = mConfig.isCurrentDeviceEnabled();
+ if (mEqFragment != null) {
+ mEqFragment.updateEnabledState();
+ }
+ if (mControlFragment != null) {
+ mControlFragment.updateEnabledState();
+ }
+
+ ((ActivityMusic) getActivity()).setGlobalToggleChecked(currentDeviceEnabled);
+
+ if (mInterceptLayout != null) {
+ mInterceptLayout.setInterception(!currentDeviceEnabled);
+ }
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.devices, menu);
+ mMenuDevices = menu.findItem(R.id.devices);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ super.onPrepareOptionsMenu(menu);
+ mMenuDevices.getSubMenu().clear();
+ mMenuItems.clear();
+
+ final AudioDeviceInfo currentDevice = mConfig.getCurrentDevice();
+
+ MenuItem selectedItem = null;
+
+ List<AudioDeviceInfo> speakerDevices = mConfig.getConnectedDevices(
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
+ if (speakerDevices.size() > 0) {
+ AudioDeviceInfo ai = speakerDevices.get(0);
+ int viewId = View.generateViewId();
+ MenuItem item = mMenuDevices.getSubMenu().add(R.id.devices, viewId,
+ Menu.NONE, MasterConfigControl.getDeviceDisplayString(getActivity(), ai));
+ item.setIcon(R.drawable.ic_action_dsp_icons_speaker);
+ mMenuItems.put(item, ai);
+ selectedItem = item;
+ }
+
+ List<AudioDeviceInfo> headsetDevices = mConfig.getConnectedDevices(
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_WIRED_HEADSET);
+ if (headsetDevices.size() > 0) {
+ AudioDeviceInfo ai = headsetDevices.get(0);
+ int viewId = View.generateViewId();
+ MenuItem item = mMenuDevices.getSubMenu().add(R.id.devices, viewId,
+ Menu.NONE, MasterConfigControl.getDeviceDisplayString(getActivity(), ai));
+ item.setIcon(R.drawable.ic_action_dsp_icons_headphones);
+ mMenuItems.put(item, ai);
+ if (currentDevice.getId() == ai.getId()) {
+ selectedItem = item;
+ }
+ }
+
+ List<AudioDeviceInfo> lineOutDevices = mConfig.getConnectedDevices(
+ AudioDeviceInfo.TYPE_LINE_ANALOG, AudioDeviceInfo.TYPE_LINE_DIGITAL);
+ if (lineOutDevices.size() > 0) {
+ AudioDeviceInfo ai = lineOutDevices.get(0);
+ int viewId = View.generateViewId();
+ MenuItem item = mMenuDevices.getSubMenu().add(R.id.devices, viewId,
+ Menu.NONE, MasterConfigControl.getDeviceDisplayString(getActivity(), ai));
+ item.setIcon(R.drawable.ic_action_dsp_icons_lineout);
+ mMenuItems.put(item, ai);
+ if (currentDevice.getId() == ai.getId()) {
+ selectedItem = item;
+ }
+ }
+
+ List<AudioDeviceInfo> bluetoothDevices = mConfig.getConnectedDevices(
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP);
+ for (AudioDeviceInfo ai : bluetoothDevices) {
+ int viewId = View.generateViewId();
+ MenuItem item = mMenuDevices.getSubMenu().add(R.id.devices, viewId,
+ Menu.NONE, MasterConfigControl.getDeviceDisplayString(getActivity(), ai));
+ item.setIcon(R.drawable.ic_action_dsp_icons_bluetoof);
+ mMenuItems.put(item, ai);
+ if (currentDevice.getId() == ai.getId()) {
+ selectedItem = item;
+ }
+ }
+
+ List<AudioDeviceInfo> usbDevices = mConfig.getConnectedDevices(
+ AudioDeviceInfo.TYPE_USB_ACCESSORY, AudioDeviceInfo.TYPE_USB_DEVICE);
+ for (AudioDeviceInfo ai : usbDevices) {
+ int viewId = View.generateViewId();
+ MenuItem item = mMenuDevices.getSubMenu().add(R.id.devices, viewId,
+ Menu.NONE, MasterConfigControl.getDeviceDisplayString(getActivity(), ai));
+ item.setIcon(R.drawable.ic_action_device_usb);
+ mMenuItems.put(item, ai);
+ if (currentDevice.getId() == ai.getId()) {
+ selectedItem = item;
+ }
+ }
+ mMenuDevices.getSubMenu().setGroupCheckable(R.id.devices, true, true);
+ selectedItem.setChecked(true);
+ mMenuDevices.setIcon(selectedItem.getIcon());
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ AudioDeviceInfo device = mMenuItems.get(item);
+
+ if (device != null) {
+ UserSession.getInstance().deviceChanged();
+ mDeviceChanging = true;
+ if (item.isCheckable()) {
+ item.setChecked(!item.isChecked());
+ }
+ mSystemDevice = mConfig.getSystemDevice();
+ mUserSelection = device;
+ getActivity().runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mConfig.setCurrentDevice(mUserSelection, true);
+ }
+ });
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ if (container == null) {
+ Log.w(TAG, "container is null.");
+ // no longer displaying this fragment
+ return null;
+ }
+
+ View root = inflater.inflate(mConfig.hasMaxxAudio()
+ ? R.layout.fragment_audiofx_maxxaudio
+ : R.layout.fragment_audiofx, container, false);
+
+ final FragmentTransaction fragmentTransaction = getChildFragmentManager()
+ .beginTransaction();
+
+ boolean createNewFrags = true;
+
+ if (savedInstanceState != null) {
+ createNewFrags = showFragments();
+ }
+
+ if (createNewFrags) {
+ fragmentTransaction.add(R.id.equalizer, mEqFragment = new EqualizerFragment(),
+ TAG_EQUALIZER);
+ fragmentTransaction.add(R.id.controls, mControlFragment = new ControlsFragment(),
+ TAG_CONTROLS);
+ }
+
+ fragmentTransaction.commit();
+
+
+ return root;
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+
+ // view was destroyed
+ final FragmentTransaction fragmentTransaction = getChildFragmentManager()
+ .beginTransaction();
+
+ if (mEqFragment != null) {
+ fragmentTransaction.remove(mEqFragment);
+ mEqFragment = null;
+ }
+ if (mControlFragment != null) {
+ fragmentTransaction.remove(mControlFragment);
+ mControlFragment = null;
+ }
+
+ fragmentTransaction.commitAllowingStateLoss();
+
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mInterceptLayout = (InterceptableLinearLayout) view.findViewById(R.id.interceptable_layout);
+ }
+
+ public void animateBackgroundColorTo(int colorTo, Animator.AnimatorListener listener,
+ ColorUpdateListener updateListener) {
+ if (mColorChangeAnimator != null) {
+ mColorChangeAnimator.cancel();
+ mColorChangeAnimator = null;
+ }
+ mColorChangeAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
+ mCurrentBackgroundColor, colorTo);
+ mColorChangeAnimator.setDuration(500);
+ mColorChangeAnimator.addUpdateListener(updateListener != null ? updateListener
+ : mColorUpdateListener);
+ if (listener != null) {
+ mColorChangeAnimator.addListener(listener);
+ }
+ mColorChangeAnimator.start();
+ }
+
+ @Override
+ public void onDeviceChanged(AudioDeviceInfo device, boolean userChange) {
+ updateEnabledState();
+ getActivity().invalidateOptionsMenu();
+ }
+
+ public CompoundButton getGlobalSwitch() {
+ return ((ActivityMusic) getActivity()).getGlobalSwitch();
+ }
+
+ @Override
+ public void onGlobalDeviceToggle(final boolean checked) {
+ final CompoundButton buttonView = getGlobalSwitch();
+ final Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ buttonView.setEnabled(false);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ updateEnabledState();
+ buttonView.setEnabled(true);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ buttonView.setEnabled(true);
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ };
+ final Integer colorTo = checked
+ ? mEqManager.getAssociatedPresetColorHex(mEqManager.getCurrentPresetIndex())
+ : mDisabledColor;
+ animateBackgroundColorTo(colorTo, animatorListener, null);
+ }
+
+ private ValueAnimator.AnimatorUpdateListener mColorUpdateListener
+ = new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ updateBackgroundColors((Integer) animation.getAnimatedValue(), false);
+ }
+ };
+
+ public static class ColorUpdateListener implements ValueAnimator.AnimatorUpdateListener {
+
+ final AudioFxBaseFragment mFrag;
+
+ public ColorUpdateListener(AudioFxBaseFragment frag) {
+ this.mFrag = frag;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mFrag.setBackgroundColor((Integer) animation.getAnimatedValue(), false);
+ }
+ }
+
+ public int getDisabledColor() {
+ return mDisabledColor;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/fragment/ControlsFragment.java b/src/org/cyanogenmod/audiofx/audiofx/fragment/ControlsFragment.java
new file mode 100644
index 0000000..02e7077
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/fragment/ControlsFragment.java
@@ -0,0 +1,103 @@
+package com.cyngn.audiofx.fragment;
+
+import android.annotation.Nullable;
+import android.media.AudioDeviceInfo;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.knobs.KnobCommander;
+import com.cyngn.audiofx.knobs.KnobContainer;
+import com.cyngn.audiofx.stats.UserSession;
+
+public class ControlsFragment extends AudioFxBaseFragment {
+
+ private static final String TAG = ControlsFragment.class.getSimpleName();
+ private static final boolean DEBUG = false;
+
+ KnobCommander mKnobCommander;
+ KnobContainer mKnobContainer;
+ CheckBox mMaxxVolumeSwitch;
+
+ private CompoundButton.OnCheckedChangeListener mMaxxVolumeListener
+ = new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mConfig.getMaxxVolumeEnabled() != isChecked) {
+ UserSession.getInstance().maxxVolumeToggled();
+ }
+ mConfig.setMaxxVolumeEnabled(isChecked);
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mKnobCommander = KnobCommander.getInstance(getActivity());
+ }
+
+ @Override
+ public void onPause() {
+ MasterConfigControl.getInstance(getActivity()).getCallbacks().removeDeviceChangedCallback(mKnobContainer);
+ super.onPause();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ MasterConfigControl.getInstance(getActivity()).getCallbacks().addDeviceChangedCallback(mKnobContainer);
+ }
+
+ @Override
+ public void updateFragmentBackgroundColors(int color) {
+ if (mKnobContainer != null) {
+ mKnobContainer.updateKnobHighlights(color);
+ }
+ }
+
+
+ public void updateEnabledState() {
+ final AudioDeviceInfo device = mConfig.getCurrentDevice();
+ boolean currentDeviceEnabled = mConfig.isCurrentDeviceEnabled();
+
+ if (DEBUG) {
+ Log.d(TAG, "updating with current device: " + device.getType());
+ }
+
+ if (mMaxxVolumeSwitch != null) {
+ mMaxxVolumeSwitch.setChecked(mConfig.getMaxxVolumeEnabled());
+ mMaxxVolumeSwitch.setEnabled(currentDeviceEnabled);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ View root = inflater.inflate(mConfig.hasMaxxAudio() ? R.layout.controls_maxx_audio
+ : R.layout.controls_generic, container, false);
+ return root;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mKnobContainer = (KnobContainer) view.findViewById(R.id.knob_container);
+ mMaxxVolumeSwitch = (CheckBox) view.findViewById(R.id.maxx_volume_switch);
+
+ updateFragmentBackgroundColors(getCurrentBackgroundColor());
+
+ if (mMaxxVolumeSwitch != null) {
+ mMaxxVolumeSwitch.setOnCheckedChangeListener(mMaxxVolumeListener);
+ }
+ }
+
+
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/fragment/EqualizerFragment.java b/src/org/cyanogenmod/audiofx/audiofx/fragment/EqualizerFragment.java
new file mode 100644
index 0000000..2d958b2
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/fragment/EqualizerFragment.java
@@ -0,0 +1,559 @@
+package com.cyngn.audiofx.fragment;
+
+import android.animation.Animator;
+import android.animation.ArgbEvaluator;
+import android.animation.ValueAnimator;
+import android.annotation.Nullable;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.graphics.drawable.ColorDrawable;
+import android.media.AudioDeviceInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.v4.view.ViewPager;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.activity.StateCallbacks;
+import com.cyngn.audiofx.eq.EqContainerView;
+import com.cyngn.audiofx.preset.InfinitePagerAdapter;
+import com.cyngn.audiofx.preset.InfiniteViewPager;
+import com.cyngn.audiofx.preset.PresetPagerAdapter;
+import com.cyngn.audiofx.stats.UserSession;
+import com.cyngn.audiofx.viewpagerindicator.CirclePageIndicator;
+
+import java.util.Arrays;
+
+public class EqualizerFragment extends AudioFxBaseFragment
+ implements StateCallbacks.DeviceChangedCallback, StateCallbacks.EqUpdatedCallback {
+
+ private static final String TAG = EqualizerFragment.class.getSimpleName();
+ private static final boolean DEBUG = false;
+ private static final boolean DEBUG_VIEWPAGER = true;
+
+ private final ArgbEvaluator mArgbEval = new ArgbEvaluator();
+
+ public EqContainerView mEqContainer;
+ InfiniteViewPager mPresetPager;
+ CirclePageIndicator mPresetPageIndicator;
+ PresetPagerAdapter mDataAdapter;
+ InfinitePagerAdapter mInfiniteAdapter;
+ int mCurrentRealPage;
+
+ private Handler mHandler;
+
+ // whether we are in the middle of animating while switching devices
+ boolean mDeviceChanging;
+
+ private ViewPager mFakePager;
+
+ private int mAnimatingToRealPageTarget = -1;
+
+ /*
+ * this array can hold on to arrays which store preset levels,
+ * so modifying values in here should only be done with extreme care
+ */
+ private float[] mSelectedPositionBands;
+
+ // current selected index
+ public int mSelectedPosition = 0;
+
+ private MasterConfigControl mConfig;
+ private EqualizerManager mEqManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mConfig = MasterConfigControl.getInstance(getActivity());
+ mEqManager = mConfig.getEqualizerManager();
+
+ mHandler = new Handler();
+ }
+
+ @Override
+ public void onPause() {
+ mEqContainer.stopListening();
+ mConfig.getCallbacks().removeDeviceChangedCallback(this);
+ mConfig.getCallbacks().removeEqUpdatedCallback(this);
+ super.onPause();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mEqContainer.startListening();
+ mConfig.getCallbacks().addEqUpdatedCallback(this);
+ mConfig.getCallbacks().addDeviceChangedCallback(this);
+ mPresetPageIndicator.notifyDataSetChanged();
+ mDataAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void updateFragmentBackgroundColors(int color) {
+ if (getActivity() != null && getActivity().getWindow() != null) {
+ getActivity().getWindow().setBackgroundDrawable(new ColorDrawable(color));
+ }
+ }
+
+ public void jumpToPreset(int index) {
+ int diff = index - (mCurrentRealPage % mDataAdapter.getCount());
+ // double it, short (e.g. 1 hop) distances sometimes bug out??
+ diff += mDataAdapter.getCount();
+ int newPage = mCurrentRealPage + diff;
+ mPresetPager.setCurrentItemAbsolute(newPage, false);
+ }
+
+ private void removeCurrentCustomPreset(boolean showWarning) {
+ if (showWarning) {
+ Preset p = mEqManager.getCurrentPreset();
+ new AlertDialog.Builder(getActivity())
+ .setMessage(String.format(getString(
+ R.string.remove_custom_preset_warning_message), p.getName()))
+ .setNegativeButton(android.R.string.no, null)
+ .setPositiveButton(android.R.string.yes,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ removeCurrentCustomPreset(false);
+ }
+ })
+ .create()
+ .show();
+ return;
+ }
+
+ final int currentIndexBeforeRemove = mEqManager.getCurrentPresetIndex();
+ if (mEqManager.removePreset(currentIndexBeforeRemove)) {
+ mInfiniteAdapter.notifyDataSetChanged();
+ mDataAdapter.notifyDataSetChanged();
+ mPresetPageIndicator.notifyDataSetChanged();
+
+ jumpToPreset(mSelectedPosition - 1);
+ }
+ }
+
+ private void openRenameDialog() {
+ AlertDialog.Builder renameDialog = new AlertDialog.Builder(getActivity());
+ renameDialog.setTitle(R.string.rename);
+ final EditText newName = new EditText(getActivity());
+ newName.setText(mEqManager.getCurrentPreset().getName());
+ renameDialog.setView(newName);
+ renameDialog.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface d, int which) {
+ mEqManager.renameCurrentPreset(newName.getText().toString());
+ final TextView viewWithTag = (TextView) mPresetPager
+ .findViewWithTag(mEqManager.getCurrentPreset());
+ viewWithTag.setText(newName.getText().toString());
+ mDataAdapter.notifyDataSetChanged();
+ mPresetPager.invalidate();
+ }
+ });
+
+ renameDialog.setNegativeButton(android.R.string.cancel,
+ new DialogInterface.OnClickListener() {
+
+ public void onClick(DialogInterface d, int which) {
+ }
+ });
+
+ // disable ok button if text is empty
+ final AlertDialog dialog = renameDialog.create();
+ newName.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (s.length() == 0) {
+ dialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(false);
+ } else {
+ dialog.getButton(Dialog.BUTTON_POSITIVE).setEnabled(true);
+ }
+ }
+ });
+
+ dialog.show();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ Bundle savedInstanceState) {
+ View root = inflater.inflate(R.layout.equalizer, container, false);
+ return root;
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mSelectedPositionBands = mEqManager.getPersistedPresetLevels(mEqManager.getCurrentPresetIndex());
+ mSelectedPosition = mEqManager.getCurrentPresetIndex();
+
+ mEqContainer = (EqContainerView) view.findViewById(R.id.eq_container);
+ mPresetPager = (InfiniteViewPager) view.findViewById(R.id.pager);
+ mPresetPageIndicator = (CirclePageIndicator) view.findViewById(R.id.indicator);
+ mFakePager = (ViewPager) view.findViewById(R.id.fake_pager);
+
+ mEqContainer.findViewById(R.id.save).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+
+ final int newidx = mEqManager.addPresetFromCustom();
+ mInfiniteAdapter.notifyDataSetChanged();
+ mDataAdapter.notifyDataSetChanged();
+ mPresetPageIndicator.notifyDataSetChanged();
+
+ jumpToPreset(newidx);
+ }
+ }
+ );
+ mEqContainer.findViewById(R.id.rename).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mEqManager.isUserPreset()) {
+ openRenameDialog();
+ }
+ }
+ }
+ );
+ mEqContainer.findViewById(R.id.remove).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ removeCurrentCustomPreset(true);
+ }
+ }
+ );
+
+ mDataAdapter = new PresetPagerAdapter(getActivity());
+ mInfiniteAdapter = new InfinitePagerAdapter(mDataAdapter);
+
+ mPresetPager.setAdapter(mInfiniteAdapter);
+ mPresetPager.setOnPageChangeListener(mViewPageChangeListener);
+
+ mFakePager.setAdapter(mDataAdapter);
+ mCurrentRealPage = mPresetPager.getCurrentItem();
+
+ mPresetPageIndicator.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // eat all events
+ return true;
+ }
+ });
+ mPresetPageIndicator.setSnap(true);
+
+ mPresetPageIndicator.setViewPager(mFakePager, 0);
+ mPresetPageIndicator.setCurrentItem(mSelectedPosition);
+
+ mFakePager.setCurrentItem(mSelectedPosition);
+ mPresetPager.setCurrentItem(mSelectedPosition);
+ }
+
+ @Override
+ public void onBandLevelChange(int band, float dB, boolean fromSystem) {
+ // call backs we get when bands are changing, check if the user is physically touching them
+ // and set the preset to "custom" and do proper animations.
+ if (!fromSystem) { // from user
+ if (!mEqManager.isCustomPreset() // not on custom already
+ && !mEqManager.isUserPreset() // or not on a user preset
+ && !mEqManager.isAnimatingToCustom()) { // and animation hasn't started
+ if (DEBUG) Log.w(TAG, "met conditions to start an animation to custom trigger");
+ // view pager is infinite, so we can't set the item to 0. find NEXT 0
+ mEqManager.setAnimatingToCustom(true);
+
+ final int newIndex = mEqManager.copyToCustom();
+
+ mInfiniteAdapter.notifyDataSetChanged();
+ mDataAdapter.notifyDataSetChanged();
+ mPresetPager.getAdapter().notifyDataSetChanged();
+ // do background transition manually as viewpager can't handle this bg change
+ final Integer colorTo = !mConfig.isCurrentDeviceEnabled()
+ ? getDisabledColor()
+ : mEqManager.getAssociatedPresetColorHex(newIndex);
+ final Animator.AnimatorListener listener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ int diff = newIndex - (mCurrentRealPage % mDataAdapter.getCount());
+ diff += mDataAdapter.getCount();
+ int newPage = mCurrentRealPage + diff;
+
+ mAnimatingToRealPageTarget = newPage;
+ mPresetPager.setCurrentItemAbsolute(newPage);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ };
+ animateBackgroundColorTo(colorTo, listener, null);
+
+ }
+ mSelectedPositionBands[band] = dB;
+ }
+ }
+
+ @Override
+ public void onPresetChanged(int newPresetIndex) {
+ }
+
+ @Override
+ public void onPresetsChanged() {
+ mDataAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onDeviceChanged(AudioDeviceInfo device, boolean userChange) {
+ int diff = mEqManager.getCurrentPresetIndex() - mSelectedPosition;
+ final boolean samePage = diff == 0;
+ diff = mDataAdapter.getCount() + diff;
+ if (DEBUG) {
+ Log.d(TAG, "diff: " + diff);
+ }
+ mCurrentRealPage = mPresetPager.getCurrentItem();
+
+ if (DEBUG) Log.d(TAG, "mCurrentRealPage Before: " + mCurrentRealPage);
+ final int newPage = mCurrentRealPage + diff;
+ if (DEBUG) Log.d(TAG, "mCurrentRealPage After: " + newPage);
+
+ mSelectedPositionBands = mEqManager.getPresetLevels(mSelectedPosition);
+ final float[] targetBandLevels = mEqManager.getPresetLevels(mEqManager.getCurrentPresetIndex());
+
+ // do background transition manually as viewpager can't handle this bg change
+ final Integer colorTo = !mConfig.isCurrentDeviceEnabled()
+ ? getDisabledColor()
+ : mEqManager.getAssociatedPresetColorHex(mEqManager.getCurrentPresetIndex());
+
+ final Animator.AnimatorListener animatorListener = new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mEqManager.setChangingPresets(true);
+
+ mDeviceChanging = true;
+
+ if (!samePage) {
+ mPresetPager.setCurrentItemAbsolute(newPage);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mEqManager.setChangingPresets(false);
+
+ mSelectedPosition = mEqManager.getCurrentPresetIndex();
+ mSelectedPositionBands = mEqManager.getPresetLevels(mSelectedPosition);
+
+ mDeviceChanging = false;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ };
+
+ final AudioFxFragment.ColorUpdateListener animatorUpdateListener
+ = new AudioFxFragment.ColorUpdateListener(this) {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animator) {
+ super.onAnimationUpdate(animator);
+
+ final int N = mEqManager.getNumBands();
+ for (int i = 0; i < N; i++) { // animate bands
+ float delta = targetBandLevels[i] - mSelectedPositionBands[i];
+ float newBandLevel = mSelectedPositionBands[i]
+ + (delta * animator.getAnimatedFraction());
+ //if (DEBUG_VIEWPAGER) Log.d(TAG, i + ", delta: " + delta + ", newBandLevel: " + newBandLevel);
+ mEqManager.setLevel(i, newBandLevel, true);
+ }
+ }
+ };
+
+ animateBackgroundColorTo(colorTo, animatorListener, animatorUpdateListener);
+ }
+
+ @Override
+ public void onGlobalDeviceToggle(boolean on) {
+ if (!on) {
+ mFakePager.setCurrentItem(mFakePager.getCurrentItem(), true);
+ }
+ }
+
+
+ private ViewPager.OnPageChangeListener mViewPageChangeListener = new ViewPager.OnPageChangeListener() {
+
+ int mState;
+ float mLastOffset;
+ boolean mJustGotToCustomAndSettling;
+
+ @Override
+ public void onPageScrolled(int newPosition, float positionOffset, int positionOffsetPixels) {
+ if (DEBUG_VIEWPAGER)
+ Log.i(TAG, "onPageScrolled(" + newPosition + ", " + positionOffset + ", "
+ + positionOffsetPixels + ")");
+ Integer colorFrom;
+ Integer colorTo;
+
+ if (newPosition == mAnimatingToRealPageTarget && mEqManager.isAnimatingToCustom()) {
+ if (DEBUG_VIEWPAGER) Log.w(TAG, "settling var set to true");
+ mJustGotToCustomAndSettling = true;
+ mAnimatingToRealPageTarget = -1;
+ }
+
+ newPosition = newPosition % mDataAdapter.getCount();
+
+
+ if (mEqManager.isAnimatingToCustom() || mDeviceChanging) {
+ if (DEBUG_VIEWPAGER)
+ Log.i(TAG, "ignoring onPageScrolled because animating to custom or device is changing");
+ return;
+ }
+
+ int toPos;
+ if (mLastOffset - positionOffset > 0.8) { // this is needed for flings
+ //Log.e(TAG, "OFFSET DIFF > 0.8! Setting selected position from: " + mSelectedPosition + " to " + newPosition);
+ mSelectedPosition = newPosition;
+ // mSelectedPositionBands will be reset by setPreset() below calling back to onPresetChanged()
+
+ mEqManager.setPreset(mSelectedPosition);
+ }
+
+ if (newPosition < mSelectedPosition || (newPosition == mDataAdapter.getCount() - 1)
+ && mSelectedPosition == 0) {
+ // scrolling left <<<<<
+ positionOffset = (1 - positionOffset);
+ //Log.v(TAG, "<<<<<< positionOffset: " + positionOffset + " (last offset: " + mLastOffset + ")");
+ toPos = newPosition;
+ colorTo = mEqManager.getAssociatedPresetColorHex(toPos);
+ } else {
+ // scrolling right >>>>>
+ //Log.v(TAG, ">>>>>>> positionOffset: " + positionOffset + " (last offset: " + mLastOffset + ")");
+ toPos = newPosition + 1 % mDataAdapter.getCount();
+ if (toPos >= mDataAdapter.getCount()) {
+ toPos = 0;
+ }
+
+ colorTo = mEqManager.getAssociatedPresetColorHex(toPos);
+ }
+
+ if (!mDeviceChanging && mConfig.isCurrentDeviceEnabled()) {
+ colorFrom = mEqManager.getAssociatedPresetColorHex(mSelectedPosition);
+ setBackgroundColor((Integer) mArgbEval.evaluate(positionOffset, colorFrom, colorTo),
+ true);
+ }
+
+ if (mSelectedPositionBands == null) {
+ mSelectedPositionBands = mEqManager.getPresetLevels(mSelectedPosition);
+ }
+ // get current bands
+ float[] finalPresetLevels = mEqManager.getPresetLevels(toPos);
+
+ final int N = mEqManager.getNumBands();
+ for (int i = 0; i < N; i++) { // animate bands
+ float delta = finalPresetLevels[i] - mSelectedPositionBands[i];
+ float newBandLevel = mSelectedPositionBands[i] + (delta * positionOffset);
+ //if (DEBUG_VIEWPAGER) Log.d(TAG, i + ", delta: " + delta + ", newBandLevel: " + newBandLevel);
+ mEqManager.setLevel(i, newBandLevel, true);
+ }
+ mLastOffset = positionOffset;
+
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (DEBUG_VIEWPAGER) Log.i(TAG, "onPageSelected(" + position + ")");
+ mCurrentRealPage = position;
+ position = position % mDataAdapter.getCount();
+ if (DEBUG_VIEWPAGER) Log.e(TAG, "onPageSelected(" + position + ")");
+ mFakePager.setCurrentItem(position);
+ mSelectedPosition = position;
+ if (!mDeviceChanging) {
+ mSelectedPositionBands = mEqManager.getPresetLevels(mSelectedPosition);
+ if (UserSession.getInstance() != null) {
+ UserSession.getInstance().presetSelected();
+ }
+ }
+ }
+
+
+ @Override
+ public void onPageScrollStateChanged(int newState) {
+ mState = newState;
+ if (mDeviceChanging) { // avoid setting unwanted presets during custom animations
+ return;
+ }
+ if (DEBUG_VIEWPAGER)
+ Log.w(TAG, "onPageScrollStateChanged(" + stateToString(newState) + ")");
+
+ if (mJustGotToCustomAndSettling && mState == ViewPager.SCROLL_STATE_IDLE) {
+ if (DEBUG_VIEWPAGER)
+ Log.w(TAG, "onPageScrollChanged() setting animating to custom = false");
+ mJustGotToCustomAndSettling = false;
+ mEqManager.setChangingPresets(false);
+ mEqManager.setAnimatingToCustom(false);
+ } else {
+ if (mState == ViewPager.SCROLL_STATE_IDLE) {
+ animateBackgroundColorTo(!mConfig.isCurrentDeviceEnabled()
+ ? getDisabledColor()
+ : mEqManager.getAssociatedPresetColorHex(mSelectedPosition),
+ null, null);
+
+ mEqManager.setChangingPresets(false);
+ mEqManager.setPreset(mSelectedPosition);
+
+ } else {
+ // not idle
+ mEqManager.setChangingPresets(true);
+ }
+ }
+ }
+
+ private String stateToString(int state) {
+ switch (state) {
+ case 0:
+ return "STATE_IDLE";
+ case 1:
+ return "STATE_DRAGGING";
+ case 2:
+ return "STATE_SETTLING";
+ default:
+ return "STATE_WUT";
+ }
+ }
+
+ };
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobCommander.java b/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobCommander.java
new file mode 100644
index 0000000..b045c16
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobCommander.java
@@ -0,0 +1,177 @@
+package com.cyngn.audiofx.knobs;
+
+import android.content.Context;
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.service.AudioFxService;
+
+public class KnobCommander {
+
+ public static final int KNOB_TREBLE = 0;
+ public static final int KNOB_BASS = 1;
+ public static final int KNOB_VIRTUALIZER = 2;
+
+ private static KnobCommander sInstance;
+
+ private Context mContext;
+ private MasterConfigControl mConfig;
+
+ private KnobCommander(Context context) {
+ mContext = context;
+ mConfig = MasterConfigControl.getInstance(mContext);
+ }
+
+ public static KnobCommander getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new KnobCommander(context);
+ }
+ return sInstance;
+ }
+
+ public RadialKnob.OnKnobChangeListener getRadialKnobCallback(int whichKnob) {
+ switch (whichKnob) {
+ case KNOB_TREBLE: return mTrebleKnobCallback;
+ case KNOB_BASS: return mBassKnobCallback;
+ case KNOB_VIRTUALIZER: return mVirtualizerCallback;
+ default: return null;
+ }
+ }
+
+ public void updateTrebleKnob(RadialKnob trebleKnob, boolean enabled) {
+ if (trebleKnob != null) {
+ trebleKnob.setValue(getTrebleStrength());
+ trebleKnob.setOn(isTrebleEffectEnabled());
+ trebleKnob.setEnabled(enabled);
+ }
+ }
+
+ public void updateBassKnob(RadialKnob bassKnob, boolean enabled) {
+ if (bassKnob != null) {
+ bassKnob.setValue(getBassStrength());
+ bassKnob.setOn(isBassEffectEnabled());
+ bassKnob.setEnabled(enabled);
+ }
+ }
+
+ public void updateVirtualizerKnob(RadialKnob virtualizerKnob, boolean enabled) {
+ if (virtualizerKnob != null) {
+ virtualizerKnob.setValue(getVirtualizerStrength());
+ virtualizerKnob.setOn(isVirtualizerEffectEnabled());
+ virtualizerKnob.setEnabled(enabled);
+ }
+ }
+
+ public boolean hasBassBoost() {
+ return mConfig.hasBassBoost();
+ }
+
+ public boolean hasTreble() {
+ return mConfig.hasMaxxAudio() || mConfig.hasDts();
+ }
+
+ public boolean hasVirtualizer() {
+ return mConfig.hasVirtualizer();
+ }
+
+ public boolean isBassEffectEnabled() {
+ return mConfig.getPrefs().getBoolean(Constants.DEVICE_AUDIOFX_BASS_ENABLE, false);
+ }
+
+ public boolean isTrebleEffectEnabled() {
+ return mConfig.getPrefs().getBoolean(Constants.DEVICE_AUDIOFX_TREBLE_ENABLE, false);
+ }
+
+ public boolean isVirtualizerEffectEnabled() {
+ return mConfig.getPrefs().getBoolean(Constants.DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, false);
+ }
+
+ public int getVirtualizerStrength() {
+ return Integer.valueOf(mConfig.getPrefs().getString(Constants.DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "0")) / 10;
+ }
+
+ public int getBassStrength() {
+ return Integer.valueOf(mConfig.getPrefs().getString(Constants.DEVICE_AUDIOFX_BASS_STRENGTH, "0")) / 10;
+ }
+
+ public int getTrebleStrength() {
+ return Integer.valueOf(mConfig.getPrefs().getString(Constants.DEVICE_AUDIOFX_TREBLE_STRENGTH, "0"));
+ }
+
+ public void setTrebleEnabled(boolean on) {
+ mConfig.getPrefs().edit().putBoolean(Constants.DEVICE_AUDIOFX_TREBLE_ENABLE, on).apply();
+ mConfig.updateService(AudioFxService.TREBLE_BOOST_CHANGED);
+ }
+
+ public void setTrebleStrength(int value) {
+ // set parameter and state
+ mConfig.getPrefs().edit().putString(Constants.DEVICE_AUDIOFX_TREBLE_STRENGTH, String.valueOf(value)).apply();
+ mConfig.updateService(AudioFxService.TREBLE_BOOST_CHANGED);
+ }
+
+ public void setBassEnabled(boolean on) {
+ mConfig.getPrefs().edit().putBoolean(Constants.DEVICE_AUDIOFX_BASS_ENABLE, on).apply();
+ mConfig.updateService(AudioFxService.BASS_BOOST_CHANGED);
+ }
+
+ public void setBassStrength(int value) {
+ // set parameter and state
+ mConfig.getPrefs().edit().putString(Constants.DEVICE_AUDIOFX_BASS_STRENGTH, String.valueOf(value * 10)).apply();
+ mConfig.updateService(AudioFxService.BASS_BOOST_CHANGED);
+ }
+
+ public void setVirtualizerEnabled(boolean on) {
+ mConfig.getPrefs().edit().putBoolean(Constants.DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, on).apply();
+ mConfig.updateService(AudioFxService.VIRTUALIZER_CHANGED);
+ }
+
+ public void setVirtualiserStrength(int value) {
+ // set parameter and state
+ mConfig.getPrefs().edit().putString(Constants.DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, String.valueOf(value * 10)).apply();
+ mConfig.updateService(AudioFxService.VIRTUALIZER_CHANGED);
+ }
+
+ private RadialKnob.OnKnobChangeListener mTrebleKnobCallback = new RadialKnob.OnKnobChangeListener() {
+ @Override
+ public void onValueChanged(RadialKnob knob, int value, boolean fromUser) {
+ if (fromUser) {
+ setTrebleStrength(value);
+ }
+ }
+
+ @Override
+ public boolean onSwitchChanged(RadialKnob knob, boolean on) {
+ setTrebleEnabled(on);
+ return true;
+ }
+ };
+
+ private RadialKnob.OnKnobChangeListener mBassKnobCallback = new RadialKnob.OnKnobChangeListener() {
+ @Override
+ public void onValueChanged(RadialKnob knob, int value, boolean fromUser) {
+ if (fromUser) {
+ setBassStrength(value);
+ }
+ }
+
+ @Override
+ public boolean onSwitchChanged(RadialKnob knob, boolean on) {
+ setBassEnabled(on);
+ return true;
+ }
+ };
+
+ private RadialKnob.OnKnobChangeListener mVirtualizerCallback = new RadialKnob.OnKnobChangeListener() {
+ @Override
+ public void onValueChanged(RadialKnob knob, int value, boolean fromUser) {
+ if (fromUser) {
+ setVirtualiserStrength(value);
+ }
+ }
+
+ @Override
+ public boolean onSwitchChanged(RadialKnob knob, boolean on) {
+ setVirtualizerEnabled(on);
+ return true;
+ }
+ };
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobContainer.java b/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobContainer.java
new file mode 100644
index 0000000..91e811b
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/knobs/KnobContainer.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cyngn.audiofx.knobs;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.media.AudioDeviceInfo;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.activity.StateCallbacks;
+
+public class KnobContainer extends LinearLayout
+ implements StateCallbacks.DeviceChangedCallback {
+
+ private static final String TAG = KnobContainer.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final int NOTIFY_DISABLE_DELAY = 5000;
+
+ private static final int MSG_EXPAND = 0;
+ private static final int MSG_CONTRACT = 1;
+
+ private ViewGroup mTrebleContainer;
+ private ViewGroup mBassContainer;
+ private ViewGroup mVirtualizerContainer;
+ private RadialKnob mTrebleKnob;
+ private RadialKnob mBassKnob;
+ private RadialKnob mVirtualizerKnob;
+
+ private H mHandler;
+
+ private KnobCommander mKnobCommander;
+
+ private long mLastDisabledNotifyTime = -1;
+
+ public KnobContainer(Context context) {
+ super(context);
+ }
+
+ public KnobContainer(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public KnobContainer(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ private void init() {
+ mKnobCommander = KnobCommander.getInstance(mContext);
+ mHandler = new H();
+
+ if (!MasterConfigControl.getInstance(mContext).hasMaxxAudio()) {
+ // we must add the proper knobs dynamically.
+ if (mKnobCommander.hasBassBoost()) {
+ mBassContainer = addKnob(KnobCommander.KNOB_BASS);
+ }
+ if (mKnobCommander.hasTreble()) {
+ mTrebleContainer = addKnob(KnobCommander.KNOB_TREBLE);
+ }
+ if (mKnobCommander.hasVirtualizer()) {
+ mVirtualizerContainer = addKnob(KnobCommander.KNOB_VIRTUALIZER);
+ }
+ }
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ init();
+
+ if (DEBUG) Log.d(TAG, "onFinishInflate()");
+
+ OnTouchListener knobTouchListener = new OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ Message message;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ message = mHandler.obtainMessage(MSG_EXPAND, v.getTag());
+ mHandler.sendMessageDelayed(message, 0);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mHandler.removeMessages(MSG_EXPAND);
+ message = mHandler.obtainMessage(MSG_CONTRACT, v.getTag());
+ mHandler.sendMessageDelayed(message, 10);
+ break;
+ }
+ if (!v.isEnabled()) {
+ notifyDisabled();
+ return true;
+ }
+ return false;
+ }
+ };
+
+ if (MasterConfigControl.getInstance(getContext()).hasMaxxAudio()) {
+ mVirtualizerContainer = (ViewGroup) findViewById(R.id.virtualizer_knob_container);
+ mBassContainer = (ViewGroup) findViewById(R.id.bass_knob_container);
+ mTrebleContainer = (ViewGroup) findViewById(R.id.treble_knob_container);
+ }
+
+ if (mTrebleContainer != null) {
+ mTrebleKnob = (RadialKnob) mTrebleContainer.findViewById(R.id.knob);
+ mTrebleKnob.setTag(new KnobInfo(KnobCommander.KNOB_TREBLE, mTrebleKnob,
+ mTrebleContainer.findViewById(R.id.label)));
+ mTrebleKnob.setOnTouchListener(knobTouchListener);
+ mTrebleKnob.setOnKnobChangeListener(
+ KnobCommander.getInstance(getContext()).getRadialKnobCallback(
+ KnobCommander.KNOB_TREBLE
+ )
+ );
+ mTrebleKnob.setMax(100);
+ }
+ if (mBassContainer != null) {
+ mBassKnob = (RadialKnob) mBassContainer.findViewById(R.id.knob);
+ mBassKnob.setTag(new KnobInfo(KnobCommander.KNOB_BASS, mBassKnob, mBassContainer.findViewById(R.id.label)));
+ mBassKnob.setOnTouchListener(knobTouchListener);
+ mBassKnob.setOnKnobChangeListener(
+ KnobCommander.getInstance(getContext()).getRadialKnobCallback(
+ KnobCommander.KNOB_BASS
+ )
+ );
+ mBassKnob.setMax(100);
+
+
+ }
+ if (mVirtualizerContainer != null) {
+ mVirtualizerKnob = (RadialKnob) mVirtualizerContainer.findViewById(R.id.knob);
+ mVirtualizerKnob.setTag(new KnobInfo(KnobCommander.KNOB_VIRTUALIZER, mVirtualizerKnob,
+ mVirtualizerContainer.findViewById(R.id.label)));
+ mVirtualizerKnob.setOnTouchListener(knobTouchListener);
+ mVirtualizerKnob.setOnKnobChangeListener(
+ KnobCommander.getInstance(getContext()).getRadialKnobCallback(
+ KnobCommander.KNOB_VIRTUALIZER
+ )
+ );
+ mVirtualizerKnob.setMax(100);
+ }
+ updateKnobs(MasterConfigControl.getInstance(mContext).getCurrentDevice());
+
+ if (!MasterConfigControl.getInstance(mContext).hasMaxxAudio()) {
+ setLayoutTransition(null);
+ }
+ }
+
+ private ViewGroup addKnob(int whichKnob) {
+ ViewGroup knobContainer = (ViewGroup) LayoutInflater.from(mContext)
+ .inflate(R.layout.generic_knob_control, this, false);
+ TextView label = (TextView) knobContainer.findViewById(R.id.label);
+
+ int newContainerId = 0;
+ int knobLabelRes = 0;
+ switch (whichKnob) {
+ case KnobCommander.KNOB_BASS:
+ newContainerId = R.id.bass_knob_container;
+ knobLabelRes = R.string.bass;
+ break;
+
+ case KnobCommander.KNOB_TREBLE:
+ newContainerId = R.id.treble_knob_container;
+ knobLabelRes = R.string.treble;
+ break;
+
+ case KnobCommander.KNOB_VIRTUALIZER:
+ newContainerId = R.id.virtualizer_knob_container;
+ knobLabelRes = R.string.virtualizer;
+ break;
+
+ default:
+ return null;
+ }
+
+ knobContainer.setId(newContainerId);
+ label.setText(knobLabelRes);
+
+ addView(knobContainer, getKnobParams());
+ return knobContainer;
+ }
+
+ private LayoutParams getKnobParams() {
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ } else {
+ return new LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1);
+ }
+ }
+
+ public void setKnobVisible(int knob, boolean visible) {
+ final int newMode = visible ? View.VISIBLE : View.GONE;
+ ViewGroup v = null;
+ switch (knob) {
+ case KnobCommander.KNOB_VIRTUALIZER:
+ v = mVirtualizerContainer;
+ break;
+ case KnobCommander.KNOB_BASS:
+ v = mBassContainer;
+ break;
+ case KnobCommander.KNOB_TREBLE:
+ v = mTrebleContainer;
+ break;
+ }
+ if (v == null && visible) {
+ throw new UnsupportedOperationException("no knob container for knob: " + knob);
+ }
+
+ if (newMode == v.getVisibility()) {
+ return;
+ }
+ Log.d(TAG, "setKnobVisible() knob=" + knob + " visible=" + visible);
+ v.setVisibility(newMode);
+
+ // only used on maxx audio layout
+ if (MasterConfigControl.getInstance(mContext).hasMaxxAudio()) {
+ /* ensure spacing looks ok!
+ *
+ * it goes like, Space, knob layout, Space, knob layout, Space, etc.....
+ * starting with the first knob (skipping the first space), ensure the pairs have the
+ * same visibility so there's no extra space at the end.
+ */
+ for (int i = 1; i < getChildCount() - 1; i += 2) {
+ View layout = getChildAt(i);
+ View space = getChildAt(i + 1);
+ if (space.getVisibility() != layout.getVisibility()) {
+ space.setVisibility(layout.getVisibility());
+ }
+ }
+ }
+ }
+
+ public void updateKnobHighlights(int color) {
+ if (mTrebleKnob != null) {
+ mTrebleKnob.setHighlightColor(color);
+ }
+ if (mBassKnob != null) {
+ mBassKnob.setHighlightColor(color);
+ }
+ if (mVirtualizerKnob != null) {
+ mVirtualizerKnob.setHighlightColor(color);
+ }
+ }
+
+ private void notifyDisabled() {
+ final long now = System.currentTimeMillis();
+ if (mLastDisabledNotifyTime == -1 || now - mLastDisabledNotifyTime > NOTIFY_DISABLE_DELAY) {
+ mLastDisabledNotifyTime = now;
+ Toast.makeText(mContext, R.string.effect_unavalable_for_speaker,
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public boolean shouldDelayChildPressedState() {
+ return false;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ private void resize(RadialKnob knob, View label, boolean makeBig) {
+ if (knob.isEnabled()) {
+ label.animate()
+ .alpha(makeBig ? 0 : 1)
+ .setInterpolator(new AccelerateInterpolator())
+ .setDuration(100);
+
+ /*
+ if (makeBig) {
+ ResizeAnimation resizeAnimation = new ResizeAnimation(this);
+ resizeAnimation.setHeightParams(getHeight(), mExpandedHeight);
+ resizeAnimation.setDuration(100);
+ startAnimation(resizeAnimation);
+ } else {
+ ResizeAnimation resizeAnimation = new ResizeAnimation(this);
+ resizeAnimation.setHeightParams(getHeight(), mRegularHeight);
+ resizeAnimation.setDuration(100);
+ startAnimation(resizeAnimation);
+ }
+ */
+ knob.resize(makeBig);
+ }
+ }
+
+ @Override
+ public void onDeviceChanged(AudioDeviceInfo device, boolean userChange) {
+ if (device != null) {
+ updateKnobs(device);
+ }
+ }
+
+ @Override
+ public void onGlobalDeviceToggle(boolean on) {
+
+ }
+
+ private void updateKnobs(AudioDeviceInfo device) {
+ if (device == null) {
+ return;
+ }
+ final boolean speaker = device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER;
+ final boolean maxxAudio = MasterConfigControl.getInstance(mContext).hasMaxxAudio();
+ final boolean dts = MasterConfigControl.getInstance(mContext).hasDts();
+ final boolean effectsEnabled = !speaker || maxxAudio || dts;
+
+ mKnobCommander.updateTrebleKnob(mTrebleKnob, effectsEnabled);
+ mKnobCommander.updateBassKnob(mBassKnob, effectsEnabled);
+ mKnobCommander.updateVirtualizerKnob(mVirtualizerKnob, effectsEnabled);
+ if (maxxAudio) {
+ // speaker? hide virtualizer
+ setKnobVisible(KnobCommander.KNOB_VIRTUALIZER, !speaker);
+ } else if (dts) {
+ // same for DTS
+ setKnobVisible(KnobCommander.KNOB_VIRTUALIZER, !speaker);
+ } else {
+ setKnobVisible(KnobCommander.KNOB_VIRTUALIZER, true);
+ }
+ }
+
+ public static class KnobInfo {
+ int whichKnob;
+ RadialKnob knob;
+ View label;
+
+ public KnobInfo(int whichKnob, RadialKnob knob, View label) {
+ this.knob = knob;
+ this.label = label;
+ this.whichKnob = whichKnob;
+ }
+ }
+
+ private class H extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_EXPAND:
+ case MSG_CONTRACT:
+ RadialKnob knob = ((KnobInfo) msg.obj).knob;
+ View label = ((KnobInfo) msg.obj).label;
+ boolean expand = msg.what == MSG_EXPAND;
+ resize(knob, label, expand);
+ break;
+ }
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/knobs/RadialKnob.java b/src/org/cyanogenmod/audiofx/audiofx/knobs/RadialKnob.java
new file mode 100644
index 0000000..0e4cbb2
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/knobs/RadialKnob.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015, The CyanogenMod Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.cyngn.audiofx.knobs;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.RectF;
+import android.graphics.Typeface;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import android.widget.Toast;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.stats.UserSession;
+
+public class RadialKnob extends View {
+
+ private static final String TAG = RadialKnob.class.getSimpleName();
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final float REGULAR_SCALE = 0.8f;
+
+ public static final float TOUCHING_SCALE = 1f;
+ private static final int DO_NOT_VIBRATE_THRESHOLD = 100;
+
+ private static final int DEGREE_OFFSET = -225;
+ private static final int START_ANGLE = 360 + DEGREE_OFFSET;
+ private static final int MAX_DEGREES = 270;
+
+ private final Paint mPaint, mTextPaint;
+
+ ValueAnimator mAnimator;
+ float mOffProgress;
+ boolean mAnimating = false;
+ long mDownTime;
+ long mUpTime;
+ private OnKnobChangeListener mOnKnobChangeListener = null;
+ private float mProgress = 0.0f;
+ private float mTouchProgress = 0.0f;
+ private int mMax = 100;
+ private boolean mOn = false;
+ private boolean mEnabled = true;
+ private float mLastX;
+ private float mLastY;
+ private boolean mMoved;
+ private int mWidth = 0;
+ private RectF mRectF, mOuterRect = new RectF(), mInnerRect = new RectF();
+ private float mLastAngle;
+ private Long mLastVibrateTime;
+ private int mHighlightColor;
+ private int mBackgroundArcColor;
+ private int mBackgroundArcColorDisabled;
+ private int mRectPadding;
+ private int mStrokeWidth;
+ private float mHandleWidth; // little square indicator where user touches
+ private float mTextOffset;
+
+ Path mPath = new Path();
+ PathMeasure mPathMeasure = new PathMeasure();
+ float[] mTmp = new float[2];
+ float mStartX, mStopX, mStartY, mStopY;
+
+ public RadialKnob(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ Resources res = getResources();
+ mBackgroundArcColor = res.getColor(R.color.radial_knob_arc_bg);
+ mBackgroundArcColorDisabled = res.getColor(R.color.radial_knob_arc_bg_disabled);
+ mHighlightColor = res.getColor(R.color.highlight);
+
+ mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mTextPaint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextPaint.setElegantTextHeight(true);
+ mTextPaint.setFakeBoldText(true);
+ mTextPaint.setTextSize(res.getDimension(R.dimen.radial_text_size));
+ mTextPaint.setColor(Color.LTGRAY);
+
+ mTextOffset = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2,
+ getResources().getDisplayMetrics());
+
+ mHandleWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5,
+ getResources().getDisplayMetrics());
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setColor(mHighlightColor);
+ mPaint.setStrokeWidth(mStrokeWidth = res.getDimensionPixelSize(R.dimen.radial_knob_stroke));
+ mPaint.setStrokeCap(Paint.Cap.BUTT);
+ mPaint.setStyle(Paint.Style.STROKE);
+ mPaint.setShadowLayer(2, 1, -2, getResources().getColor(R.color.black));
+
+ setScaleX(REGULAR_SCALE);
+ setScaleY(REGULAR_SCALE);
+
+ mRectPadding = res.getDimensionPixelSize(R.dimen.radial_rect_padding);
+ invalidate();
+ }
+
+ public RadialKnob(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public RadialKnob(Context context) {
+ this(context, null);
+ }
+
+ public void setValue(int value) {
+ if (mMax != 0) {
+ setProgress(((float) value) / mMax);
+ mTouchProgress = mProgress;
+ mLastAngle = mProgress * MAX_DEGREES;
+ }
+ }
+
+ public void setProgress(float progress, boolean fromUser) {
+ if (progress > 1.0f) {
+ progress = 1.0f;
+ }
+ if (progress < 0.0f) {
+ progress = 0.0f;
+ }
+
+ mProgress = progress;
+
+ invalidate();
+
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onValueChanged(this, (int) (progress * mMax), fromUser);
+ }
+ }
+
+ public void setMax(int max) {
+ mMax = max;
+ }
+
+ public float getProgress() {
+ return mProgress;
+ }
+
+ public void setProgress(float progress) {
+ setProgress(progress, false);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public void setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ if (enabled) {
+ setOn(mOn);
+ }
+ invalidate();
+ }
+
+ public void setOn(final boolean on) {
+ mOn = on;
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ invalidate();
+ }
+
+ public void setHighlightColor(int color) {
+ mPaint.setColor(mHighlightColor = color);
+ invalidate();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ mPaint.setStrokeWidth(mStrokeWidth);
+
+ mPaint.setColor(mEnabled ? mBackgroundArcColor : mBackgroundArcColorDisabled);
+ canvas.drawArc(mRectF, START_ANGLE, MAX_DEGREES, false, mPaint);
+
+ final float sweepAngle = mEnabled ? mProgress * MAX_DEGREES : 0;
+ if (mOn) {
+ mPaint.setColor(mHighlightColor);
+ canvas.drawArc(mRectF, START_ANGLE, sweepAngle, false, mPaint);
+ }
+
+ final float indicatorSweepAngle = Math.max(1f, sweepAngle);
+
+ // render the indicator
+ mPath.reset();
+ mPath.arcTo(mInnerRect, START_ANGLE, indicatorSweepAngle, true);
+
+ mPathMeasure.setPath(mPath, false);
+ mPathMeasure.getPosTan(mPathMeasure.getLength(), mTmp, null);
+
+ mStartX = mTmp[0];
+ mStartY = mTmp[1];
+
+ mPath.reset();
+ mPath.arcTo(mOuterRect, START_ANGLE, indicatorSweepAngle, true);
+
+ mPathMeasure.setPath(mPath, false);
+ mPathMeasure.getPosTan(mPathMeasure.getLength(), mTmp, null);
+
+ mStopX = mTmp[0];
+ mStopY = mTmp[1];
+
+ mPaint.setStrokeWidth(mHandleWidth);
+ mPaint.setColor(Color.WHITE);
+ canvas.drawLine(mStartX, mStartY, mStopX, mStopY, mPaint);
+
+ canvas.drawText(getProgressText(),
+ mOuterRect.centerX(),
+ mOuterRect.centerY() + (mTextPaint.getTextSize() / 2.f) - mTextOffset,
+ mTextPaint);
+ }
+
+ private String getProgressText() {
+ if (mEnabled) {
+ return ((int) (mProgress * 100)) + "%";
+ } else {
+ return "--";
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldW, int oldH) {
+ super.onSizeChanged(w, h, oldW, oldH);
+
+ int size = w > h ? h : w;
+ mWidth = size;
+ int diff;
+ if (w > h) {
+ diff = (w - h) / 2;
+ mRectF = new RectF(mRectPadding + diff, mRectPadding,
+ w - mRectPadding - diff, h - mRectPadding);
+ } else {
+ diff = (h - w) / 2;
+ mRectF = new RectF(mRectPadding, mRectPadding + diff,
+ w - mRectPadding, h - mRectPadding - diff);
+ }
+ mOuterRect.set(mRectF);
+ mOuterRect.inset(-mRectPadding, -mRectPadding);
+ mInnerRect.set(mRectF);
+ mInnerRect.inset(mRectPadding, mRectPadding);
+ }
+
+ private boolean isUserSelected() {
+ return getScaleX() == TOUCHING_SCALE && getScaleY() == TOUCHING_SCALE;
+ }
+
+ private void animateTo(float progress) {
+ if (DEBUG) Log.w(TAG, "animateTo(" + progress + ")");
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ mAnimator = ValueAnimator.ofFloat(mProgress, progress);
+ mAnimator.setDuration(100);
+ mAnimator.setInterpolator(new AccelerateInterpolator());
+ mAnimator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mAnimating = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAnimating = false;
+ postInvalidate();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mAnimating = false;
+ postInvalidate();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ });
+ mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float progress = (Float) animation.getAnimatedValue();
+ mProgress = progress;
+ mLastAngle = mProgress * MAX_DEGREES;
+ if (DEBUG) Log.i(TAG, "onAnimationUpdate(): mProgress: "
+ + mProgress + ", mLastAngle: " + mLastAngle);
+
+ setProgress(mProgress);
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onValueChanged(RadialKnob.this,
+ (int) (progress * mMax), true);
+ }
+ postInvalidate();
+ }
+ });
+ mAnimator.start();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ final float x = event.getX();
+ final float y = event.getY();
+
+ if (!mEnabled) {
+ return false;
+ }
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mDownTime = System.currentTimeMillis();
+ mOffProgress = 0;
+
+ getParent().requestDisallowInterceptTouchEvent(true);
+ vibrate();
+ mLastX = event.getX();
+ mLastY = event.getY();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // we can be animating while moving
+ if (mAnimating) {
+ return true;
+ }
+ final float center = getWidth() / 2;
+ final float radius = (center / 2) - (mRectPadding * 2);
+
+ final boolean inDeadzone = inCircle(x, y, center, center, radius);
+ final boolean inOuterCircle = inCircle(x, y, center, center, radius + 70);
+ if (DEBUG)
+ Log.d(TAG, "inOuterCircle: " + inOuterCircle + ", inDeadzone: " + inDeadzone);
+ final float delta = getDelta(x, y);
+ final float angle = angleWithOffset(x, y, DEGREE_OFFSET);
+
+ if (mOn) {
+ if (isUserSelected() && (!inDeadzone)) {
+ float angleDiff = Math.abs(mLastAngle - angle);
+ if (mProgress == 1 && angle < (MAX_DEGREES / 2)) {
+ // oh jeez. no jumping from 100!
+ return true;
+ }
+ if (angleDiff < 90) {
+ // jump!
+ //Log.w(TAG, "using angle");
+ mLastAngle = angle;
+ mTouchProgress = angle / MAX_DEGREES;
+ mMoved = true;
+ if (DEBUG) Log.v(TAG, "ANGLE setProgress: " + mTouchProgress);
+ setProgress(mTouchProgress, true);
+ } else if (angle > 0 && angle < MAX_DEGREES) {
+ if (DEBUG) Log.v(TAG, "ANGLE animateTo: " + angle);
+ mMoved = true;
+ animateTo(angle / MAX_DEGREES);
+ }
+ }
+ // if it's less than one degree, turn it off
+ // 1% ~= 2.7 degrees, pick something slightly higher
+ if (mTouchProgress < (2.71f / MAX_DEGREES) && mOn && mMoved) {
+ mTouchProgress = (2.71f / MAX_DEGREES);
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onSwitchChanged(this, !mOn);
+ }
+ setOn(!mOn);
+ }
+ } else {
+ // off
+ if (isUserSelected() && (!inDeadzone)) {
+ if (delta > 0) {
+ mOffProgress += delta;
+ } else if (angle > 90) {
+ mOffProgress = 0;
+ }
+ if (DEBUG)
+ Log.d(TAG, "OFF, touching angle: " + angle +
+ ", mOffProgress: " + mOffProgress + ", delta " + delta);
+ // we want at least 1%, how many degrees = 1%? + a little padding
+ final float onePercentInDegrees = (MAX_DEGREES / 100) + 1f;
+ if (mOffProgress > 15 && angle < MAX_DEGREES
+ && angle >= onePercentInDegrees) {
+ if (DEBUG) Log.w(TAG, "delta: " + delta);
+ if (angle <= MAX_DEGREES) {
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onSwitchChanged(this, !mOn);
+ }
+
+ setOn(!mOn);
+ if (angle > 30) {
+ animateTo(angle / MAX_DEGREES);
+ } else {
+ setProgress(angle / MAX_DEGREES, true);
+ }
+ mLastAngle = angle;
+ mMoved = false;
+ } else {
+ if (DEBUG) Log.w(TAG, "off, angle > 300, ignoring");
+ }
+ }
+ }
+ mLastX = x;
+ mLastY = y;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ mUpTime = System.currentTimeMillis();
+ final float finalAngle = angleWithOffset(x, y, DEGREE_OFFSET);
+ if (DEBUG) Log.d(TAG, "angle at death: " + finalAngle);
+ if (mUpTime - mDownTime < 100 && mMoved && finalAngle < MAX_DEGREES) {
+ if (mOn) {
+ animateTo(finalAngle / MAX_DEGREES);
+ } else {
+ if (mOnKnobChangeListener != null) {
+ mOnKnobChangeListener.onSwitchChanged(this, !mOn);
+ }
+
+ setOn(!mOn);
+ }
+ }
+ if (mMoved) {
+ UserSession.getInstance()
+ .knobOptionsAdjusted(((KnobContainer.KnobInfo)getTag()).whichKnob);
+ }
+ mLastX = -1;
+ mLastY = -1;
+ mOffProgress = 0;
+ mMoved = false;
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private void vibrate() {
+ if (mLastVibrateTime == null || System.currentTimeMillis() - mLastVibrateTime
+ > DO_NOT_VIBRATE_THRESHOLD) {
+ Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ vibrator.vibrate(40);
+ mLastVibrateTime = System.currentTimeMillis();
+ }
+ }
+
+ public void resize(boolean selected) {
+ if (!mEnabled) {
+ return;
+ }
+ if (selected) {
+ animate()
+ .scaleY(RadialKnob.TOUCHING_SCALE)
+ .scaleX(RadialKnob.TOUCHING_SCALE)
+ .setDuration(100);
+ } else {
+ animate()
+ .scaleY(RadialKnob.REGULAR_SCALE)
+ .scaleX(RadialKnob.REGULAR_SCALE)
+ .setDuration(100);
+ }
+ }
+
+ private float getDelta(float x, float y) {
+ float angle = angle(x, y);
+ float oldAngle = angle(mLastX, mLastY);
+ float delta = angle - oldAngle;
+ if (delta >= 180.0f) {
+ delta = -oldAngle;
+ } else if (delta <= -180.0f) {
+ delta = 360 - oldAngle;
+ }
+ return delta;
+ }
+
+ private float angle(float x, float y) {
+ float center = mWidth / 2.0f;
+ x -= center;
+ y -= center;
+
+ if (x == 0.0f) {
+ if (y > 0.0f) {
+ return 180.0f;
+ } else {
+ return 0.0f;
+ }
+ }
+
+ float angle = (float) (Math.atan(y / x) / Math.PI * 180.0);
+ if (x > 0.0f) {
+ angle += 90;
+ } else {
+ angle += 270;
+ }
+ return angle;
+ }
+
+ private float angleWithOffset(float x, float y, int degreeOffset) {
+ float angle = angle(x, y);
+ if (angle > 180) {
+ angle += degreeOffset;
+ } else {
+ angle += (360 + degreeOffset);
+ }
+ return angle;
+ }
+
+
+ private static boolean inCircle(float x, float y, float circleCenterX, float circleCenterY,
+ float circleRadius) {
+ double dx = Math.pow(x - circleCenterX, 2);
+ double dy = Math.pow(y - circleCenterY, 2);
+
+ if ((dx + dy) < Math.pow(circleRadius, 2)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public void setOnKnobChangeListener(OnKnobChangeListener l) {
+ mOnKnobChangeListener = l;
+ }
+
+ public interface OnKnobChangeListener {
+ void onValueChanged(RadialKnob knob, int value, boolean fromUser);
+
+ boolean onSwitchChanged(RadialKnob knob, boolean on);
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/preset/InfinitePagerAdapter.java b/src/org/cyanogenmod/audiofx/audiofx/preset/InfinitePagerAdapter.java
new file mode 100644
index 0000000..71811f4
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/preset/InfinitePagerAdapter.java
@@ -0,0 +1,95 @@
+package com.cyngn.audiofx.preset;
+
+import android.os.Parcelable;
+import android.support.v4.view.PagerAdapter;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A PagerAdapter that wraps around another PagerAdapter to handle paging wrap-around.
+ */
+public class InfinitePagerAdapter extends PagerAdapter {
+
+ private static final String TAG = "InfinitePagerAdapter";
+ private static final boolean DEBUG = false;
+
+ private PagerAdapter adapter;
+
+ public InfinitePagerAdapter(PagerAdapter adapter) {
+ this.adapter = adapter;
+ }
+
+ @Override
+ public int getCount() {
+ // warning: scrolling to very high values (1,000,000+) results in
+ // strange drawing behaviour
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * @return the {@link #getCount()} result of the wrapped adapter
+ */
+ public int getRealCount() {
+ return adapter.getCount();
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ int virtualPosition = position % getRealCount();
+ debug("instantiateItem: real position: " + position);
+ debug("instantiateItem: virtual position: " + virtualPosition);
+
+ // only expose virtual position to the inner adapter
+ return adapter.instantiateItem(container, virtualPosition);
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ int virtualPosition = position % getRealCount();
+ debug("destroyItem: real position: " + position);
+ debug("destroyItem: virtual position: " + virtualPosition);
+
+ // only expose virtual position to the inner adapter
+ adapter.destroyItem(container, virtualPosition, object);
+ }
+
+ /*
+ * Delegate rest of methods directly to the inner adapter.
+ */
+
+ @Override
+ public void finishUpdate(ViewGroup container) {
+ adapter.finishUpdate(container);
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return adapter.isViewFromObject(view, object);
+ }
+
+ @Override
+ public void restoreState(Parcelable bundle, ClassLoader classLoader) {
+ adapter.restoreState(bundle, classLoader);
+ }
+
+ @Override
+ public Parcelable saveState() {
+ return adapter.saveState();
+ }
+
+ @Override
+ public void startUpdate(ViewGroup container) {
+ adapter.startUpdate(container);
+ }
+
+ /*
+ * End delegation
+ */
+
+ private void debug(String message) {
+ if (DEBUG) {
+ Log.d(TAG, message);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/org/cyanogenmod/audiofx/audiofx/preset/InfiniteViewPager.java b/src/org/cyanogenmod/audiofx/audiofx/preset/InfiniteViewPager.java
new file mode 100644
index 0000000..8a4ed38
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/preset/InfiniteViewPager.java
@@ -0,0 +1,106 @@
+package com.cyngn.audiofx.preset;
+
+
+import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+
+/**
+ * A {@link ViewPager} that allows pseudo-infinite paging with a wrap-around effect. Should be used with an {@link
+ * InfinitePagerAdapter}.
+ */
+public class InfiniteViewPager extends ViewPager {
+
+ private final EqualizerManager mEqManager;
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
+ public InfiniteViewPager(Context context) {
+ super(context);
+ mEqManager = MasterConfigControl.getInstance(context).getEqualizerManager();
+ }
+
+ public InfiniteViewPager(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mEqManager = MasterConfigControl.getInstance(context).getEqualizerManager();
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (mEqManager.isAnimatingToCustom()) {
+ return false;
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int textSize = getResources().getDimensionPixelSize(R.dimen.preset_text_size)
+ + getResources().getDimensionPixelSize(R.dimen.preset_text_padding);
+ super.onMeasure(widthMeasureSpec,
+ MeasureSpec.makeMeasureSpec(textSize, MeasureSpec.EXACTLY));
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (mEqManager.isAnimatingToCustom()) {
+ return false;
+ }
+ boolean result;
+ try {
+ result = super.onTouchEvent(ev);
+ } catch (IllegalArgumentException e) {
+ /* There's a bug with the support library where it doesn't check
+ * the proper pointer index, so when multi touching the container,
+ * this can sometimes be thrown. Supposedly there are no downsides to just
+ * catching the exception and moving along, so let's do that....
+ */
+ result = false;
+ }
+ return result;
+ }
+
+ @Override
+ public void setAdapter(PagerAdapter adapter) {
+ super.setAdapter(adapter);
+ // offset first element so that we can scroll to the left
+ setCurrentItem(0);
+ }
+
+ @Override
+ public void setCurrentItem(int item) {
+ // offset the current item to ensure there is space to scroll
+ item = getOffsetAmount() + (item % getAdapter().getCount());
+ super.setCurrentItem(item);
+ }
+
+ public void setCurrentItemAbsolute(int item) {
+ super.setCurrentItem(item);
+ }
+
+ private int getOffsetAmount() {
+ if (getAdapter() instanceof InfinitePagerAdapter) {
+ InfinitePagerAdapter infAdapter = (InfinitePagerAdapter) getAdapter();
+ // allow for 100 back cycles from the beginning
+ // should be enough to create an illusion of infinity
+ // warning: scrolling to very high values (1,000,000+) results in
+ // strange drawing behaviour
+ return infAdapter.getRealCount() * 100;
+ } else {
+ return 0;
+ }
+ }
+
+ public void setCurrentItemAbsolute(int newPage, boolean b) {
+ super.setCurrentItem(newPage, b);
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/preset/PresetPagerAdapter.java b/src/org/cyanogenmod/audiofx/audiofx/preset/PresetPagerAdapter.java
new file mode 100644
index 0000000..f6875f7
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/preset/PresetPagerAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cyngn.audiofx.preset;
+
+import android.content.Context;
+import android.support.v4.view.PagerAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.EqualizerManager;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+
+public class PresetPagerAdapter extends PagerAdapter {
+
+ private final Context mContext;
+ private final EqualizerManager mEqManager;
+
+ public PresetPagerAdapter(Context context) {
+ super();
+ mContext = context;
+ mEqManager = MasterConfigControl.getInstance(mContext).getEqualizerManager();
+ }
+
+ @Override
+ public int getItemPosition(Object object) {
+ View v = (View) object;
+ int index = mEqManager.indexOf(((Preset) v.getTag()));
+ if (index == -1) {
+ return POSITION_NONE;
+ } else {
+ return index;
+ }
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preset_adapter_row, container, false);
+ TextView tv = (TextView) view;
+ tv.setText(mEqManager.getLocalizedPresetName(position));
+ tv.setTag(mEqManager.getPreset(position));
+ container.addView(tv);
+ return view;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ if (object instanceof View) {
+ container.removeView((View) object);
+ }
+ }
+
+ @Override
+ public int getCount() {
+ return mEqManager.getPresetCount();
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object o) {
+ return view == o;
+ }
+
+
+
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/receiver/QuickSettingsTileReceiver.java b/src/org/cyanogenmod/audiofx/audiofx/receiver/QuickSettingsTileReceiver.java
new file mode 100644
index 0000000..c27d44a
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/receiver/QuickSettingsTileReceiver.java
@@ -0,0 +1,36 @@
+package com.cyngn.audiofx.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.service.AudioFxService;
+
+/**
+ * Created by roman on 1/13/16.
+ */
+public class QuickSettingsTileReceiver extends BroadcastReceiver {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "QSTileReceiver";
+
+ public static final String ACTION_TOGGLE_CURRENT_DEVICE
+ = "com.cyngn.audiofx.action.TOGGLE_DEVICE";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG) {
+ Log.i(TAG, "onReceive() called with " + "context = [" + context + "], intent = [" + intent + "]");
+ }
+ if (ACTION_TOGGLE_CURRENT_DEVICE.equals(intent.getAction())) {
+ final MasterConfigControl config = MasterConfigControl.getInstance(context);
+
+ config.setCurrentDeviceEnabled(!config.isCurrentDeviceEnabled());
+
+ // tell service explicitly to update the qs tile in case UI isn't up to let it know
+ context.startService(new Intent(AudioFxService.ACTION_UPDATE_TILE)
+ .setClass(context, AudioFxService.class));
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/ServiceDispatcher.java b/src/org/cyanogenmod/audiofx/audiofx/receiver/ServiceDispatcher.java
index 7a838b1..7581ba2 100644
--- a/src/org/cyanogenmod/audiofx/ServiceDispatcher.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/receiver/ServiceDispatcher.java
@@ -1,19 +1,5 @@
-/*
- * Copyright (C) 2016 The CyanogenMod Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.cyanogenmod.audiofx;
+
+package com.cyngn.audiofx.receiver;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -21,6 +7,8 @@ import android.content.Intent;
import android.media.audiofx.AudioEffect;
import android.util.Log;
+import com.cyngn.audiofx.service.AudioFxService;
+
import cyanogenmod.media.AudioSessionInfo;
import cyanogenmod.media.CMAudioManager;
@@ -28,7 +16,7 @@ public class ServiceDispatcher extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Intent service = new Intent(context.getApplicationContext(), HeadsetService.class);
+ Intent service = new Intent(context.getApplicationContext(), AudioFxService.class);
String action = intent.getAction();
// We can also get AUDIO_BECOMING_NOISY, which means a device change is
@@ -39,10 +27,11 @@ public class ServiceDispatcher extends BroadcastReceiver {
String pkg = intent.getStringExtra(AudioEffect.EXTRA_PACKAGE_NAME);
service.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, sessionId);
service.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, pkg);
+
} else if (action.equals(CMAudioManager.ACTION_AUDIO_SESSIONS_CHANGED)) {
// callback from CMAudioService
- final AudioSessionInfo info = (AudioSessionInfo)intent.getParcelableExtra(
+ final AudioSessionInfo info = (AudioSessionInfo) intent.getParcelableExtra(
CMAudioManager.EXTRA_SESSION_INFO);
boolean added = intent.getBooleanExtra(CMAudioManager.EXTRA_SESSION_ADDED, false);
service.putExtra(CMAudioManager.EXTRA_SESSION_INFO, info);
@@ -51,5 +40,9 @@ public class ServiceDispatcher extends BroadcastReceiver {
service.setAction(action);
context.startService(service);
+ if (AudioFxService.DEBUG) {
+ Log.d("AudioFX-Dispatcher", "Received " + action);
+ }
+
}
}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/service/AudioFxService.java b/src/org/cyanogenmod/audiofx/audiofx/service/AudioFxService.java
new file mode 100644
index 0000000..ce158b5
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/service/AudioFxService.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2014 The CyanogenMod Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2016 Cyanogen Inc.
+ *
+ * Proprietary and confidential.
+ */
+package com.cyngn.audiofx.service;
+
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.audiofx.AudioEffect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.ActivityMusic;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.backends.EffectSet;
+import com.cyngn.audiofx.receiver.QuickSettingsTileReceiver;
+
+import java.lang.ref.WeakReference;
+import java.util.Locale;
+
+import cyanogenmod.app.CMStatusBarManager;
+import cyanogenmod.app.CustomTile;
+import cyanogenmod.media.AudioSessionInfo;
+import cyanogenmod.media.CMAudioManager;
+
+/**
+ * This service is responsible for applying all requested effects from the AudioFX UI.
+ *
+ * Since the AudioFX UI allows for different configurations based on the current output device,
+ * the service is also responsible for applying the effects properly based on user configuration,
+ * and the current device output state.
+ */
+public class AudioFxService extends Service
+ implements AudioOutputChangeListener.AudioOutputChangedCallback {
+
+ static final String TAG = AudioFxService.class.getSimpleName();
+
+ public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final boolean ENABLE_REVERB = false;
+
+ public static final String ACTION_DEVICE_OUTPUT_CHANGED
+ = "org.cyanogenmod.audiofx.ACTION_DEVICE_OUTPUT_CHANGED";
+
+ public static final String ACTION_UPDATE_TILE = "com.cyngn.audiofx.action.UPDATE_TILE";
+
+ public static final String EXTRA_DEVICE = "device";
+
+ // flags for updateService to minimize DSP traffic
+ public static final int EQ_CHANGED = 0x1;
+ public static final int BASS_BOOST_CHANGED = 0x2;
+ public static final int VIRTUALIZER_CHANGED = 0x4;
+ public static final int TREBLE_BOOST_CHANGED = 0x8;
+ public static final int VOLUME_BOOST_CHANGED = 0x10;
+ public static final int REVERB_CHANGED = 0x20;
+ public static final int ALL_CHANGED = 0xFF;
+
+ // flags from audio.h, used by session callbacks
+ static final int AUDIO_OUTPUT_FLAG_FAST = 0x4;
+ static final int AUDIO_OUTPUT_FLAG_DEEP_BUFFER = 0x8;
+ static final int AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10;
+
+ private static final int TILE_ID = 555;
+
+ private Locale mLastLocale;
+
+ private CustomTile mTile;
+ private CustomTile.Builder mTileBuilder;
+
+ private AudioOutputChangeListener mOutputListener;
+ private DevicePreferenceManager mDevicePrefs;
+ private SessionManager mSessionManager;
+ private Handler mHandler;
+
+ private AudioDeviceInfo mCurrentDevice;
+
+ public static class LocalBinder extends Binder {
+
+ final WeakReference<AudioFxService> mService;
+
+ public LocalBinder(AudioFxService service) {// added a constructor for Stub here
+ mService = new WeakReference<AudioFxService>(service);
+ }
+
+ private boolean checkService() {
+ if (mService.get() == null) {
+ Log.e("AudioFx-LocalBinder", "Service was null!");
+ }
+ return mService.get() != null;
+ }
+
+ public void update(int flags) {
+ if (checkService()) {
+ mService.get().update(flags);
+ }
+ }
+
+ public void setOverrideLevels(short band, float level) {
+ if (checkService()) {
+ mService.get().mSessionManager.setOverrideLevels(band, level);
+ }
+ }
+
+ public EffectSet getEffect(Integer id) {
+ if (checkService()) {
+ return mService.get().mSessionManager.getEffectForSession(id);
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (DEBUG) Log.i(TAG, "Starting service.");
+
+ HandlerThread handlerThread = new HandlerThread("AudioFx-Backend");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+
+ mOutputListener = new AudioOutputChangeListener(getApplicationContext(), mHandler);
+ mOutputListener.addCallback(this);
+
+ mDevicePrefs = new DevicePreferenceManager(getApplicationContext(), mCurrentDevice);
+ if (!mDevicePrefs.initDefaults()) {
+ stopSelf();
+ return;
+ }
+
+ mSessionManager = new SessionManager(getApplicationContext(), mHandler, mDevicePrefs,
+ mCurrentDevice);
+ mOutputListener.addCallback(mDevicePrefs, mSessionManager);
+
+ final CMAudioManager cma = CMAudioManager.getInstance(getApplicationContext());
+ for (AudioSessionInfo asi : cma.listAudioSessions(AudioManager.STREAM_MUSIC)) {
+ mSessionManager.addSession(asi);
+ }
+
+ updateQsTile();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (DEBUG) {
+ Log.i(TAG, "onStartCommand() called with " + "intent = [" + intent + "], flags = ["
+ + flags + "], startId = [" + startId + "]");
+ }
+ if (intent != null && intent.getAction() != null) {
+ if (ACTION_UPDATE_TILE.equals(intent.getAction())) {
+ update(ALL_CHANGED);
+ } else {
+ String action = intent.getAction();
+ int sessionId = intent.getIntExtra(AudioEffect.EXTRA_AUDIO_SESSION, 0);
+ String pkg = intent.getStringExtra(AudioEffect.EXTRA_PACKAGE_NAME);
+ int stream = mapContentTypeToStream(
+ intent.getIntExtra(AudioEffect.EXTRA_CONTENT_TYPE,
+ AudioEffect.CONTENT_TYPE_MUSIC));
+
+ if (action.equals(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)) {
+ if (DEBUG) {
+ Log.i(TAG, String.format("New audio session: %d package: %s contentType=%d",
+ sessionId, pkg, stream));
+ }
+ AudioSessionInfo info = new AudioSessionInfo(sessionId, stream, -1, -1, -1);
+ mSessionManager.addSession(info);
+
+ } else if (action.equals(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)) {
+
+ AudioSessionInfo info = new AudioSessionInfo(sessionId, stream, -1, -1, -1);
+ mSessionManager.removeSession(info);
+
+ } else if (action.equals(CMAudioManager.ACTION_AUDIO_SESSIONS_CHANGED)) {
+
+ final AudioSessionInfo info = (AudioSessionInfo) intent.getParcelableExtra(
+ CMAudioManager.EXTRA_SESSION_INFO);
+ if (info != null && info.getSessionId() > 0) {
+ boolean added = intent.getBooleanExtra(CMAudioManager.EXTRA_SESSION_ADDED,
+ false);
+ if (added) {
+ mSessionManager.addSession(info);
+ } else {
+ mSessionManager.removeSession(info);
+ }
+ }
+
+ }
+ }
+ }
+ return START_STICKY;
+ }
+
+ /**
+ * maps {@link AudioEffect#EXTRA_CONTENT_TYPE} to an AudioManager.STREAM_* item
+ */
+ private static int mapContentTypeToStream(int contentType) {
+ switch (contentType) {
+ case AudioEffect.CONTENT_TYPE_VOICE:
+ return AudioManager.STREAM_VOICE_CALL;
+ case AudioEffect.CONTENT_TYPE_GAME:
+ // explicitly don't support game effects right now
+ return -1;
+ case AudioEffect.CONTENT_TYPE_MOVIE:
+ case AudioEffect.CONTENT_TYPE_MUSIC:
+ default:
+ return AudioManager.STREAM_MUSIC;
+ }
+ }
+
+ @Override
+ public synchronized void onAudioOutputChanged(boolean firstChange,
+ AudioDeviceInfo outputDevice) {
+ if (outputDevice == null) {
+ return;
+ }
+
+ mCurrentDevice = outputDevice;
+
+ if (DEBUG)
+ Log.d(TAG, "Broadcasting device changed event");
+
+ // Update the UI with the change
+ Intent intent = new Intent(ACTION_DEVICE_OUTPUT_CHANGED);
+ intent.putExtra("device", outputDevice.getId());
+ LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
+
+ updateQsTile();
+ }
+
+ private void updateQsTile() {
+ if (mCurrentDevice == null || mDevicePrefs == null) {
+ // too early
+ return;
+ }
+ if (mTileBuilder == null) {
+ mTileBuilder = new CustomTile.Builder(this);
+ }
+
+ mLastLocale = getResources().getConfiguration().locale;
+ final PendingIntent pi = PendingIntent.getBroadcast(this, 0,
+ new Intent(QuickSettingsTileReceiver.ACTION_TOGGLE_CURRENT_DEVICE)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .setClass(this, QuickSettingsTileReceiver.class), 0);
+
+ final PendingIntent longPress = PendingIntent.getActivity(this, 0,
+ new Intent(this, ActivityMusic.class)
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK), 0);
+
+ String label = getString(R.string.qs_tile_label,
+ MasterConfigControl.getDeviceDisplayString(this, mCurrentDevice));
+
+ mTileBuilder
+ .hasSensitiveData(false)
+ .setIcon(mDevicePrefs.isGlobalEnabled() ? R.drawable.ic_qs_visualizer_on
+ : R.drawable.ic_qs_visualizer_off)
+ .setLabel(label)
+ .setContentDescription(R.string.qs_tile_content_description)
+ .shouldCollapsePanel(false)
+ .setOnClickIntent(pi)
+ .setOnLongClickIntent(longPress);
+
+ mTile = mTileBuilder.build();
+
+ CMStatusBarManager.getInstance(this).publishTile(TILE_ID, mTile);
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Log.i(TAG, "Stopping service.");
+
+ mOutputListener.removeCallback(this, mSessionManager, mDevicePrefs);
+ mSessionManager.onDestroy();
+
+ CMStatusBarManager.getInstance(this).removeTile(TILE_ID);
+
+ super.onDestroy();
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return new LocalBinder(this);
+ }
+
+ @Override
+ public void onTrimMemory(int level) {
+ if (DEBUG) Log.d(TAG, "onTrimMemory: level=" + level);
+ switch (level) {
+ case TRIM_MEMORY_BACKGROUND:
+ case TRIM_MEMORY_MODERATE:
+ case TRIM_MEMORY_RUNNING_MODERATE:
+ case TRIM_MEMORY_COMPLETE:
+ if (DEBUG) Log.d(TAG, "killing service if no effects active.");
+ mHandler.postDelayed(new Runnable() {
+ @Override
+ public void run() {
+ if (!mSessionManager.hasActiveSessions()) {
+ stopSelf();
+ Log.w(TAG, "self destructing, no sessions active and nothing to do.");
+ }
+ }
+ }, 1000);
+ break;
+ }
+ }
+
+ /**
+ * Queue up a backend update.
+ */
+ private void update(int flags) {
+ mSessionManager.update(flags);
+
+ if ((flags & ALL_CHANGED) == ALL_CHANGED) {
+ updateQsTile();
+ }
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (!mLastLocale.equals(newConfig.locale)) {
+ updateQsTile();
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/service/AudioOutputChangeListener.java b/src/org/cyanogenmod/audiofx/audiofx/service/AudioOutputChangeListener.java
new file mode 100644
index 0000000..f85d9c1
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/service/AudioOutputChangeListener.java
@@ -0,0 +1,131 @@
+
+package com.cyngn.audiofx.service;
+
+import static android.media.AudioDeviceInfo.convertDeviceTypeToInternalDevice;
+
+import android.content.Context;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class AudioOutputChangeListener extends AudioDeviceCallback {
+
+ private static final String TAG = "AudioFx-" + AudioOutputChangeListener.class.getSimpleName();
+
+ private boolean mInitial = true;
+
+ private final Context mContext;
+ private final AudioManager mAudioManager;
+ private final Handler mHandler;
+ private int mLastDevice = -1;
+
+ private final ArrayList<AudioOutputChangedCallback> mCallbacks = new ArrayList<AudioOutputChangedCallback>();
+
+ public interface AudioOutputChangedCallback {
+ public void onAudioOutputChanged(boolean firstChange, AudioDeviceInfo outputDevice);
+ }
+
+ public AudioOutputChangeListener(Context context, Handler handler) {
+ mContext = context;
+ mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mHandler = handler;
+ }
+
+ public void addCallback(AudioOutputChangedCallback... callbacks) {
+ synchronized (mCallbacks) {
+ boolean initial = mCallbacks.size() == 0;
+ mCallbacks.addAll(Arrays.asList(callbacks));
+ if (initial) {
+ mAudioManager.registerAudioDeviceCallback(this, mHandler);
+ }
+ }
+ }
+
+ public void removeCallback(AudioOutputChangedCallback... callbacks) {
+ synchronized (mCallbacks) {
+ mCallbacks.removeAll(Arrays.asList(callbacks));
+ if (mCallbacks.size() == 0) {
+ mAudioManager.unregisterAudioDeviceCallback(this);
+ }
+ }
+ }
+
+ private void callback() {
+ synchronized (mCallbacks) {
+ final AudioDeviceInfo device = getCurrentDevice();
+
+ if (device == null) {
+ Log.w(TAG, "Unable to determine audio device!");
+ return;
+ }
+
+ if (mInitial || device.getId() != mLastDevice) {
+ Log.d(TAG, "onAudioOutputChanged id: " + device.getId() +
+ " type: " + device.getType() +
+ " name: " + device.getProductName() +
+ " address: " + device.getAddress() +
+ " [" + device.toString() + "]");
+ mLastDevice = device.getId();
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ synchronized (mCallbacks) {
+ for (AudioOutputChangedCallback callback : mCallbacks) {
+ callback.onAudioOutputChanged(mInitial, device);
+ }
+ }
+ }
+ });
+
+ if (mInitial) {
+ mInitial = false;
+ }
+ }
+ }
+ }
+
+ public void refresh() {
+ callback();
+ }
+
+ @Override
+ public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+ callback();
+ }
+
+ @Override
+ public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
+ callback();
+ }
+
+ public List<AudioDeviceInfo> getConnectedOutputs() {
+ final List<AudioDeviceInfo> outputs = new ArrayList<AudioDeviceInfo>();
+ final int forMusic = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
+ for (AudioDeviceInfo ai : mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
+ if ((convertDeviceTypeToInternalDevice(ai.getType()) & forMusic) > 0) {
+ outputs.add(ai);
+ }
+ }
+ return outputs;
+ }
+
+ public AudioDeviceInfo getCurrentDevice() {
+ final List<AudioDeviceInfo> devices = getConnectedOutputs();
+ return devices.size() > 0 ? devices.get(0) : null;
+ }
+
+ public AudioDeviceInfo getDeviceById(int id) {
+ for (AudioDeviceInfo ai : mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)) {
+ if (ai.getId() == id) {
+ return ai;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/service/BootReceiver.java b/src/org/cyanogenmod/audiofx/audiofx/service/BootReceiver.java
new file mode 100644
index 0000000..df853a5
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/service/BootReceiver.java
@@ -0,0 +1,14 @@
+package com.cyngn.audiofx.service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import com.cyngn.audiofx.Constants;
+
+public class BootReceiver extends BroadcastReceiver {
+ public void onReceive(Context context, Intent intent) {
+ final Intent service = new Intent(context.getApplicationContext(), AudioFxService.class);
+ context.startService(service);
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/service/DevicePreferenceManager.java b/src/org/cyanogenmod/audiofx/audiofx/service/DevicePreferenceManager.java
new file mode 100644
index 0000000..928209e
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/service/DevicePreferenceManager.java
@@ -0,0 +1,294 @@
+package com.cyngn.audiofx.service;
+
+import static com.cyngn.audiofx.Constants.AUDIOFX_GLOBAL_FILE;
+import static com.cyngn.audiofx.Constants.AUDIOFX_GLOBAL_HAS_BASSBOOST;
+import static com.cyngn.audiofx.Constants.AUDIOFX_GLOBAL_HAS_DTS;
+import static com.cyngn.audiofx.Constants.AUDIOFX_GLOBAL_HAS_MAXXAUDIO;
+import static com.cyngn.audiofx.Constants.AUDIOFX_GLOBAL_HAS_VIRTUALIZER;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_BASS_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_BASS_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_EQ_PRESET;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_GLOBAL_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_MAXXVOLUME_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_TREBLE_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_TREBLE_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_HEADSET;
+import static com.cyngn.audiofx.Constants.DEVICE_SPEAKER;
+import static com.cyngn.audiofx.Constants.EQUALIZER_BAND_LEVEL_RANGE;
+import static com.cyngn.audiofx.Constants.EQUALIZER_CENTER_FREQS;
+import static com.cyngn.audiofx.Constants.EQUALIZER_NUMBER_OF_BANDS;
+import static com.cyngn.audiofx.Constants.EQUALIZER_NUMBER_OF_PRESETS;
+import static com.cyngn.audiofx.Constants.EQUALIZER_PRESET;
+import static com.cyngn.audiofx.Constants.EQUALIZER_PRESET_NAMES;
+import static com.cyngn.audiofx.Constants.SAVED_DEFAULTS;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.media.AudioDeviceInfo;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.cyngn.audiofx.Constants;
+import com.cyngn.audiofx.R;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.backends.EffectSet;
+import com.cyngn.audiofx.backends.EffectsFactory;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+class DevicePreferenceManager implements AudioOutputChangeListener.AudioOutputChangedCallback {
+
+ private static final String TAG = AudioFxService.TAG;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Context mContext;
+
+ private AudioDeviceInfo mCurrentDevice;
+
+ public DevicePreferenceManager(Context context, AudioDeviceInfo device) {
+ mContext = context;
+ mCurrentDevice = device;
+ }
+
+ public boolean initDefaults() {
+ try {
+ saveAndApplyDefaults(false);
+ } catch (Exception e) {
+ SharedPreferences prefs = Constants.getGlobalPrefs(mContext);
+ prefs.edit().clear().commit();
+ Log.e(TAG, "Failed to initialize defaults!", e);
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public void onAudioOutputChanged(boolean firstChange, AudioDeviceInfo outputDevice) {
+ mCurrentDevice = outputDevice;
+ }
+
+ public SharedPreferences getCurrentDevicePrefs() {
+ return mContext.getSharedPreferences(
+ MasterConfigControl.getDeviceIdentifierString(mCurrentDevice), 0);
+ }
+
+ public SharedPreferences prefsFor(final String name) {
+ return mContext.getSharedPreferences(name, 0);
+ }
+
+ private boolean hasPrefs(final String name) {
+ return mContext.getSharedPrefsFile(name).exists();
+ }
+
+ public boolean isGlobalEnabled() {
+ return getCurrentDevicePrefs().getBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, false);
+ }
+
+ /**
+ * This method sets some sane defaults for presets, device defaults, etc
+ * <p/>
+ * First we read presets from the system, then adjusts some setting values
+ * for some better defaults!
+ */
+ private void saveAndApplyDefaults(boolean overridePrevious) {
+ if (DEBUG) {
+ Log.d(TAG, "saveAndApplyDefaults() called with overridePrevious = " +
+ "[" + overridePrevious + "]");
+ }
+ SharedPreferences prefs = Constants.getGlobalPrefs(mContext);
+
+ final int currentPrefVer = prefs.getInt(Constants.AUDIOFX_GLOBAL_PREFS_VERSION_INT, 0);
+ boolean needsPrefsUpdate = currentPrefVer < Constants.CURRENT_PREFS_INT_VERSION
+ || overridePrevious;
+
+ if (needsPrefsUpdate) {
+ Log.d(TAG, "rebuilding presets due to preference upgrade from " + currentPrefVer
+ + " to " + Constants.CURRENT_PREFS_INT_VERSION);
+ }
+
+ if (prefs.getBoolean(SAVED_DEFAULTS, false) && !needsPrefsUpdate) {
+ if (DEBUG) {
+ Log.e(TAG, "we've already saved defaults and don't need a pref update. aborting.");
+ }
+ return;
+ }
+ EffectSet temp = new EffectsFactory().createEffectSet(mContext, 0, null);
+
+ final int numBands = temp.getNumEqualizerBands();
+ final int numPresets = temp.getNumEqualizerPresets();
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(EQUALIZER_NUMBER_OF_PRESETS, String.valueOf(numPresets));
+ editor.putString(EQUALIZER_NUMBER_OF_BANDS, String.valueOf(numBands));
+
+ // range
+ short[] rangeShortArr = temp.getEqualizerBandLevelRange();
+ editor.putString(EQUALIZER_BAND_LEVEL_RANGE, rangeShortArr[0]
+ + ";" + rangeShortArr[1]);
+
+ // center freqs
+ StringBuilder centerFreqs = new StringBuilder();
+ // audiofx.global.centerfreqs
+ for (short i = 0; i < numBands; i++) {
+ centerFreqs.append(temp.getCenterFrequency(i));
+ centerFreqs.append(";");
+
+ }
+ centerFreqs.deleteCharAt(centerFreqs.length() - 1);
+ editor.putString(EQUALIZER_CENTER_FREQS, centerFreqs.toString());
+
+ // populate preset names
+ StringBuilder presetNames = new StringBuilder();
+ for (int i = 0; i < numPresets; i++) {
+ String presetName = temp.getEqualizerPresetName((short) i);
+ presetNames.append(presetName);
+ presetNames.append("|");
+
+ // populate preset band values
+ StringBuilder presetBands = new StringBuilder();
+ temp.useEqualizerPreset((short) i);
+
+ for (int j = 0; j < numBands; j++) {
+ // loop through preset bands
+ presetBands.append(temp.getEqualizerBandLevel((short) j));
+ presetBands.append(";");
+ }
+ presetBands.deleteCharAt(presetBands.length() - 1);
+ editor.putString(EQUALIZER_PRESET + i, presetBands.toString());
+ }
+ if (presetNames.length() > 0) {
+ presetNames.deleteCharAt(presetNames.length() - 1);
+ }
+ editor.putString(EQUALIZER_PRESET_NAMES, presetNames.toString());
+
+ editor.putBoolean(AUDIOFX_GLOBAL_HAS_VIRTUALIZER, temp.hasVirtualizer());
+ editor.putBoolean(AUDIOFX_GLOBAL_HAS_BASSBOOST, temp.hasBassBoost());
+ editor.putBoolean(AUDIOFX_GLOBAL_HAS_MAXXAUDIO, temp.getBrand() == Constants.EFFECT_TYPE_MAXXAUDIO);
+ editor.putBoolean(AUDIOFX_GLOBAL_HAS_DTS, temp.getBrand() == Constants.EFFECT_TYPE_DTS);
+ editor.commit();
+ temp.release();
+
+ applyDefaults(needsPrefsUpdate);
+
+ prefs
+ .edit()
+ .putInt(Constants.AUDIOFX_GLOBAL_PREFS_VERSION_INT,
+ Constants.CURRENT_PREFS_INT_VERSION)
+ .putBoolean(Constants.SAVED_DEFAULTS, true)
+ .commit();
+ }
+
+ private static int findInList(String needle, List<String> haystack) {
+ for (int i = 0; i < haystack.size(); i++) {
+ if (haystack.get(i).equalsIgnoreCase(needle)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * This method sets up some *persisted* defaults.
+ * Prereq: saveDefaults() must have been run before this can apply its defaults properly.
+ */
+ private void applyDefaults(boolean overridePrevious) {
+ if (DEBUG) {
+ Log.d(TAG, "applyDefaults() called with overridePrevious = [" + overridePrevious + "]");
+ }
+
+ if (!(overridePrevious || !hasPrefs(DEVICE_SPEAKER) ||
+ !hasPrefs(AUDIOFX_GLOBAL_FILE))) {
+ return;
+ }
+
+ final SharedPreferences globalPrefs = Constants.getGlobalPrefs(mContext);
+
+ // Nothing to see here for EFFECT_TYPE_DTS
+ if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_DTS, false)) {
+ return;
+ }
+
+ // set up the builtin speaker configuration
+ final String smallSpeakers = getNonLocalizedString(R.string.small_speakers);
+ final List<String> presetNames = new ArrayList<String>(Arrays.asList(
+ globalPrefs.getString(EQUALIZER_PRESET_NAMES, "").split("\\|")));
+ final SharedPreferences speakerPrefs = prefsFor(DEVICE_SPEAKER);
+
+ if (globalPrefs.getBoolean(AUDIOFX_GLOBAL_HAS_MAXXAUDIO, false)) {
+ // MaxxAudio defaults for builtin speaker:
+ // maxxvolume: on maxxbass: 40% maxxtreble: 32%
+ speakerPrefs.edit()
+ .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true)
+ .putBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, true)
+ .putBoolean(DEVICE_AUDIOFX_BASS_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_BASS_STRENGTH, "400")
+ .putBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "32")
+ .commit();
+
+ // Defaults for headphones
+ // maxxvolume: on maxxbass: 20% maxxtreble: 40% maxxspace: 20%
+ prefsFor(DEVICE_HEADSET).edit()
+ .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true)
+ .putBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, true)
+ .putBoolean(DEVICE_AUDIOFX_BASS_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_BASS_STRENGTH, "200")
+ .putBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "40")
+ .putBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "200")
+ .commit();
+ } else {
+ // Defaults for headphones
+ // bass boost: 15% virtualizer: 20% preset: FLAT
+ int flat = findInList(getNonLocalizedString(R.string.flat), presetNames);
+ prefsFor(DEVICE_HEADSET).edit()
+ .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true)
+ .putBoolean(DEVICE_AUDIOFX_BASS_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_BASS_STRENGTH, "150")
+ .putBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "200")
+ .putString(DEVICE_AUDIOFX_EQ_PRESET, (flat >= 0 ? String.valueOf(flat) : "0"))
+ .commit();
+ }
+
+ // for 5 band configs, let's add a `Small Speaker` configuration if one
+ // doesn't exist ( from oss AudioFX: -170;270;50;-220;200 )
+ if (Integer.parseInt(globalPrefs.getString(EQUALIZER_NUMBER_OF_BANDS, "0")) == 5 &&
+ findInList(smallSpeakers, presetNames) < 0) {
+
+ int currentPresets = Integer.parseInt(
+ globalPrefs.getString(EQUALIZER_NUMBER_OF_PRESETS, "0"));
+
+ presetNames.add(smallSpeakers);
+ String newPresetNames = TextUtils.join("|", presetNames);
+ globalPrefs.edit()
+ .putString(EQUALIZER_PRESET + currentPresets, "-170;270;50;-220;200")
+ .putString(EQUALIZER_PRESET_NAMES, newPresetNames)
+ .putString(EQUALIZER_NUMBER_OF_PRESETS, Integer.toString(++currentPresets))
+ .commit();
+
+ }
+
+ // set the small speakers preset as the default
+ int idx = findInList(smallSpeakers, presetNames);
+ if (idx >= 0) {
+ speakerPrefs.edit()
+ .putBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE, true)
+ .putString(DEVICE_AUDIOFX_EQ_PRESET, String.valueOf(idx))
+ .commit();
+ }
+ }
+
+ private String getNonLocalizedString(int res) {
+ Configuration config = new Configuration(mContext.getResources().getConfiguration());
+ config.setLocale(Locale.ROOT);
+ return mContext.createConfigurationContext(config).getString(res);
+ }
+}
+
diff --git a/src/org/cyanogenmod/audiofx/audiofx/service/SessionManager.java b/src/org/cyanogenmod/audiofx/audiofx/service/SessionManager.java
new file mode 100644
index 0000000..c744686
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/service/SessionManager.java
@@ -0,0 +1,422 @@
+package com.cyngn.audiofx.service;
+
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_BASS_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_BASS_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_EQ_PRESET_LEVELS;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_GLOBAL_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_MAXXVOLUME_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_REVERB_PRESET;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_TREBLE_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_TREBLE_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_ENABLE;
+import static com.cyngn.audiofx.Constants.DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH;
+import static com.cyngn.audiofx.Constants.DEVICE_DEFAULT_GLOBAL_ENABLE;
+import static com.cyngn.audiofx.activity.MasterConfigControl.getDeviceIdentifierString;
+import static com.cyngn.audiofx.service.AudioFxService.ALL_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.BASS_BOOST_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.ENABLE_REVERB;
+import static com.cyngn.audiofx.service.AudioFxService.EQ_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.REVERB_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.TREBLE_BOOST_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.VIRTUALIZER_CHANGED;
+import static com.cyngn.audiofx.service.AudioFxService.VOLUME_BOOST_CHANGED;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.audiofx.PresetReverb;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.cyngn.audiofx.backends.EffectSet;
+import com.cyngn.audiofx.backends.EffectsFactory;
+import com.cyngn.audiofx.eq.EqUtils;
+
+import cyanogenmod.media.AudioSessionInfo;
+import cyanogenmod.media.CMAudioManager;
+
+class SessionManager implements AudioOutputChangeListener.AudioOutputChangedCallback {
+
+ private static final String TAG = AudioFxService.TAG;
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final DevicePreferenceManager mDevicePrefs;
+ private final CMAudioManager mCMAudio;
+
+ /**
+ * All fields ending with L should be locked on {@link #mAudioSessionsL}
+ */
+ private final SparseArray<EffectSet> mAudioSessionsL = new SparseArray<EffectSet>();
+
+
+ private AudioDeviceInfo mCurrentDevice = null;
+
+ // audio priority handler messages
+ private static final int MSG_UPDATE_DSP = 100;
+ private static final int MSG_ADD_SESSION = 101;
+ private static final int MSG_REMOVE_SESSION = 102;
+ private static final int MSG_UPDATE_FOR_SESSION = 103;
+ private static final int MSG_UPDATE_EQ_OVERRIDE = 104;
+
+ public SessionManager(Context context, Handler handler, DevicePreferenceManager devicePrefs,
+ AudioDeviceInfo outputDevice) {
+ mContext = context;
+ mCMAudio = CMAudioManager.getInstance(context);
+ mDevicePrefs = devicePrefs;
+ mCurrentDevice = outputDevice;
+ mHandler = new Handler(handler.getLooper(), new AudioServiceHandler());
+ }
+
+ public void onDestroy() {
+ synchronized (mAudioSessionsL) {
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.getLooper().quit();
+ }
+ }
+
+ public void update(int flags) {
+ if (mHandler == null) {
+ return;
+ }
+ synchronized (mAudioSessionsL) {
+ mHandler.obtainMessage(MSG_UPDATE_DSP, flags, 0).sendToTarget();
+ }
+ }
+
+ public void setOverrideLevels(short band, float level) {
+ synchronized (mAudioSessionsL) {
+ mHandler.obtainMessage(MSG_UPDATE_EQ_OVERRIDE, band, 0, level).sendToTarget();
+ }
+ }
+
+ /**
+ * Callback which listens for session updates from AudioPolicyManager. This is a
+ * feature added by CM which notifies when sessions are created or
+ * destroyed on a particular stream. This is independent of the standard control
+ * intents and should not conflict with them. This feature may not be available on
+ * all devices.
+ *
+ * Default logic is to do our best to only attach to music streams. We never attach
+ * to low-latency streams automatically, and we don't attach to mono streams by default
+ * either since these are usually notifications/ringtones/etc.
+ */
+ public boolean shouldHandleSession(AudioSessionInfo info) {
+ final boolean music = info.getStream() == AudioManager.STREAM_MUSIC;
+ final boolean offloaded = (info.getFlags() < 0)
+ || (info.getFlags() & AudioFxService.AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) > 0
+ || (info.getFlags() & AudioFxService.AUDIO_OUTPUT_FLAG_DEEP_BUFFER) > 0;
+ final boolean stereo = info.getChannelMask() < 0 || info.getChannelMask() > 1;
+
+ return music && offloaded && stereo && info.getSessionId() > 0;
+ }
+
+ public void addSession(AudioSessionInfo info) {
+ synchronized (mAudioSessionsL) {
+ // Never auto-attach is someone is recording! We don't want to interfere
+ // with any sort of loopback mechanisms.
+ final boolean recording = AudioSystem.isSourceActive(0) || AudioSystem.isSourceActive(6);
+ if (recording) {
+ Log.w(TAG, "Recording in progress, not performing auto-attach!");
+ return;
+ }
+ if (shouldHandleSession(info) &&
+ !mHandler.hasMessages(MSG_ADD_SESSION, info.getSessionId())) {
+ mHandler.removeMessages(MSG_REMOVE_SESSION, info.getSessionId());
+ mHandler.obtainMessage(MSG_ADD_SESSION, info.getSessionId()).sendToTarget();
+ if (DEBUG) Log.i(TAG, "New audio session: " + info.toString());
+ }
+ }
+ }
+
+ public void removeSession(AudioSessionInfo info) {
+ synchronized (mAudioSessionsL) {
+ if (shouldHandleSession(info) &&
+ !mHandler.hasMessages(MSG_REMOVE_SESSION, info.getSessionId())) {
+ int sid = info.getSessionId();
+ final EffectSet effects = mAudioSessionsL.get(sid);
+ if (effects != null) {
+ effects.setMarkedForDeath(true);
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(MSG_REMOVE_SESSION, sid),
+ effects.getReleaseDelay());
+ if (DEBUG) Log.i(TAG, "Audio session queued for removal: " + info.toString());
+ }
+ }
+ }
+ }
+
+ public String getCurrentDeviceIdentifier() {
+ return getDeviceIdentifierString(mCurrentDevice);
+ }
+
+ public boolean hasActiveSessions() {
+ synchronized (mAudioSessionsL) {
+ return mAudioSessionsL.size() > 0;
+ }
+ }
+
+ EffectSet getEffectForSession(int sessionId) {
+ synchronized (mAudioSessionsL) {
+ return mAudioSessionsL.get(sessionId);
+ }
+ }
+
+ /**
+ * Update the backend with our changed preferences.
+ *
+ * This must only be called from the HandlerThread!
+ */
+ private void updateBackendLocked(int flags, EffectSet session) {
+ if (Looper.getMainLooper().equals(Looper.myLooper())) {
+ throw new IllegalStateException("updateBackend must not be called on the UI thread!");
+ }
+
+ final SharedPreferences prefs = mDevicePrefs.getCurrentDevicePrefs();
+
+ if (DEBUG) {
+ Log.i(TAG, "+++ updateBackend() called with flags=[" + flags + "], session=[" + session + "]");
+ }
+
+ if (session == null) {
+ return;
+ }
+
+ final boolean globalEnabled = prefs.getBoolean(DEVICE_AUDIOFX_GLOBAL_ENABLE,
+ DEVICE_DEFAULT_GLOBAL_ENABLE);
+
+ if ((flags & ALL_CHANGED) > 0) {
+ // global bypass toggle
+ session.setGlobalEnabled(globalEnabled);
+ }
+
+ if (globalEnabled) {
+ // tell the backend it's time to party
+ if (!session.beginUpdate()) {
+ Log.e(TAG, "session " + session + " failed to beginUpdate()");
+ return;
+ }
+
+ // equalizer
+ try {
+ if ((flags & EQ_CHANGED) > 0) {
+ // equalizer is always on unless bypassed
+ session.enableEqualizer(true);
+ String savedPreset = prefs.getString(DEVICE_AUDIOFX_EQ_PRESET_LEVELS, null);
+ if (savedPreset != null) {
+ session.setEqualizerLevelsDecibels(EqUtils.stringBandsToFloats(savedPreset));
+ }
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling equalizer!", e);
+ }
+
+ // bass
+ try {
+ if ((flags & BASS_BOOST_CHANGED) > 0 && session.hasBassBoost()) {
+ boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_BASS_ENABLE, false);
+ session.enableBassBoost(enable);
+ session.setBassBoostStrength(Short.valueOf(prefs
+ .getString(DEVICE_AUDIOFX_BASS_STRENGTH, "0")));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling bass boost!", e);
+ }
+
+ // reverb
+ if (ENABLE_REVERB) {
+ try {
+ if ((flags & REVERB_CHANGED) > 0 && session.hasReverb()) {
+ short preset = Short.decode(prefs.getString(DEVICE_AUDIOFX_REVERB_PRESET,
+ String.valueOf(PresetReverb.PRESET_NONE)));
+ session.enableReverb(preset > 0);
+ session.setReverbPreset(preset);
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling reverb preset", e);
+ }
+ }
+
+ // virtualizer
+ try {
+ if ((flags & VIRTUALIZER_CHANGED) > 0 && session.hasVirtualizer()) {
+ boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_VIRTUALIZER_ENABLE, false);
+ session.enableVirtualizer(enable);
+ session.setVirtualizerStrength(Short.valueOf(prefs.getString(
+ DEVICE_AUDIOFX_VIRTUALIZER_STRENGTH, "0")));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling virtualizer!");
+ }
+
+ // extended audio effects
+ try {
+ if ((flags & TREBLE_BOOST_CHANGED) > 0 && session.hasTrebleBoost()) {
+ // treble
+ boolean enable = prefs.getBoolean(DEVICE_AUDIOFX_TREBLE_ENABLE, false);
+ session.enableTrebleBoost(enable);
+ session.setTrebleBoostStrength(Short.valueOf(
+ prefs.getString(DEVICE_AUDIOFX_TREBLE_STRENGTH, "0")));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling treble boost!", e);
+ }
+
+ try {
+ if ((flags & VOLUME_BOOST_CHANGED) > 0 && session.hasVolumeBoost()) {
+ // maxx volume
+ session.enableVolumeBoost(prefs.getBoolean(DEVICE_AUDIOFX_MAXXVOLUME_ENABLE, false));
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error enabling volume boost!", e);
+ }
+
+ // mic drop
+ if (!session.commitUpdate()) {
+ Log.e(TAG, "session " + session + " failed to commitUpdate()");
+ }
+ }
+ if (DEBUG) {
+ Log.i(TAG, "--- updateBackend() called with flags=[" + flags + "], session=[" + session + "]");
+ }
+ }
+
+ private class AudioServiceHandler implements Handler.Callback {
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ synchronized (mAudioSessionsL) {
+ EffectSet session = null;
+ Integer sessionId = 0;
+ int flags = 0;
+
+ switch (msg.what) {
+ case MSG_ADD_SESSION:
+ /**
+ * msg.obj = sessionId
+ */
+ sessionId = (Integer) msg.obj;
+ if (sessionId == null || sessionId <= 0) {
+ break;
+ }
+
+ session = mAudioSessionsL.get(sessionId);
+ if (session == null) {
+ try {
+ session = new EffectsFactory()
+ .createEffectSet(mContext, sessionId, mCurrentDevice);
+ } catch (Exception e) {
+ Log.e(TAG, "couldn't create effects for session id: " + sessionId, e);
+ break;
+ }
+ mAudioSessionsL.put(sessionId, session);
+ if (DEBUG) Log.w(TAG, "added new EffectSet for sessionId=" + sessionId);
+ updateBackendLocked(ALL_CHANGED, session);
+ } else {
+ session.setMarkedForDeath(false);
+ }
+ break;
+
+ case MSG_REMOVE_SESSION:
+ /**
+ * msg.obj = sessionId
+ */
+ sessionId = (Integer) msg.obj;
+ if (sessionId == null || sessionId <= 0) {
+ break;
+ }
+
+ session = mAudioSessionsL.get(sessionId);
+ if (session != null && session.isMarkedForDeath()) {
+ mHandler.removeMessages(MSG_UPDATE_FOR_SESSION, sessionId);
+ session.release();
+ mAudioSessionsL.remove(sessionId);
+ if (DEBUG) Log.w(TAG, "removed and released sessionId=" + sessionId);
+ }
+
+ break;
+
+ case MSG_UPDATE_DSP:
+ /**
+ * msg.arg1 = update what flags
+ */
+ flags = msg.arg1;
+
+ final String mode = getCurrentDeviceIdentifier();
+ if (DEBUG) Log.i(TAG, "Updating to configuration: " + mode);
+
+ final int N = mAudioSessionsL.size();
+ for (int i = 0; i < N; i++) {
+ sessionId = mAudioSessionsL.keyAt(i);
+ mHandler.obtainMessage(MSG_UPDATE_FOR_SESSION, flags, 0, sessionId).sendToTarget();
+ }
+ break;
+
+ case MSG_UPDATE_FOR_SESSION:
+ /**
+ * msg.arg1 = update what flags
+ * msg.arg2 = unused
+ * msg.obj = session id integer (for consistency)
+ */
+ sessionId = (Integer) msg.obj;
+ flags = msg.arg1;
+
+ if (sessionId == null || sessionId <= 0) {
+ break;
+ }
+
+ String device = getCurrentDeviceIdentifier();
+ if (DEBUG) Log.i(TAG, "updating DSP for sessionId=" + sessionId +
+ ", device=" + device + " flags=" + flags);
+
+ session = mAudioSessionsL.get(sessionId);
+ if (session != null) {
+ updateBackendLocked(flags, session);
+ }
+ break;
+
+ case MSG_UPDATE_EQ_OVERRIDE:
+ for (int i = 0; i < mAudioSessionsL.size(); i++) {
+ sessionId = mAudioSessionsL.keyAt(i);
+ session = mAudioSessionsL.get(sessionId);
+ if (session != null) {
+ session.setEqualizerBandLevel((short) msg.arg1, (float) msg.obj);
+ }
+ }
+ break;
+ }
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Updates the backend and notifies the frontend when the output device has changed
+ */
+ @Override
+ public void onAudioOutputChanged(boolean firstChange, AudioDeviceInfo outputDevice) {
+ synchronized (mAudioSessionsL) {
+ if (mCurrentDevice == null ||
+ (outputDevice != null && mCurrentDevice.getId() != outputDevice.getId())) {
+ mCurrentDevice = outputDevice;
+ }
+
+ EffectSet session = null;
+
+ // Update all the sessions for this output which are moving
+ final int N = mAudioSessionsL.size();
+ for (int i = 0; i < N; i++) {
+ session = mAudioSessionsL.valueAt(i);
+
+ session.setDevice(mCurrentDevice);
+ updateBackendLocked(ALL_CHANGED, session);
+ }
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/stats/AppState.java b/src/org/cyanogenmod/audiofx/audiofx/stats/AppState.java
new file mode 100644
index 0000000..5417bcd
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/stats/AppState.java
@@ -0,0 +1,41 @@
+package com.cyngn.audiofx.stats;
+
+import com.cyanogen.ambient.analytics.Event;
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.activity.MasterConfigControl;
+import com.cyngn.audiofx.eq.EqUtils;
+import com.cyngn.audiofx.knobs.KnobCommander;
+
+/**
+ * Created by roman on 9/29/15.
+ */
+public class AppState {
+ public static void appendState(MasterConfigControl control,
+ KnobCommander knobs, Event.Builder builder) {
+ // what's the current output device?
+ builder.addField("state_current_device", control.getCurrentDeviceIdentifier());
+
+ // what preset? if custom, what name/values?
+ builder.addField("state_preset_name", control.getEqualizerManager().getCurrentPreset().getName());
+
+ if (control.getEqualizerManager().getCurrentPreset() instanceof Preset.CustomPreset) {
+ builder.addField("state_custom_preset_values",
+ EqUtils.floatLevelsToString(control.getEqualizerManager().getCurrentPreset().getLevels()));
+ }
+
+ // knob states
+ if (control.hasMaxxAudio()) {
+ builder.addField("state_maxx_volume", control.getMaxxVolumeEnabled());
+ }
+
+ if (knobs.hasBassBoost()) {
+ builder.addField("state_knob_bass", knobs.getBassStrength());
+ }
+ if (knobs.hasTreble()) {
+ builder.addField("state_knob_treble", knobs.getTrebleStrength());
+ }
+ if (knobs.hasVirtualizer()) {
+ builder.addField("state_knob_virtualizer", knobs.getVirtualizerStrength());
+ }
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/stats/UserSession.java b/src/org/cyanogenmod/audiofx/audiofx/stats/UserSession.java
new file mode 100644
index 0000000..bb8787c
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/stats/UserSession.java
@@ -0,0 +1,202 @@
+package com.cyngn.audiofx.stats;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.cyanogen.ambient.analytics.Event;
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.knobs.KnobCommander;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class UserSession implements Parcelable {
+
+ private static final String SOURCE_NONE = "none";
+
+ private static UserSession sSession;
+ public static final UserSession getInstance() {
+ return sSession;
+ }
+
+ private String mSource;
+ private int mDevicesChanged;
+ private int mEnabledDisabledToggles;
+ private int mPresetsSelected;
+ private int mPresetsCreated;
+ private int mPresetsRemoved;
+ private int mPresetsRenamed;
+ private int mMaxxVolumeToggled;
+ private int mTrebleKnobAdjusted;
+ private int mBassKnobAdjusted;
+ private int mVirtualizerKnobAdjusted;
+
+ public UserSession(String incomingPackageSource) {
+ if (incomingPackageSource == null) {
+ mSource = SOURCE_NONE;
+ } else {
+ mSource = incomingPackageSource;
+ }
+ sSession = this;
+ }
+
+ public void deviceChanged() {
+ mDevicesChanged++;
+ }
+
+ public void deviceEnabledDisabled() {
+ mEnabledDisabledToggles++;
+ }
+
+ public void presetSelected() {
+ mPresetsSelected++;
+ }
+
+ public void presetRemoved() {
+ mPresetsRemoved++;
+ }
+
+ public void presetRenamed() {
+ mPresetsRenamed++;
+ }
+
+ public void presetCreated() {
+ mPresetsCreated++;
+ }
+
+ public void maxxVolumeToggled() {
+ mMaxxVolumeToggled++;
+ }
+
+ public void knobOptionsAdjusted(int knob) {
+ switch (knob) {
+ case KnobCommander.KNOB_BASS:
+ mBassKnobAdjusted++;
+ break;
+ case KnobCommander.KNOB_TREBLE:
+ mTrebleKnobAdjusted++;
+ break;
+ case KnobCommander.KNOB_VIRTUALIZER:
+ mVirtualizerKnobAdjusted++;
+ break;
+ }
+ }
+
+ public void append(Event.Builder builder) {
+ builder.addField("session_source", mSource);
+ if (mDevicesChanged > 0)
+ builder.addField("session_devices_changed_count", mDevicesChanged);
+ if (mEnabledDisabledToggles > 0)
+ builder.addField("session_devices_enabled_disabled_count", mEnabledDisabledToggles);
+ if (mPresetsSelected > 0)
+ builder.addField("session_presets_changed_count", mPresetsSelected);
+ if (mPresetsCreated > 0)
+ builder.addField("session_presets_created_count", mPresetsCreated);
+ if (mPresetsRemoved > 0)
+ builder.addField("session_presets_removed_count", mPresetsRemoved);
+ if (mPresetsRenamed > 0)
+ builder.addField("session_presets_renamed_count", mPresetsRenamed);
+ if (mMaxxVolumeToggled > 0)
+ builder.addField("session_maxx_volume_toggled", mMaxxVolumeToggled);
+ if (mBassKnobAdjusted > 0)
+ builder.addField("session_knobs_bass_adjusted_count", mBassKnobAdjusted);
+ if (mVirtualizerKnobAdjusted > 0)
+ builder.addField("session_knobs_virtualizer_adjusted_count", mVirtualizerKnobAdjusted);
+ if (mTrebleKnobAdjusted > 0)
+ builder.addField("session_knobs_treble_adjusted_count", mTrebleKnobAdjusted);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder s = new StringBuilder(getClass().getName() + "[");
+ if (mSource != null) {
+ s.append("mSource=").append(mSource).append(", ");
+ }
+ if (mDevicesChanged > 0) {
+ s.append("mDevicesChanged=").append(mDevicesChanged).append(", ");
+ }
+ if (mEnabledDisabledToggles > 0) {
+ s.append("mEnabledDisabledToggles=").append(mEnabledDisabledToggles).append(", ");
+ }
+ if (mPresetsSelected > 0) {
+ s.append("mPresetsSelected=").append(mPresetsSelected).append(", ");
+ }
+ if (mPresetsCreated > 0) {
+ s.append("mPresetsCreated=").append(mPresetsCreated).append(", ");
+ }
+ if (mPresetsRemoved > 0) {
+ s.append("mPresetsRemoved=").append(mPresetsRemoved).append(", ");
+ }
+ if (mPresetsRenamed > 0) {
+ s.append("mPresetsRenamed=").append(mPresetsRenamed).append(", ");
+ }
+ if (mMaxxVolumeToggled > 0) {
+ s.append("mMaxxVolumeToggled=").append(mMaxxVolumeToggled).append(", ");
+ }
+ if (mBassKnobAdjusted > 0) {
+ s.append("mBassKnobAdjusted=").append(mBassKnobAdjusted).append(", ");
+ }
+ if (mVirtualizerKnobAdjusted > 0) {
+ s.append("mVirtualizerKnobAdjusted=").append(mVirtualizerKnobAdjusted).append(", ");
+ }
+ if (mTrebleKnobAdjusted > 0) {
+ s.append("mTrebleKnobAdjusted=").append(mTrebleKnobAdjusted).append(", ");
+ }
+ if (s.charAt(s.length() - 2) == ',') {
+ s.delete(s.length() - 2, s.length());
+ }
+ s.append("]");
+
+ return s.toString();
+ }
+
+ public static final Creator<UserSession> CREATOR = new Creator<UserSession>() {
+ @Override
+ public UserSession createFromParcel(Parcel in) {
+ return new UserSession(in);
+ }
+
+ @Override
+ public UserSession[] newArray(int size) {
+ return new UserSession[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ protected UserSession(Parcel in) {
+ mSource = in.readString();
+ mDevicesChanged = in.readInt();
+ mEnabledDisabledToggles = in.readInt();
+ mPresetsSelected = in.readInt();
+ mPresetsCreated = in.readInt();
+ mPresetsRemoved = in.readInt();
+ mPresetsRenamed = in.readInt();
+ mBassKnobAdjusted = in.readInt();
+ mVirtualizerKnobAdjusted = in.readInt();
+ mTrebleKnobAdjusted = in.readInt();
+ mMaxxVolumeToggled = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mSource);
+ dest.writeInt(mDevicesChanged);
+ dest.writeInt(mEnabledDisabledToggles);
+ dest.writeInt(mPresetsSelected);
+ dest.writeInt(mPresetsCreated);
+ dest.writeInt(mPresetsRemoved);
+ dest.writeInt(mPresetsRenamed);
+ dest.writeInt(mBassKnobAdjusted);
+ dest.writeInt(mVirtualizerKnobAdjusted);
+ dest.writeInt(mTrebleKnobAdjusted);
+ dest.writeInt(mMaxxVolumeToggled);
+ }
+
+ private static class State {
+ private String mOutputDevice;
+ private Preset mPreset;
+ private String mKnobsOpts;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/CirclePageIndicator.java b/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/CirclePageIndicator.java
new file mode 100644
index 0000000..b4b4a6b
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/CirclePageIndicator.java
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.cyngn.audiofx.viewpagerindicator;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.drawable.Drawable;
+import android.support.v4.view.MotionEventCompat;
+import android.support.v4.view.ViewConfigurationCompat;
+import android.support.v4.view.ViewPager;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import com.cyngn.audiofx.R;
+
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.widget.LinearLayout.HORIZONTAL;
+import static android.widget.LinearLayout.VERTICAL;
+
+/**
+ * Draws circles (one for each view). The current view position is filled and
+ * others are only stroked.
+ */
+public class CirclePageIndicator extends View implements PageIndicator {
+ private static final int INVALID_POINTER = -1;
+
+ private float mRadius;
+ private final Paint mPaintPageFill = new Paint(ANTI_ALIAS_FLAG);
+ private final Paint mPaintStroke = new Paint(ANTI_ALIAS_FLAG);
+ private final Paint mPaintFill = new Paint(ANTI_ALIAS_FLAG);
+ private ViewPager mViewPager;
+ private ViewPager.OnPageChangeListener mListener;
+ private int mCurrentPage;
+ private int mSnapPage;
+ private float mPageOffset;
+ private int mScrollState;
+ private int mOrientation;
+ private boolean mCentered;
+ private boolean mSnap;
+
+ private int mTouchSlop;
+ private float mLastMotionX = -1;
+ private int mActivePointerId = INVALID_POINTER;
+ private boolean mIsDragging;
+
+
+ public CirclePageIndicator(Context context) {
+ this(context, null);
+ }
+
+ public CirclePageIndicator(Context context, AttributeSet attrs) {
+ this(context, attrs, R.attr.vpiCirclePageIndicatorStyle);
+ }
+
+ public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ if (isInEditMode()) return;
+
+ //Load defaults from resources
+ final Resources res = getResources();
+ final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color);
+ final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color);
+ final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation);
+ final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color);
+ final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width);
+ final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius);
+ final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered);
+ final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap);
+
+ //Retrieve styles attributes
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, 0);
+
+ mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered);
+ mOrientation = a.getInt(R.styleable.CirclePageIndicator_android_orientation, defaultOrientation);
+ mPaintPageFill.setStyle(Style.FILL);
+ mPaintPageFill.setColor(a.getColor(R.styleable.CirclePageIndicator_pageColor, defaultPageColor));
+ mPaintStroke.setStyle(Style.STROKE);
+ mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor));
+ mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth));
+ mPaintFill.setStyle(Style.FILL);
+ mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor));
+ mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius);
+ mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap);
+
+ Drawable background = a.getDrawable(R.styleable.CirclePageIndicator_android_background);
+ if (background != null) {
+ setBackgroundDrawable(background);
+ }
+
+ a.recycle();
+
+ final ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);
+ }
+
+
+ public void setCentered(boolean centered) {
+ mCentered = centered;
+ invalidate();
+ }
+
+ public boolean isCentered() {
+ return mCentered;
+ }
+
+ public void setPageColor(int pageColor) {
+ mPaintPageFill.setColor(pageColor);
+ invalidate();
+ }
+
+ public int getPageColor() {
+ return mPaintPageFill.getColor();
+ }
+
+ public void setFillColor(int fillColor) {
+ mPaintFill.setColor(fillColor);
+ invalidate();
+ }
+
+ public int getFillColor() {
+ return mPaintFill.getColor();
+ }
+
+ public void setOrientation(int orientation) {
+ switch (orientation) {
+ case HORIZONTAL:
+ case VERTICAL:
+ mOrientation = orientation;
+ requestLayout();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL.");
+ }
+ }
+
+ public int getOrientation() {
+ return mOrientation;
+ }
+
+ public void setStrokeColor(int strokeColor) {
+ mPaintStroke.setColor(strokeColor);
+ invalidate();
+ }
+
+ public int getStrokeColor() {
+ return mPaintStroke.getColor();
+ }
+
+ public void setStrokeWidth(float strokeWidth) {
+ mPaintStroke.setStrokeWidth(strokeWidth);
+ invalidate();
+ }
+
+ public float getStrokeWidth() {
+ return mPaintStroke.getStrokeWidth();
+ }
+
+ public void setRadius(float radius) {
+ mRadius = radius;
+ invalidate();
+ }
+
+ public float getRadius() {
+ return mRadius;
+ }
+
+ public void setSnap(boolean snap) {
+ mSnap = snap;
+ invalidate();
+ }
+
+ public boolean isSnap() {
+ return mSnap;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mViewPager == null) {
+ return;
+ }
+ final int count = mViewPager.getAdapter().getCount();
+ if (count == 0) {
+ return;
+ }
+
+ if (mCurrentPage >= count) {
+ setCurrentItem(count - 1);
+ return;
+ }
+
+ int longSize;
+ int longPaddingBefore;
+ int longPaddingAfter;
+ int shortPaddingBefore;
+ if (mOrientation == HORIZONTAL) {
+ longSize = getWidth();
+ longPaddingBefore = getPaddingLeft();
+ longPaddingAfter = getPaddingRight();
+ shortPaddingBefore = getPaddingTop();
+ } else {
+ longSize = getHeight();
+ longPaddingBefore = getPaddingTop();
+ longPaddingAfter = getPaddingBottom();
+ shortPaddingBefore = getPaddingLeft();
+ }
+
+ final float threeRadius = mRadius * 3;
+ final float shortOffset = shortPaddingBefore + mRadius;
+ float longOffset = longPaddingBefore + mRadius;
+ if (mCentered) {
+ longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f);
+ }
+
+ float dX;
+ float dY;
+
+ float pageFillRadius = mRadius;
+ if (mPaintStroke.getStrokeWidth() > 0) {
+ pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f;
+ }
+
+ //Draw stroked circles
+ for (int iLoop = 0; iLoop < count; iLoop++) {
+ float drawLong = longOffset + (iLoop * threeRadius);
+ if (mOrientation == HORIZONTAL) {
+ dX = drawLong;
+ dY = shortOffset;
+ } else {
+ dX = shortOffset;
+ dY = drawLong;
+ }
+ // Only paint fill if not completely transparent
+ if (mPaintPageFill.getAlpha() > 0) {
+ canvas.drawCircle(dX, dY, (float) (pageFillRadius/1.5f), mPaintPageFill);
+ }
+
+ // Only paint stroke if a stroke width was non-zero
+ if (pageFillRadius != mRadius) {
+ canvas.drawCircle(dX, dY, mRadius, mPaintStroke);
+ }
+ }
+
+ //Draw the filled circle according to the current scroll
+ float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;
+ if (!mSnap) {
+ cx += mPageOffset * threeRadius;
+ }
+ if (mOrientation == HORIZONTAL) {
+ dX = longOffset + cx;
+ dY = shortOffset;
+ } else {
+ dX = shortOffset;
+ dY = longOffset + cx;
+ }
+ canvas.drawCircle(dX, dY, mRadius, mPaintFill);
+ }
+
+ public boolean onTouchEvent(android.view.MotionEvent ev) {
+ if (super.onTouchEvent(ev)) {
+ return true;
+ }
+ if ((mViewPager == null) || (mViewPager.getAdapter().getCount() == 0)) {
+ return false;
+ }
+
+ final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
+ switch (action) {
+ case MotionEvent.ACTION_DOWN:
+ mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
+ mLastMotionX = ev.getX();
+ break;
+
+ case MotionEvent.ACTION_MOVE: {
+ final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
+ final float x = MotionEventCompat.getX(ev, activePointerIndex);
+ final float deltaX = x - mLastMotionX;
+
+ if (!mIsDragging) {
+ if (Math.abs(deltaX) > mTouchSlop) {
+ mIsDragging = true;
+ }
+ }
+
+ if (mIsDragging) {
+ mLastMotionX = x;
+ if (mViewPager.isFakeDragging() || mViewPager.beginFakeDrag()) {
+ mViewPager.fakeDragBy(deltaX);
+ }
+ }
+
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (!mIsDragging) {
+ final int count = mViewPager.getAdapter().getCount();
+ final int width = getWidth();
+ final float halfWidth = width / 2f;
+ final float sixthWidth = width / 6f;
+
+ if ((mCurrentPage > 0) && (ev.getX() < halfWidth - sixthWidth)) {
+ if (action != MotionEvent.ACTION_CANCEL) {
+ mViewPager.setCurrentItem(mCurrentPage - 1);
+ }
+ return true;
+ } else if ((mCurrentPage < count - 1) && (ev.getX() > halfWidth + sixthWidth)) {
+ if (action != MotionEvent.ACTION_CANCEL) {
+ mViewPager.setCurrentItem(mCurrentPage + 1);
+ }
+ return true;
+ }
+ }
+
+ mIsDragging = false;
+ mActivePointerId = INVALID_POINTER;
+ if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
+ break;
+
+ case MotionEventCompat.ACTION_POINTER_DOWN: {
+ final int index = MotionEventCompat.getActionIndex(ev);
+ mLastMotionX = MotionEventCompat.getX(ev, index);
+ mActivePointerId = MotionEventCompat.getPointerId(ev, index);
+ break;
+ }
+
+ case MotionEventCompat.ACTION_POINTER_UP:
+ final int pointerIndex = MotionEventCompat.getActionIndex(ev);
+ final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
+ if (pointerId == mActivePointerId) {
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
+ }
+ mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
+ break;
+ }
+
+ return true;
+ }
+
+ @Override
+ public void setViewPager(ViewPager view) {
+ if (mViewPager == view) {
+ return;
+ }
+ if (mViewPager != null) {
+ mViewPager.setOnPageChangeListener(null);
+ }
+ if (view.getAdapter() == null) {
+ throw new IllegalStateException("ViewPager does not have adapter instance.");
+ }
+ mViewPager = view;
+ mViewPager.setOnPageChangeListener(this);
+ invalidate();
+ }
+
+ @Override
+ public void setViewPager(ViewPager view, int initialPosition) {
+ setViewPager(view);
+ setCurrentItem(initialPosition);
+ }
+
+ @Override
+ public void setCurrentItem(int item) {
+ if (mViewPager == null) {
+ throw new IllegalStateException("ViewPager has not been bound.");
+ }
+ mViewPager.setCurrentItem(item);
+ mCurrentPage = item;
+ invalidate();
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ invalidate();
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ mScrollState = state;
+
+ if (mListener != null) {
+ mListener.onPageScrollStateChanged(state);
+ }
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ mCurrentPage = position;
+ mPageOffset = positionOffset;
+ invalidate();
+
+ if (mListener != null) {
+ mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
+ }
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) {
+ mCurrentPage = position;
+ mSnapPage = position;
+ invalidate();
+ }
+
+ if (mListener != null) {
+ mListener.onPageSelected(position);
+ }
+ }
+
+ @Override
+ public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
+ mListener = listener;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View#onMeasure(int, int)
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (mOrientation == HORIZONTAL) {
+ setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec));
+ } else {
+ setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec));
+ }
+ }
+
+ /**
+ * Determines the width of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureLong(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) {
+ //We were told how big to be
+ result = specSize;
+ } else {
+ //Calculate the width according the views count
+ final int count = mViewPager.getAdapter().getCount();
+ result = (int)(getPaddingLeft() + getPaddingRight()
+ + (count * 2 * mRadius) + (count - 1) * mRadius + 1);
+ //Respect AT_MOST value if that was what is called for by measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines the height of this view
+ *
+ * @param measureSpec
+ * A measureSpec packed into an int
+ * @return The height of the view, honoring constraints from measureSpec
+ */
+ private int measureShort(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ //We were told how big to be
+ result = specSize;
+ } else {
+ //Measure the height
+ result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);
+ //Respect AT_MOST value if that was what is called for by measureSpec
+ if (specMode == MeasureSpec.AT_MOST) {
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/PageIndicator.java b/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/PageIndicator.java
new file mode 100644
index 0000000..131d53f
--- /dev/null
+++ b/src/org/cyanogenmod/audiofx/audiofx/viewpagerindicator/PageIndicator.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2011 Patrik Akerfeldt
+ * Copyright (C) 2011 Jake Wharton
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyngn.audiofx.viewpagerindicator;
+
+import android.support.v4.view.ViewPager;
+
+/**
+ * A PageIndicator is responsible to show an visual indicator on the total views
+ * number and the current visible view.
+ */
+public interface PageIndicator extends ViewPager.OnPageChangeListener {
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ */
+ void setViewPager(ViewPager view);
+
+ /**
+ * Bind the indicator to a ViewPager.
+ *
+ * @param view
+ * @param initialPosition
+ */
+ void setViewPager(ViewPager view, int initialPosition);
+
+ /**
+ * <p>Set the current page of both the ViewPager and indicator.</p>
+ *
+ * <p>This <strong>must</strong> be used if you need to set the page before
+ * the views are drawn on screen (e.g., default start page).</p>
+ *
+ * @param item
+ */
+ void setCurrentItem(int item);
+
+ /**
+ * Set a page change listener which will receive forwarded events.
+ *
+ * @param listener
+ */
+ void setOnPageChangeListener(ViewPager.OnPageChangeListener listener);
+
+ /**
+ * Notify the indicator that the fragment list has changed.
+ */
+ void notifyDataSetChanged();
+}
diff --git a/src/org/cyanogenmod/audiofx/widget/Biquad.java b/src/org/cyanogenmod/audiofx/audiofx/widget/Biquad.java
index f90153d..4486dfe 100644
--- a/src/org/cyanogenmod/audiofx/widget/Biquad.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/widget/Biquad.java
@@ -1,14 +1,14 @@
-package org.cyanogenmod.audiofx.widget;
+package com.cyngn.audiofx.widget;
/**
* Evaluate transfer functions of biquad filters in direct form 1.
*
* @author alankila
*/
-class Biquad {
+public class Biquad {
private Complex mB0, mB1, mB2, mA0, mA1, mA2;
- protected void setHighShelf(double centerFrequency, double samplingFrequency,
+ public void setHighShelf(double centerFrequency, double samplingFrequency,
double dbGain, double slope) {
double w0 = 2 * Math.PI * centerFrequency / samplingFrequency;
double a = Math.pow(10, dbGain/40);
@@ -22,7 +22,7 @@ class Biquad {
mA2 = new Complex((a+1) - (a-1) *Math.cos(w0) - 2*Math.sqrt(a)*alpha, 0);
}
- protected Complex evaluateTransfer(Complex z) {
+ public Complex evaluateTransfer(Complex z) {
Complex zSquared = z.mul(z);
Complex nom = mB0.add(mB1.div(z)).add(mB2.div(zSquared));
Complex den = mA0.add(mA1.div(z)).add(mA2.div(zSquared));
diff --git a/src/org/cyanogenmod/audiofx/widget/Complex.java b/src/org/cyanogenmod/audiofx/audiofx/widget/Complex.java
index b4691a3..dbbaaf2 100644
--- a/src/org/cyanogenmod/audiofx/widget/Complex.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/widget/Complex.java
@@ -1,14 +1,14 @@
-package org.cyanogenmod.audiofx.widget;
+package com.cyngn.audiofx.widget;
/**
* Java support for complex numbers.
*
* @author alankila
*/
-class Complex {
+public class Complex {
private final double mReal, mIm;
- protected Complex(double real, double im) {
+ public Complex(double real, double im) {
mReal = real;
mIm = im;
}
@@ -18,7 +18,7 @@ class Complex {
*
* @return length
*/
- protected double rho() {
+ public double rho() {
return Math.sqrt(mReal * mReal + mIm * mIm);
}
@@ -27,7 +27,7 @@ class Complex {
*
* @return angle in radians
*/
- protected double theta() {
+ public double theta() {
return Math.atan2(mIm, mReal);
}
@@ -36,7 +36,7 @@ class Complex {
*
* @return conjugate
*/
- protected Complex con() {
+ public Complex con() {
return new Complex(mReal, -mIm);
}
@@ -46,7 +46,7 @@ class Complex {
* @param other
* @return sum
*/
- protected Complex add(Complex other) {
+ public Complex add(Complex other) {
return new Complex(mReal + other.mReal, mIm + other.mIm);
}
@@ -56,7 +56,7 @@ class Complex {
* @param other
* @return multiplication result
*/
- protected Complex mul(Complex other) {
+ public Complex mul(Complex other) {
return new Complex(mReal * other.mReal - mIm * other.mIm,
mReal * other.mIm + mIm * other.mReal);
}
@@ -67,7 +67,7 @@ class Complex {
* @param a
* @return multiplication result
*/
- protected Complex mul(double a) {
+ public Complex mul(double a) {
return new Complex(mReal * a, mIm * a);
}
@@ -77,7 +77,7 @@ class Complex {
* @param other
* @return division result
*/
- protected Complex div(Complex other) {
+ public Complex div(Complex other) {
double lengthSquared = other.mReal * other.mReal + other.mIm * other.mIm;
return mul(other.con()).div(lengthSquared);
}
@@ -88,7 +88,7 @@ class Complex {
* @param a
* @return division result
*/
- protected Complex div(double a) {
+ public Complex div(double a) {
return new Complex(mReal / a, mIm / a);
}
}
diff --git a/src/org/cyanogenmod/audiofx/widget/EqualizerSurface.java b/src/org/cyanogenmod/audiofx/audiofx/widget/EqualizerSurface.java
index ff44c43..2b3c637 100644
--- a/src/org/cyanogenmod/audiofx/widget/EqualizerSurface.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/widget/EqualizerSurface.java
@@ -17,10 +17,9 @@
* - Modified extensively by cyanogen for multi-band support
*/
-package org.cyanogenmod.audiofx.widget;
+package com.cyngn.audiofx.widget;
import android.animation.Animator;
-import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
@@ -38,10 +37,8 @@ import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
-import org.cyanogenmod.audiofx.R;
+import com.cyngn.audiofx.R;
import java.util.Arrays;
@@ -77,7 +74,7 @@ public class EqualizerSurface extends SurfaceView implements ValueAnimator.Anima
setWillNotDraw(false);
mWhite = new Paint();
- mWhite.setColor(getResources().getColor(R.color.white));
+ mWhite.setColor(getResources().getColor(R.color.color_grey));
mWhite.setStyle(Style.STROKE);
mWhite.setTextSize(mTextSize = context.getResources().getDimensionPixelSize(R.dimen.eq_label_text_size));
mWhite.setTypeface(Typeface.DEFAULT_BOLD);
@@ -386,13 +383,17 @@ public class EqualizerSurface extends SurfaceView implements ValueAnimator.Anima
for (float dB = mMinDB + 3; dB <= mMaxDB - 3; dB += 3) {
float y = projectY(dB) * mHeight;
// canvas.drawLine(0, y, mWidth - 1, y, mGridLines);
- canvas.drawText(String.format("%+d", (int)dB), 1, (y - 1), mWhite);
+// canvas.drawText(String.format("%+d", (int)dB), 1, (y - 1), mWhite);
}
for (int i = 0; i < mNumBands; i ++) {
float freq = mCenterFreqs[i];
float x = projectX(freq) * mWidth;
+
float y = projectY(mLevels[i]) * (mHeight);
+
+ Log.i("eqsurface", i + " level: " + mLevels[i] + ", y: " + y);
+
String frequencyText = String.format(freq < 1000 ? "%.0f" : "%.0fk",
freq < 1000 ? freq : freq / 1000);
diff --git a/src/org/cyanogenmod/audiofx/widget/InterceptableLinearLayout.java b/src/org/cyanogenmod/audiofx/audiofx/widget/InterceptableLinearLayout.java
index c8d838a..ae0e8a0 100644
--- a/src/org/cyanogenmod/audiofx/widget/InterceptableLinearLayout.java
+++ b/src/org/cyanogenmod/audiofx/audiofx/widget/InterceptableLinearLayout.java
@@ -26,7 +26,7 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-package org.cyanogenmod.audiofx.widget;
+package com.cyngn.audiofx.widget;
import android.content.Context;
import android.util.AttributeSet;
@@ -53,6 +53,11 @@ public class InterceptableLinearLayout extends LinearLayout {
return mIntercept;
}
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+
public void setInterception(boolean intercept) {
mIntercept = intercept;
}
diff --git a/src/org/cyanogenmod/audiofx/widget/Gallery.java b/src/org/cyanogenmod/audiofx/widget/Gallery.java
deleted file mode 100644
index 8bb5f2a..0000000
--- a/src/org/cyanogenmod/audiofx/widget/Gallery.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.cyanogenmod.audiofx.widget;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.TextView;
-
-import org.cyanogenmod.audiofx.R;
-
-public class Gallery extends android.widget.Gallery {
- public interface OnItemSelectedListener {
- public void onItemSelected(int position);
- }
-
- private boolean mEnabled = false;
-
- private int mHighlightColor;
- private int mLowlightColor;
- private int mDisabledColor;
-
- private TextView mLastView = null;
- private OnItemSelectedListener mOnItemSelectedListener = null;
-
- public Gallery(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- Resources res = getResources();
- mHighlightColor = res.getColor(R.color.highlight);
- mLowlightColor = res.getColor(R.color.grey);
- mDisabledColor = res.getColor(R.color.disabled_gallery);
-
- setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- TextView tv = (TextView) view;
- if (tv != null) {
- tv.setTextColor(mEnabled ? mHighlightColor : mDisabledColor);
- }
- if (mLastView != null && mLastView != tv) {
- mLastView.setTextColor(mEnabled ? mLowlightColor : mDisabledColor);
- }
- mLastView = tv;
- if (mEnabled && mOnItemSelectedListener != null) {
- mOnItemSelectedListener.onItemSelected(position);
- }
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
- }
- });
- }
-
- public Gallery(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public Gallery(Context context) {
- this(context, null);
- }
-
- public void setOnItemSelectedListener(OnItemSelectedListener listener) {
- mOnItemSelectedListener = listener;
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
- final int count = getChildCount();
- for (int i = 0; i < count; ++i) {
- final View view = getChildAt(i);
- if (view instanceof TextView) {
- ((TextView) view).setTextColor(enabled ? mLowlightColor : mDisabledColor);
- }
- }
-
- if (enabled) {
- final TextView tv = (TextView) getSelectedView();
- if (tv != null) {
- tv.setTextColor(mHighlightColor);
- }
- }
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- return mEnabled ? super.onDown(e) : false;
- }
-}
diff --git a/src/org/cyanogenmod/audiofx/widget/Knob.java b/src/org/cyanogenmod/audiofx/widget/Knob.java
deleted file mode 100644
index ec3312d..0000000
--- a/src/org/cyanogenmod/audiofx/widget/Knob.java
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (c) 2013, The Linux Foundation. All rights reserved.
- * Copyright (c) 2014, The CyanogenMod Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package org.cyanogenmod.audiofx.widget;
-
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.RectF;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.lang.Math;
-
-import org.cyanogenmod.audiofx.R;
-
-public class Knob extends FrameLayout {
- private static final String TAG = Knob.class.getSimpleName();
-
- private static final int STROKE_WIDTH = 35;
- private static final float TEXT_SIZE = 0.20f;
- private static final float TEXT_PADDING = 0.31f;
- private static final float LABEL_PADDING = 0.02f;
- private static final float LABEL_SIZE = 0.08f;
- private static final float LABEL_WIDTH = 0.45f;
- private static final float INDICATOR_RADIUS = 0.38f;
- private ValueAnimator mAnimator;
-
- public interface OnKnobChangeListener {
- void onValueChanged(Knob knob, int value, boolean fromUser);
-
- boolean onSwitchChanged(Knob knob, boolean on);
-
- void onAnimationFinished(boolean endValue);
- }
-
- private OnKnobChangeListener mOnKnobChangeListener = null;
-
- private float mOriginalProgress = 0.0f;
- private float mProgress = 0.0f;
- private int mMax = 100;
- private boolean mOn = false;
- private boolean mEnabled = false;
-
- private int mHighlightColor;
- private int mLowlightColor;
- private int mDisabledColor;
-
- private final Paint mPaint;
-
- private final TextView mLabelTV;
- private final TextView mProgressTV;
-
- private final ImageView mKnobOn;
-
- private float mLastX;
- private float mLastY;
- private boolean mMoved;
-
- private int mWidth = 0;
- private int mIndicatorWidth = 0;
-
- private RectF mRectF;
-
- public Knob(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Knob, 0, 0);
-
- String label;
- int foreground;
- try {
- label = a.getString(R.styleable.Knob_label);
- foreground = a.getResourceId(R.styleable.Knob_foreground, R.drawable.knob);
- } finally {
- a.recycle();
- }
-
- LayoutInflater li = (LayoutInflater)
- context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- li.inflate(R.layout.knob, this, true);
-
- Resources res = getResources();
- mHighlightColor = res.getColor(R.color.highlight);
- mLowlightColor = res.getColor(R.color.lowlight);
- mDisabledColor = res.getColor(R.color.disabled_knob);
-
- ImageView fg = (ImageView) findViewById(R.id.knob_foreground);
- fg.setImageResource(R.drawable.knob);
-
- mLabelTV = (TextView) findViewById(R.id.knob_label);
- mLabelTV.setText(label);
- mProgressTV = (TextView) findViewById(R.id.knob_value);
-
- mKnobOn = (ImageView) findViewById(R.id.knob_toggle_on);
-
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setColor(mHighlightColor);
- mPaint.setStrokeWidth(65);
- mPaint.setStrokeCap(Paint.Cap.BUTT);
- mPaint.setStyle(Paint.Style.STROKE);
- mPaint.setShadowLayer(2, 1, -2, getResources().getColor(R.color.black));
-
- setWillNotDraw(false);
- }
-
- public Knob(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public Knob(Context context) {
- this(context, null);
- }
-
- public void setOnKnobChangeListener(OnKnobChangeListener l) {
- mOnKnobChangeListener = l;
- }
-
- public void setValue(int value) {
- if (mMax != 0) {
- mOriginalProgress = ((float) value) / mMax;
- if (mOriginalProgress > 100) {
- mOriginalProgress = 100;
- } else if (mOriginalProgress < 0) {
- mOriginalProgress = 0;
- }
-
- setProgress(mOriginalProgress);
- }
- }
-
- public void setProgress(float progress) {
- setProgress(progress, false);
- }
-
- public void updateProgressText(boolean showText, float progress) {
- if (showText) {
- mProgressTV.setText((int) (progress * 100) + "%");
- } else {
- mProgressTV.setText("--%");
- }
- }
-
- public void setProgress(float progress, boolean fromUser) {
- if (progress > 1.0f) {
- progress = 1.0f;
- } else if (progress < 0.0f) {
- progress = 0.0f;
- }
-
- mProgress = progress;
-
- updateProgressText(mEnabled && mOn, progress);
-
- invalidate();
-
- if (mOnKnobChangeListener != null) {
- mOnKnobChangeListener.onValueChanged(this, (int) (progress * mMax), fromUser);
- }
- }
-
- public void setMax(int max) {
- mMax = max;
- }
-
- public float getProgress() {
- return mProgress;
- }
-
- private void drawIndicator() {
- float r = mWidth * INDICATOR_RADIUS;
-// ImageView view = mEnabled ? mKnobOn : mKnobOff;
- mKnobOn.setTranslationX((float) Math.sin(mProgress * 2 * Math.PI) * r - mIndicatorWidth / 2);
- mKnobOn.setTranslationY((float) -Math.cos(mProgress * 2 * Math.PI) * r - mIndicatorWidth / 2);
- }
-
- @Override
- public void setEnabled(boolean enabled) {
- mEnabled = enabled;
-
- mLabelTV.setTextColor(mEnabled ? mHighlightColor : mDisabledColor);
- mProgressTV.setTextColor(mEnabled ? mHighlightColor : mDisabledColor);
- mPaint.setColor(mEnabled ? mHighlightColor : mDisabledColor);
-
-// if (enabled) {
-// mOn = true;
-// }
- if (enabled) {
- setOn(mOn, false);
- }
-// updateProgressText(mEnabled && mOn, mOriginalProgress);
-// } else {
-// }
-// invalidate();
- }
-
- public void setOn(final boolean on, boolean animate) {
- mOn = on;
-
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- if (mOriginalProgress > 1) {
- mOriginalProgress = 1;
- }
- if (animate) {
- if (on) {
- mAnimator = ValueAnimator.ofFloat(mProgress, mOriginalProgress);
- } else {
- mAnimator = ValueAnimator.ofFloat(mProgress, 0f);
- }
- mAnimator.setDuration(500);
- mAnimator.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mAnimator = null;
- updateProgressText(mOn && mEnabled, mOriginalProgress);
- if (mOnKnobChangeListener != null) {
- mOnKnobChangeListener.onAnimationFinished(on);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
-
- }
- });
- mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float progress = (Float) animation.getAnimatedValue();
- if (progress < 0) {
- progress = 0;
- } else if (progress > 1) {
- progress = 1;
- }
- mProgress = progress;
- if (mOnKnobChangeListener != null) {
- mOnKnobChangeListener.onValueChanged(Knob.this, (int) (progress * mMax), true);
- }
- updateProgressText(true, mProgress);
- invalidate();
- }
- });
- mAnimator.start();
- } else {
- updateProgressText(mEnabled && mOn, mOriginalProgress);
-
- // make progress correct value
- mProgress = mOn ? mOriginalProgress : 0f;
-
- invalidate();
-
- if (mOnKnobChangeListener != null) {
- mOnKnobChangeListener.onAnimationFinished(on);
- }
- }
-
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- drawIndicator();
- if (mEnabled) {
- canvas.drawArc(mRectF, -90, mProgress * 360, false, mPaint);
- }
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldW, int oldH) {
- int size = w > h ? h : w;
- mWidth = size;
- mIndicatorWidth = mKnobOn.getWidth();
-
- int diff;
- if (w > h) {
- diff = (w - h) / 2;
- mRectF = new RectF(STROKE_WIDTH + diff, STROKE_WIDTH,
- w - STROKE_WIDTH - diff, h - STROKE_WIDTH);
- } else {
- diff = (h - w) / 2;
- mRectF = new RectF(STROKE_WIDTH, STROKE_WIDTH + diff,
- w - STROKE_WIDTH, h - STROKE_WIDTH - diff);
- }
-
- mProgressTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, size * TEXT_SIZE);
- mProgressTV.setPadding(0, (int) (size * TEXT_PADDING), 0, 0);
- mProgressTV.setVisibility(View.VISIBLE);
- mLabelTV.setTextSize(TypedValue.COMPLEX_UNIT_PX, size * LABEL_SIZE);
- mLabelTV.setPadding(0, (int) (size * LABEL_PADDING), 0, 0);
- mLabelTV.setLayoutParams(new LinearLayout.LayoutParams((int) (w * LABEL_WIDTH),
- LayoutParams.WRAP_CONTENT));
- mLabelTV.setVisibility(View.VISIBLE);
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return true;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (mOn) {
- mLastX = event.getX();
- mLastY = event.getY();
- getParent().requestDisallowInterceptTouchEvent(true);
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (mOn) {
- float x = event.getX();
- float y = event.getY();
- float center = mWidth / 2;
- if (mMoved || (x - center) * (x - center) + (y - center) * (y - center)
- > center * center / 4) {
- float delta = getDelta(x, y);
- mOriginalProgress = mProgress + delta / 360;
- if (mOriginalProgress < 0) {
- mOriginalProgress = 0;
- } else if (mOriginalProgress > 100) {
- mOriginalProgress = 100;
- }
- setProgress(mOriginalProgress, true);
- mMoved = true;
- }
- mLastX = x;
- mLastY = y;
- }
- break;
- case MotionEvent.ACTION_UP:
- if (!mMoved) {
- if (mOnKnobChangeListener == null
- || mOnKnobChangeListener.onSwitchChanged(this, !mOn)) {
- if (mEnabled) {
- setOn(!mOn, true);
- invalidate();
- }
- }
- }
- mMoved = false;
- break;
- default:
- break;
- }
- return true;
- }
-
- private float getDelta(float x, float y) {
- float angle = angle(x, y);
- float oldAngle = angle(mLastX, mLastY);
- float delta = angle - oldAngle;
- if (delta >= 180.0f) {
- delta = -oldAngle;
- } else if (delta <= -180.0f) {
- delta = 360 - oldAngle;
- }
- return delta;
- }
-
- private float angle(float x, float y) {
- float center = mWidth / 2.0f;
- x -= center;
- y -= center;
-
- if (x == 0.0f) {
- if (y > 0.0f) {
- return 180.0f;
- } else {
- return 0.0f;
- }
- }
-
- float angle = (float) (Math.atan(y / x) / Math.PI * 180.0);
- if (x > 0.0f) {
- angle += 90;
- } else {
- angle += 270;
- }
- return angle;
- }
-}
diff --git a/src_effects/com/cyngn/audiofx/backends/EffectsFactory.java b/src_effects/com/cyngn/audiofx/backends/EffectsFactory.java
new file mode 100644
index 0000000..e33f5f5
--- /dev/null
+++ b/src_effects/com/cyngn/audiofx/backends/EffectsFactory.java
@@ -0,0 +1,35 @@
+package com.cyngn.audiofx.backends;
+
+import com.cyngn.audiofx.Constants;
+
+import android.content.Context;
+import android.media.AudioDeviceInfo;
+
+/**
+ * Creates an EffectSet appropriate for the current device
+ */
+public class EffectsFactory implements IEffectFactory {
+
+ private static final String TAG = "AudioFx-EffectsFactory";
+
+ private static int sBrand = -1; // cached value to not hit io every time we need a new effect
+
+ public EffectSet createEffectSet(Context context, int sessionId,
+ AudioDeviceInfo currentDevice) {
+ // if this throws, we're screwed, don't bother to recover. these
+ // are the standard effects that every android device must have,
+ // and if they don't exist we have bigger problems.
+ return new AndroidEffects(sessionId, currentDevice);
+ }
+
+ public static int getBrand() {
+ if (sBrand == -1) {
+ sBrand = getBrandInternal();
+ }
+ return sBrand;
+ }
+
+ private static int getBrandInternal() {
+ return Constants.EFFECT_TYPE_ANDROID;
+ }
+}
diff --git a/tests/Android.mk b/tests/Android.mk
new file mode 100644
index 0000000..a8dc5b9
--- /dev/null
+++ b/tests/Android.mk
@@ -0,0 +1,36 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := ModioFXTests
+LOCAL_INSTRUMENTATION_FOR := ModioFX
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ audiofx-android-support-test
+
+LOCAL_JAVA_LIBRARIES := \
+ android-support-v4 \
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_JACK_ENABLED := disabled
+
+# Sign the package when not using test-keys
+ifneq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/testkey)
+LOCAL_CERTIFICATE := cyngn-app
+else
+$(warning *** SIGNING MODIOFX WITH TEST KEY ***)
+endif
+
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ audiofx-android-support-test:lib/rules-0.3-release.jar
+
+include $(BUILD_MULTI_PREBUILT) \ No newline at end of file
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
new file mode 100644
index 0000000..151bd07
--- /dev/null
+++ b/tests/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.cyngn.audiofx.tests">
+
+ <application android:label="@string/app_name">
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".DebugActivity"
+ android:label="AudioFX Debug">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.cyngn.audiofx" />
+</manifest>
diff --git a/tests/README.md b/tests/README.md
new file mode 100644
index 0000000..24f8815
--- /dev/null
+++ b/tests/README.md
@@ -0,0 +1,5 @@
+## AudioFX Tests
+
+To run the tests (on a live device):
+
+ adb shell am instrument -w com.cyngn.audiofx.tests/android.support.test.runner.AndroidJUnitRunner \ No newline at end of file
diff --git a/tests/lib/rules-0.3-release.jar b/tests/lib/rules-0.3-release.jar
new file mode 100644
index 0000000..3302862
--- /dev/null
+++ b/tests/lib/rules-0.3-release.jar
Binary files differ
diff --git a/tests/res/raw/testmp3.mp3 b/tests/res/raw/testmp3.mp3
new file mode 100755
index 0000000..657faf7
--- /dev/null
+++ b/tests/res/raw/testmp3.mp3
Binary files differ
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
new file mode 100644
index 0000000..6c8112c
--- /dev/null
+++ b/tests/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<resources>
+ <string name="app_name">AudioFX Tests</string>
+</resources>
diff --git a/tests/src/com/cyngn/audiofx/PresetParcelTests.java b/tests/src/com/cyngn/audiofx/PresetParcelTests.java
new file mode 100644
index 0000000..8ea0c68
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/PresetParcelTests.java
@@ -0,0 +1,94 @@
+package com.cyngn.audiofx;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.cyngn.audiofx.Preset;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by roman on 9/29/15.
+ */
+@RunWith(AndroidJUnit4.class)
+public class PresetParcelTests {
+
+ private Preset.PermCustomPreset permPreset;
+ private Preset.PermCustomPreset permPresetCopy;
+ private Preset.CustomPreset customPreset;
+
+ @Before
+ public void setUp() throws Exception {
+ permPreset = new Preset.PermCustomPreset("test perm preset", new float[]{10, 50, 20, 30, 10000});
+ permPresetCopy = new Preset.PermCustomPreset("test perm preset", new float[]{10, 50, 20, 30, 10000});
+ customPreset = new Preset.CustomPreset("test custom preset", new float[]{10, 50, 20, 30, 10000}, false);
+ }
+
+ @Test
+ public void testPresetsEqual() {
+ assertNotEquals(permPreset, customPreset);
+ assertEquals(permPreset, permPresetCopy);
+ }
+
+ @Test
+ public void testPresetsFromString() {
+ final String permPresetTest = permPreset.toString();
+ final Preset.PermCustomPreset fromString = Preset.PermCustomPreset.fromString(permPresetTest);
+
+ assertEquals(permPreset, fromString);
+ }
+
+ @Test
+ public void testPermPresetParcelable() {
+ Parcel parcel = Parcel.obtain();
+
+ // write the parcel
+ permPreset.writeToParcel(parcel, 0);
+
+ // reset position for reading
+ parcel.setDataPosition(0);
+
+ // reconstruct object
+ final Preset.PermCustomPreset fromParcel = Preset.PermCustomPreset.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+
+ assertEquals(permPreset.getName(), fromParcel.getName());
+ assertPresetLevels(permPreset, fromParcel);
+
+ assertEquals(permPreset, fromParcel);
+ }
+
+ @Test
+ public void testCustomPresetParcelable() {
+ Parcel parcel = Parcel.obtain();
+
+ // write the parcel
+ customPreset.writeToParcel(parcel, 0);
+
+ // reset position for reading
+ parcel.setDataPosition(0);
+
+ // reconstruct object
+ final Preset.CustomPreset fromParcel = Preset.CustomPreset.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(fromParcel);
+
+ assertEquals(customPreset.getName(), fromParcel.getName());
+ assertPresetLevels(customPreset, fromParcel);
+ assertEquals(customPreset.isLocked(), fromParcel.isLocked());
+
+ assertEquals(customPreset, fromParcel);
+ }
+
+ private void assertPresetLevels(Preset p1, Preset p2) {
+ for(int i = 0; i < p1.getLevels().length; i++) {
+ assertEquals(p1.getLevels()[i], p2.getLevels()[i], 0);
+ }
+ }
+}
diff --git a/tests/src/com/cyngn/audiofx/eq/EqUtilTests.java b/tests/src/com/cyngn/audiofx/eq/EqUtilTests.java
new file mode 100644
index 0000000..bca4b85
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/eq/EqUtilTests.java
@@ -0,0 +1,40 @@
+package com.cyngn.audiofx.eq;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import com.cyngn.audiofx.Preset;
+import com.cyngn.audiofx.eq.EqUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Created by roman on 9/29/15.
+ */
+public class EqUtilTests {
+
+ private Preset.PermCustomPreset permPreset;
+ private Preset.PermCustomPreset permPresetCopy;
+ private Preset.CustomPreset customPreset;
+
+ @Before
+ public void setUp() throws Exception {
+ permPreset = new Preset.PermCustomPreset("test perm preset", new float[]{10, 50, 20, 30, 10000});
+ permPresetCopy = new Preset.PermCustomPreset("test perm preset", new float[]{10, 50, 20, 30, 10000});
+ customPreset = new Preset.CustomPreset("test custom preset", new float[]{10, 50, 20, 30, 10000}, false);
+ }
+
+ @Test
+ public void testConvertDecibelsToMillibels() {
+ final float[] convertedMillibels = EqUtils.convertDecibelsToMillibels(permPreset.getLevels());
+
+ float[] manualMillibels = new float[permPreset.getLevels().length];
+ for (int i = 0; i < manualMillibels.length; i++) {
+ manualMillibels[i] = permPreset.getLevels()[i] * 100;
+ }
+
+ for (int i = 0; i < manualMillibels.length; i++) {
+ Assert.assertEquals(manualMillibels[i], convertedMillibels[i], 0);
+ }
+ }
+
+}
diff --git a/tests/src/com/cyngn/audiofx/service/AudioFxServiceTests.java b/tests/src/com/cyngn/audiofx/service/AudioFxServiceTests.java
new file mode 100644
index 0000000..1bf531c
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/service/AudioFxServiceTests.java
@@ -0,0 +1,178 @@
+package com.cyngn.audiofx.service;
+
+import android.content.Intent;
+import android.media.audiofx.AudioEffect;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.util.Log;
+import com.cyngn.audiofx.util.BaseAudioFxServiceInstrumentationTest;
+import com.cyngn.audiofx.util.TestMediaPlayer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.cyngn.audiofx.tests.R;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by roman on 3/1/16.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AudioFxServiceTests extends BaseAudioFxServiceInstrumentationTest {
+
+ private static final String TAG = "AudioFxServiceTests";
+
+ private static final int SANE_MAX_LOOP_TIME = 1000 * 20; // 20 seconds !?
+ private static final int LOOP_SLEEP_TIME = 25;
+
+ TestMediaPlayer mPlayer;
+
+ @Before
+ public void setUp() throws Exception {
+ mPlayer = new TestMediaPlayer(getContext(), R.raw.testmp3);
+ assertNotNull(mPlayer);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (mPlayer != null) {
+ mPlayer.release();
+ mPlayer = null;
+ }
+ }
+
+ @Test
+ public void testServiceCreatesEffectsDirect() throws Exception {
+ setupService(); // this might be reused
+
+ Intent intent = new Intent(getTargetContext(), AudioFxService.class);
+ intent.setAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
+ intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mPlayer.getAudioSessionId());
+ intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getTargetContext().getPackageName());
+
+ mServiceRule.startService(intent);
+ Thread.sleep(100);
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+ }
+
+ @Test
+ public void testServiceDestroysEffectsDirect() throws Exception {
+ testServiceCreatesEffectsDirect();
+
+ Intent intent = new Intent(getTargetContext(), AudioFxService.class);
+ intent.setAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+ intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mPlayer.getAudioSessionId());
+ intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getTargetContext().getPackageName());
+
+ mServiceRule.startService(intent);
+
+ // sleep for 10s to let effects die
+ Thread.sleep(10100);
+ assertNull(mService.getEffect(mPlayer.getAudioSessionId()));
+ }
+
+ @Test
+ public void testServiceCreatesEffects() throws Exception {
+ setupService();
+
+ openFxSession(true);
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+ }
+
+ @Test
+ @LargeTest
+ public void testServiceDestroysEffects() throws Exception {
+ testServiceCreatesEffects();
+
+ closeFxSession(true);
+ // sleep for 10s to let effects die
+ assertNull(mService.getEffect(mPlayer.getAudioSessionId()));
+ }
+
+ @Test
+ public void testServiceDoesNotDestroyDeferredEffect() throws Exception {
+ setupService();
+ assertNull(mService.getEffect(mPlayer.getAudioSessionId()));
+
+ openFxSession(false);
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+
+ closeFxSession(false);
+ // shouldn't go away immediately after we close it
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+
+ Thread.sleep(8000);
+
+ // it should *still* be there not destroyed
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+
+ // reopen the session
+ openFxSession(false);
+
+ // session should still be there
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+
+ Thread.sleep(10000);
+
+ // it's been more than 10s (deferred destroy time) and we re-opened it, so it should be
+ // alive still
+ assertNotNull(mService.getEffect(mPlayer.getAudioSessionId()));
+ }
+
+ private void openFxSession(boolean block) throws InterruptedException {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
+ intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mPlayer.getAudioSessionId());
+ intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getTargetContext().getPackageName());
+ getContext().sendBroadcast(intent);
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ if (block) {
+ int cnt = 0;
+ while (mService.getEffect(mPlayer.getAudioSessionId()) == null
+ && (cnt * LOOP_SLEEP_TIME < SANE_MAX_LOOP_TIME)) {
+ cnt++;
+ Thread.sleep(LOOP_SLEEP_TIME);
+ }
+ Log.d(TAG, "took " + (cnt * LOOP_SLEEP_TIME) + "ms to open effect");
+ } else {
+ // TODO have a timeout here for failure based on time limits?
+ Thread.sleep(300);
+ }
+ }
+
+ private void closeFxSession(boolean block) throws InterruptedException {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ Intent intent = new Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
+ intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mPlayer.getAudioSessionId());
+ intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getTargetContext().getPackageName());
+ getContext().sendBroadcast(intent);
+ }
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ if (block) {
+ int cnt = 0;
+ while (mService.getEffect(mPlayer.getAudioSessionId()) != null
+ && (cnt * LOOP_SLEEP_TIME < SANE_MAX_LOOP_TIME)) {
+ cnt++;
+ Thread.sleep(LOOP_SLEEP_TIME);
+ }
+ Log.d(TAG, "took " + (cnt * LOOP_SLEEP_TIME) + "ms to close effect");
+ } else {
+ // TODO have a timeout here for failure based on time limits?
+ Thread.sleep(300);
+ }
+ }
+
+}
diff --git a/tests/src/com/cyngn/audiofx/tests/DebugActivity.java b/tests/src/com/cyngn/audiofx/tests/DebugActivity.java
new file mode 100644
index 0000000..9c98f59
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/tests/DebugActivity.java
@@ -0,0 +1,87 @@
+package com.cyngn.audiofx.tests;
+
+import android.media.AudioManager;
+import android.media.AudioSystem;
+import android.media.RingtoneManager;
+import android.os.AsyncTask;
+import android.util.Log;
+
+import com.cyngn.audiofx.util.TestDuckingMediaPlayer;
+
+/**
+ * Created by roman on 3/8/16.
+ */
+public class DebugActivity extends TestActivity {
+
+ @Override
+ protected String tag() {
+ return DebugActivity.class.getSimpleName();
+ }
+
+ @Override
+ protected Test[] tests() {
+ return new Test[]{
+ testAudioDucking()
+ };
+ }
+
+ private Test testAudioDucking() {
+ return new Test("Test Audio Ducking") {
+ @Override
+ protected void run() {
+ try {
+ final TestDuckingMediaPlayer songMediaPlayer = new TestDuckingMediaPlayer(getApplication());
+ songMediaPlayer.setAudioSessionId(AudioSystem.newAudioSessionId());
+ songMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ songMediaPlayer.setDataSource(getApplication(),
+ RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE));
+ songMediaPlayer.prepare();
+
+ final TestDuckingMediaPlayer interruptPlayer = new TestDuckingMediaPlayer(
+ DebugActivity.this, R.raw.testmp3);
+
+ final Integer focusResult = songMediaPlayer.start(AudioManager.AUDIOFOCUS_GAIN);
+ Log.d(tag(), "requestFocus returns: " + focusResult);
+
+ new AsyncTask<Void, Void, Void>() {
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ try {
+ Thread.sleep(400);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ interruptPlayer.start(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
+
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ interruptPlayer.stop();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ songMediaPlayer.stop();
+
+ interruptPlayer.release();
+ songMediaPlayer.release();
+
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ finish();
+ }
+ }
+ };
+ }
+}
diff --git a/tests/src/com/cyngn/audiofx/tests/TestActivity.java b/tests/src/com/cyngn/audiofx/tests/TestActivity.java
new file mode 100644
index 0000000..61a6b34
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/tests/TestActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.cyngn.audiofx.tests;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public abstract class TestActivity extends ListActivity
+{
+ Test[] mTests;
+
+ protected abstract String tag();
+ protected abstract Test[] tests();
+
+ protected abstract class Test {
+ protected String name;
+ protected Test(String n) {
+ name = n;
+ }
+ protected abstract void run();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mTests = tests();
+
+ String[] labels = new String[mTests.length];
+ for (int i=0; i<mTests.length; i++) {
+ labels[i] = mTests[i].name;
+ }
+
+ setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id)
+ {
+ Test t = mTests[position];
+ android.util.Log.d(tag(), "Test: " + t.name);
+ t.run();
+ }
+
+} \ No newline at end of file
diff --git a/tests/src/com/cyngn/audiofx/util/BaseAudioFxServiceInstrumentationTest.java b/tests/src/com/cyngn/audiofx/util/BaseAudioFxServiceInstrumentationTest.java
new file mode 100644
index 0000000..e882c9d
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/util/BaseAudioFxServiceInstrumentationTest.java
@@ -0,0 +1,59 @@
+package com.cyngn.audiofx.util;
+
+import android.content.Context;
+import android.content.Intent;
+import android.media.audiofx.AudioEffect;
+import android.os.IBinder;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.rule.ServiceTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import com.cyngn.audiofx.service.AudioFxService;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeoutException;
+
+import static org.junit.Assert.*;
+
+/**
+ * Created by roman on 3/1/16.
+ */
+@RunWith(AndroidJUnit4.class)
+public abstract class BaseAudioFxServiceInstrumentationTest {
+
+ private static final int MAX_ITERATION = 100;
+
+ protected AudioFxService.LocalBinder mService;
+
+ @Rule
+ public ServiceTestRule mServiceRule = new ServiceTestRule();
+
+ protected void setupService() throws TimeoutException {
+ int it = 0;
+
+ /**
+ * lol
+ * https://code.google.com/p/android/issues/detail?id=180396
+ */
+ IBinder binder;
+ while((binder = mServiceRule.bindService(
+ new Intent(InstrumentationRegistry.getTargetContext(),
+ AudioFxService.class))) == null && it < MAX_ITERATION){
+ it++;
+ }
+ mService = (AudioFxService.LocalBinder) binder;
+ assertNotNull(mService);
+ }
+
+ protected final Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
+
+ protected final Context getTargetContext() {
+ return InstrumentationRegistry.getTargetContext();
+ }
+
+}
diff --git a/tests/src/com/cyngn/audiofx/util/TestDuckingMediaPlayer.java b/tests/src/com/cyngn/audiofx/util/TestDuckingMediaPlayer.java
new file mode 100644
index 0000000..fc67cc2
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/util/TestDuckingMediaPlayer.java
@@ -0,0 +1,59 @@
+package com.cyngn.audiofx.util;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.util.Log;
+
+import com.cyngn.audiofx.tests.R;
+
+import static junit.framework.Assert.assertNotNull;
+
+/**
+ * Created by roman on 3/4/16.
+ */
+public class TestDuckingMediaPlayer extends TestMediaPlayer {
+
+ private static final String TAG = TestDuckingMediaPlayer.class.getSimpleName();
+ private AudioManager mAudioManager;
+
+ private AudioManager.OnAudioFocusChangeListener mAudioFocusChangeListener
+ = new AudioManager.OnAudioFocusChangeListener() {
+ public void onAudioFocusChange(int focusChange) {
+ Log.i(TAG, "onAudioFocusChange() called with " + "focusChange = [" + focusChange + "]");
+ switch(focusChange) {
+ case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
+ setVolume(0.4f);
+ break;
+
+ case AudioManager.AUDIOFOCUS_GAIN:
+ setVolume(1.f);
+ break;
+ }
+ }
+ };
+
+ public int start(int focus) throws IllegalStateException {
+ int result = mAudioManager.requestAudioFocus(mAudioFocusChangeListener, AudioManager.STREAM_MUSIC,
+ focus);
+ super.start();
+ return result;
+ }
+
+ @Override
+ public void stop() throws IllegalStateException {
+ mAudioManager.abandonAudioFocus(mAudioFocusChangeListener);
+ super.stop();
+ }
+
+ public TestDuckingMediaPlayer(Context context) {
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+ public TestDuckingMediaPlayer(Context context, int withResource) throws Exception {
+ super(context, withResource);
+ mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ }
+
+
+
+}
diff --git a/tests/src/com/cyngn/audiofx/util/TestMediaPlayer.java b/tests/src/com/cyngn/audiofx/util/TestMediaPlayer.java
new file mode 100644
index 0000000..ef08d1c
--- /dev/null
+++ b/tests/src/com/cyngn/audiofx/util/TestMediaPlayer.java
@@ -0,0 +1,31 @@
+package com.cyngn.audiofx.util;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.media.AudioAttributes;
+import android.media.AudioManager;
+import android.media.MediaPlayer;
+
+import com.cyngn.audiofx.tests.R;
+
+import static junit.framework.Assert.assertNotNull;
+
+/**
+ * Created by roman on 3/4/16.
+ */
+public class TestMediaPlayer extends MediaPlayer {
+
+ public TestMediaPlayer() {
+ setAudioStreamType(AudioManager.STREAM_MUSIC);
+ }
+
+ public TestMediaPlayer(Context testContext, int withResource) throws Exception {
+ this();
+ AssetFileDescriptor afd = testContext.getResources().openRawResourceFd(withResource);
+ assertNotNull(afd);
+ setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ prepare();
+ }
+
+}