├── app ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ ├── ic_trash.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_action_next.png │ │ │ │ ├── ic_action_play.png │ │ │ │ ├── ic_action_prev.png │ │ │ │ ├── ic_curr_pause.png │ │ │ │ ├── ic_curr_play.png │ │ │ │ ├── ic_menu_artist.png │ │ │ │ ├── ic_menu_edit.png │ │ │ │ ├── ic_menu_folded.png │ │ │ │ ├── ic_menu_folder.png │ │ │ │ ├── ic_menu_help.png │ │ │ │ ├── ic_menu_music.png │ │ │ │ ├── ic_menu_shake.png │ │ │ │ ├── ic_menu_skull.png │ │ │ │ ├── ic_menu_tree.png │ │ │ │ ├── ic_action_locked.png │ │ │ │ ├── ic_action_pause.png │ │ │ │ ├── ic_menu_settings.png │ │ │ │ ├── ic_menu_shuffle.png │ │ │ │ ├── ic_menu_text_big.png │ │ │ │ ├── ic_menu_unfolded.png │ │ │ │ ├── ic_action_close_pos.png │ │ │ │ ├── ic_action_goto_play.png │ │ │ │ ├── ic_action_open_pos.png │ │ │ │ ├── ic_action_unlocked.png │ │ │ │ ├── ic_default_coverart.gif │ │ │ │ ├── ic_menu_no_shuffle.png │ │ │ │ ├── ic_menu_repeat_all.png │ │ │ │ ├── ic_menu_repeat_one.png │ │ │ │ ├── ic_action_next_press.png │ │ │ │ ├── ic_action_play_press.png │ │ │ │ ├── ic_action_prev_press.png │ │ │ │ ├── ic_actionbar_launcher.png │ │ │ │ ├── ic_actionbar_overflow.png │ │ │ │ ├── ic_menu_repeat_group.png │ │ │ │ ├── ic_menu_shake_checked.png │ │ │ │ ├── ic_menu_text_regular.png │ │ │ │ ├── ic_actionbar_launcher_0.png │ │ │ │ ├── ic_actionbar_launcher_1.png │ │ │ │ ├── ic_actionbar_launcher_2.png │ │ │ │ ├── ic_actionbar_launcher_3.png │ │ │ │ ├── ic_actionbar_launcher_4.png │ │ │ │ ├── ic_actionbar_launcher_5.png │ │ │ │ ├── ic_actionbar_sublauncher.png │ │ │ │ ├── seekbar_primary_holo.9.png │ │ │ │ ├── seekbar_secondary_holo.9.png │ │ │ │ ├── ic_action_goto_play_press.png │ │ │ │ ├── seekbar_track_holo_light.9.png │ │ │ │ ├── fastscroll_thumb_default_holo.png │ │ │ │ ├── fastscroll_thumb_pressed_holo.png │ │ │ │ ├── seekbar_control_disabled_holo.png │ │ │ │ ├── seekbar_control_focused_holo.png │ │ │ │ ├── seekbar_control_normal_holo.png │ │ │ │ └── seekbar_control_pressed_holo.png │ │ │ ├── drawable-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── seekbar_primary_holo.9.png │ │ │ │ ├── seekbar_secondary_holo.9.png │ │ │ │ ├── seekbar_track_holo_light.9.png │ │ │ │ ├── fastscroll_thumb_default_holo.png │ │ │ │ ├── fastscroll_thumb_pressed_holo.png │ │ │ │ ├── seekbar_control_disabled_holo.png │ │ │ │ ├── seekbar_control_focused_holo.png │ │ │ │ ├── seekbar_control_normal_holo.png │ │ │ │ └── seekbar_control_pressed_holo.png │ │ │ ├── drawable-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── ic_actionbar_launcher.png │ │ │ │ ├── ic_actionbar_overflow.png │ │ │ │ ├── seekbar_primary_holo.9.png │ │ │ │ ├── seekbar_secondary_holo.9.png │ │ │ │ ├── seekbar_control_focused_holo.png │ │ │ │ ├── seekbar_control_normal_holo.png │ │ │ │ ├── seekbar_control_pressed_holo.png │ │ │ │ ├── seekbar_track_holo_light.9.png │ │ │ │ ├── fastscroll_thumb_default_holo.png │ │ │ │ ├── fastscroll_thumb_pressed_holo.png │ │ │ │ └── seekbar_control_disabled_holo.png │ │ │ ├── drawable-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── seekbar_primary_holo.9.png │ │ │ │ ├── seekbar_secondary_holo.9.png │ │ │ │ ├── seekbar_control_normal_holo.png │ │ │ │ ├── seekbar_track_holo_light.9.png │ │ │ │ ├── fastscroll_thumb_default_holo.png │ │ │ │ ├── fastscroll_thumb_pressed_holo.png │ │ │ │ ├── seekbar_control_disabled_holo.png │ │ │ │ ├── seekbar_control_focused_holo.png │ │ │ │ └── seekbar_control_pressed_holo.png │ │ │ ├── drawable │ │ │ │ ├── fastscroll_thumb_holo.xml │ │ │ │ ├── seekbar_control_selector_holo_light.xml │ │ │ │ ├── action_next.xml │ │ │ │ ├── action_play.xml │ │ │ │ ├── action_prev.xml │ │ │ │ ├── action_goto_play.xml │ │ │ │ ├── seekbar_horizontal_holo_light.xml │ │ │ │ └── ic_actionbar_launcher_anim.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── values-v11 │ │ │ │ ├── themes.xml │ │ │ │ └── styles.xml │ │ │ ├── menu │ │ │ │ └── menu_main.xml │ │ │ ├── layout │ │ │ │ └── song.xml │ │ │ ├── xml │ │ │ │ └── menu.xml │ │ │ └── values-sr │ │ │ │ └── strings.xml │ │ ├── java │ │ │ └── souch │ │ │ │ └── smp │ │ │ │ ├── Filter.java │ │ │ │ ├── RepeatMode.java │ │ │ │ ├── PrefKeys.java │ │ │ │ ├── RowViewHolder.java │ │ │ │ ├── PlayerState.java │ │ │ │ ├── Parameters.java │ │ │ │ ├── RowsAdapter.java │ │ │ │ ├── Row.java │ │ │ │ ├── OnSwipeTouchListener.java │ │ │ │ ├── Scrobble.java │ │ │ │ ├── RepeatingImageButton.java │ │ │ │ ├── RowGroup.java │ │ │ │ ├── ParametersImpl.java │ │ │ │ ├── MediaButtonIntentReceiver.java │ │ │ │ └── RowSong.java │ │ └── AndroidManifest.xml │ └── androidTest │ │ └── java │ │ └── souch │ │ └── smp │ │ ├── ApplicationTest.java │ │ ├── ParametersStub.java │ │ └── PathTest.java ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── misc ├── shuffle.png ├── UmlClass.dia ├── UmlClass.png ├── ic_launcher_trens.png ├── screenshots │ ├── screen3.5_artist.png │ ├── screen3.5_folder.png │ ├── screen4.7_folder.png │ ├── screen3.5_treefolder.png │ ├── screen4.7_treefolder.png │ ├── screen4.7_menu_settings.png │ ├── screen3.5_treefolder_big.png │ ├── screen4.7_treefolder_big.png │ └── screen3.5_menu_options_small.png ├── lock.svg ├── artist_ori.svg ├── music.svg ├── options.svg ├── edit.svg ├── question.svg ├── rescan.svg ├── play.svg ├── rewind.svg ├── straight.svg ├── folder.svg ├── text_big.svg ├── skull.svg ├── folded.svg ├── text_regular.svg ├── pause.svg ├── artist.svg ├── loop.svg ├── TODO.txt ├── Hammer_and_sickle.svg ├── unfolded.svg ├── loop_group.svg └── shake.svg ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── .idea ├── copyright │ └── profiles_settings.xml ├── vcs.xml ├── modules.xml ├── runConfigurations.xml ├── gradle.xml ├── compiler.xml └── misc.xml ├── Screenshots.md ├── SMP.iml ├── gradle.properties ├── gradlew.bat ├── README.md └── gradlew /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /misc/shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/shuffle.png -------------------------------------------------------------------------------- /misc/UmlClass.dia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/UmlClass.dia -------------------------------------------------------------------------------- /misc/UmlClass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/UmlClass.png -------------------------------------------------------------------------------- /misc/ic_launcher_trens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/ic_launcher_trens.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /local.properties 3 | /.idea/workspace.xml 4 | /.idea/libraries 5 | .DS_Store 6 | /build 7 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /misc/screenshots/screen3.5_artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen3.5_artist.png -------------------------------------------------------------------------------- /misc/screenshots/screen3.5_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen3.5_folder.png -------------------------------------------------------------------------------- /misc/screenshots/screen4.7_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen4.7_folder.png -------------------------------------------------------------------------------- /misc/screenshots/screen3.5_treefolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen3.5_treefolder.png -------------------------------------------------------------------------------- /misc/screenshots/screen4.7_treefolder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen4.7_treefolder.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_trash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_trash.png -------------------------------------------------------------------------------- /misc/screenshots/screen4.7_menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen4.7_menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /misc/screenshots/screen3.5_treefolder_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen3.5_treefolder_big.png -------------------------------------------------------------------------------- /misc/screenshots/screen4.7_treefolder_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen4.7_treefolder_big.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_prev.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_curr_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_curr_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_curr_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_curr_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_artist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_artist.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_edit.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_folded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_folded.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_folder.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_help.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_music.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_shake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_shake.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_skull.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_skull.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_tree.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /misc/screenshots/screen3.5_menu_options_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/misc/screenshots/screen3.5_menu_options_small.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_locked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_shuffle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_text_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_text_big.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_unfolded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_unfolded.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_close_pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_close_pos.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_goto_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_goto_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_open_pos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_open_pos.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_unlocked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_default_coverart.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_default_coverart.gif -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_no_shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_no_shuffle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_repeat_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_repeat_all.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_repeat_one.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_repeat_one.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_next_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_next_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_play_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_play_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_prev_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_prev_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_overflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_overflow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_repeat_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_repeat_group.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_shake_checked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_shake_checked.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_menu_text_regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_menu_text_regular.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_0.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_3.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_4.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_launcher_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_launcher_5.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_actionbar_sublauncher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_actionbar_sublauncher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_primary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_primary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_secondary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_secondary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_primary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_primary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_secondary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_secondary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_actionbar_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/ic_actionbar_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_actionbar_overflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/ic_actionbar_overflow.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_primary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_primary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_primary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_primary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_action_goto_play_press.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/ic_action_goto_play_press.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_track_holo_light.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_track_holo_light.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_track_holo_light.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_track_holo_light.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_secondary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_secondary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_secondary_holo.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_secondary_holo.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/fastscroll_thumb_default_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/fastscroll_thumb_default_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/fastscroll_thumb_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/fastscroll_thumb_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_control_disabled_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_control_disabled_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_control_focused_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_control_focused_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_control_normal_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/seekbar_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-hdpi/seekbar_control_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/fastscroll_thumb_default_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/fastscroll_thumb_default_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/fastscroll_thumb_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/fastscroll_thumb_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_control_disabled_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_control_disabled_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_control_focused_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_control_focused_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_control_normal_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/seekbar_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-mdpi/seekbar_control_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_control_focused_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_control_focused_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_control_normal_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_control_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_track_holo_light.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_track_holo_light.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_control_normal_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_control_normal_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_track_holo_light.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_track_holo_light.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/fastscroll_thumb_default_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/fastscroll_thumb_default_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/fastscroll_thumb_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/fastscroll_thumb_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/seekbar_control_disabled_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xhdpi/seekbar_control_disabled_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/fastscroll_thumb_default_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/fastscroll_thumb_default_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/fastscroll_thumb_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/fastscroll_thumb_pressed_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_control_disabled_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_control_disabled_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_control_focused_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_control_focused_holo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/seekbar_control_pressed_holo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/souch/SMP/HEAD/app/src/main/res/drawable-xxhdpi/seekbar_control_pressed_holo.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Screenshots.md: -------------------------------------------------------------------------------- 1 | 3.5" screen folder view 2 | 3 | ![Folder 3.5](misc/screenshots/screen3.5_folder.png) 4 | 5 | 4.7" screen 6 | 7 | ![Folder 4.7](misc/screenshots/screen4.7_treefolder.png)  8 | ![Menu settings](misc/screenshots/screen4.7_menu_settings.png) 9 | 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jun 01 13:03:28 CEST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/a/data/galaxy/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | -------------------------------------------------------------------------------- /SMP.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/Filter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public enum Filter { 22 | ARTIST, FOLDER, TREE, GENRE 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RepeatMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2017 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public enum RepeatMode { 22 | REPEAT_ALL, REPEAT_ONE, REPEAT_GROUP 23 | } 24 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | signingConfigs { 5 | release { 6 | } 7 | } 8 | compileSdkVersion 21 9 | buildToolsVersion '27.0.3' 10 | defaultConfig { 11 | applicationId "souch.smp" 12 | minSdkVersion 8 13 | targetSdkVersion 11 14 | versionCode 16 15 | versionName '1.4' 16 | } 17 | buildTypes { 18 | release { 19 | minifyEnabled false 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 22 | } 23 | debug { 24 | debuggable true 25 | } 26 | } 27 | productFlavors { 28 | } 29 | } 30 | 31 | dependencies { 32 | compile fileTree(include: ['*.jar'], dir: 'libs') 33 | androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.2.1' 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/fastscroll_thumb_holo.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 16dp 22 | 16dp 23 | 24 | -------------------------------------------------------------------------------- /misc/lock.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /misc/artist_ori.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 23 | 64dp 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/seekbar_control_selector_holo_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/action_next.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 22 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/action_play.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 22 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/action_prev.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 22 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/action_goto_play.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 22 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/androidTest/java/souch/smp/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.app.Application; 22 | import android.test.ApplicationTestCase; 23 | import android.test.InstrumentationTestCase; 24 | 25 | /** 26 | * Testing Fundamentals 27 | */ 28 | public class ApplicationTest extends ApplicationTestCase { 29 | public ApplicationTest() { 30 | super(Application.class); 31 | } 32 | } 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/PrefKeys.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public enum PrefKeys { 22 | SONG_ID, 23 | NO_LOCK, 24 | FOLLOW_SONG, 25 | ENABLE_SHAKE, 26 | SHAKE_THRESHOLD, 27 | FILTER, 28 | ROOT_FOLDERS, 29 | DEFAULT_FOLD, 30 | UNFOLD_SUBGROUP, 31 | UNFOLD_SUBGROUP_THRESHOLD, 32 | TEXT_SIZE_NORMAL, 33 | TEXT_SIZE_BIG, 34 | TEXT_SIZE_RATIO, 35 | TEXT_SIZE_CHOOSED, 36 | MEDIA_BUTTON_START_APP, 37 | VIBRATE, 38 | SHUFFLE, 39 | SCROBBLE, 40 | SONG_POS, 41 | SAVE_SONG_POS, 42 | REPEAT_MODE 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/seekbar_horizontal_holo_light.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 21 | 22 | 24 | 25 | 26 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RowViewHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.view.View; 22 | import android.widget.ImageView; 23 | import android.widget.RelativeLayout; 24 | import android.widget.TextView; 25 | 26 | public class RowViewHolder { 27 | public RowViewHolder(View view) { 28 | layout = (RelativeLayout) view.findViewById(R.id.song_layout); 29 | text = (TextView) view.findViewById(R.id.song_title); 30 | image = (ImageView) view.findViewById(R.id.curr_play); 31 | duration = (TextView) view.findViewById(R.id.song_duration); 32 | } 33 | 34 | public RelativeLayout layout; 35 | public TextView text; 36 | public TextView duration; 37 | public ImageView image; 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_actionbar_launcher_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 22 | 23 | 26 | 29 | 32 | 35 | 38 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 22 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/PlayerState.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public class PlayerState { 22 | static public final int Nope = 0b1; 23 | static public final int Idle = 0b10; 24 | static public final int Initialized = 0b100; 25 | static public final int Preparing = 0b1000; 26 | static public final int Prepared = 0b10000; 27 | static public final int Started = 0b100000; 28 | static public final int Paused = 0b1000000; 29 | static public final int PlaybackCompleted = 0b10000000; 30 | static public final int Stopped = 0b100000000; 31 | static public final int End = 0b1000000000; 32 | static public final int Error = 0b10000000000; 33 | 34 | private int state; 35 | 36 | public PlayerState() { 37 | state = Nope; 38 | } 39 | 40 | public void setState(int s) { 41 | state = s; 42 | } 43 | 44 | public int getState() { 45 | return state; 46 | } 47 | 48 | public boolean compare(int states) { 49 | return (state & states) != 0; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/Parameters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General License for more details. 14 | * 15 | * You should have received a copy of the GNU General License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public interface Parameters { 22 | boolean getNoLock(); 23 | void setNoLock(boolean noLock); 24 | 25 | boolean getFollowSong(); 26 | 27 | void setChooseTextSize(boolean big); 28 | boolean getChoosedTextSize(); 29 | int getBigTextSize(); 30 | int getNormalTextSize(); 31 | float getTextSizeRatio(); 32 | 33 | long getSongID(); 34 | void setSongID(long songID); 35 | 36 | boolean getSaveSongPos(); 37 | 38 | int getSongPos(); 39 | void setSongPos(int songPos); 40 | 41 | Filter getFilter(); 42 | void setFilter(Filter filter); 43 | 44 | RepeatMode getRepeatMode(); 45 | void setRepeatMode(RepeatMode repeatMode); 46 | 47 | String getRootFolders(); 48 | 49 | int getDefaultFold(); 50 | 51 | boolean getUnfoldSubGroup(); 52 | int getUnfoldSubGroupThreshold(); 53 | 54 | boolean getEnableShake(); 55 | void setEnableShake(boolean shakeEnabled); 56 | 57 | float getShakeThreshold(); 58 | 59 | boolean getMediaButtonStartAppShake(); 60 | 61 | boolean getVibrate(); 62 | 63 | void setShuffle(boolean shuffle); 64 | boolean getShuffle(); 65 | 66 | boolean getScrobble(); 67 | } 68 | -------------------------------------------------------------------------------- /misc/music.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 1.8 38 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /misc/options.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 48 | 50 | 52 | 54 | 60 | 64 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RowsAdapter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.Context; 22 | import android.view.LayoutInflater; 23 | import android.view.View; 24 | import android.view.ViewGroup; 25 | import android.widget.BaseAdapter; 26 | 27 | public class RowsAdapter extends BaseAdapter { 28 | private Rows rows; 29 | private LayoutInflater songInf; 30 | private Main main; 31 | 32 | 33 | public RowsAdapter(Context c, Rows theRows, Main mn) { 34 | rows = theRows; 35 | songInf = LayoutInflater.from(c); 36 | main = mn; 37 | } 38 | 39 | @Override 40 | public int getCount() { 41 | return rows.size(); 42 | } 43 | 44 | @Override 45 | public Object getItem(int arg0) { 46 | // TODO Auto-generated method stub 47 | return null; 48 | } 49 | 50 | @Override 51 | public long getItemId(int arg0) { 52 | // TODO Auto-generated method stub 53 | return 0; 54 | } 55 | 56 | 57 | @Override 58 | public View getView(int position, View convertView, ViewGroup parent) { 59 | View rowView = convertView; 60 | // reuse views 61 | if (rowView == null) { 62 | // map to song layout 63 | rowView = songInf.inflate(R.layout.song, parent, false); 64 | // configure view holder 65 | RowViewHolder viewHolder = new RowViewHolder(rowView); 66 | rowView.setTag(viewHolder); 67 | } 68 | 69 | RowViewHolder holder = (RowViewHolder) rowView.getTag(); 70 | 71 | rows.get(position).setView(holder, main, position); 72 | 73 | return rowView; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /misc/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/question.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 38 | 40 | 41 | 43 | image/svg+xml 44 | 46 | 47 | 48 | 49 | 50 | 54 | ? 68 | 69 | 70 | -------------------------------------------------------------------------------- /misc/rescan.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/play.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/main/res/layout/song.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 25 | 26 | 37 | 43 | 44 | 52 | 53 | 61 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /misc/rewind.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/straight.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /misc/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/text_big.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 52 | B 63 | -------------------------------------------------------------------------------- /misc/skull.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /misc/folded.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/text_regular.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml 55 | r 66 | -------------------------------------------------------------------------------- /misc/pause.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/androidTest/java/souch/smp/ParametersStub.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | public class ParametersStub implements Parameters { 22 | public ParametersStub() {} 23 | 24 | public boolean getNoLock() { return true; } 25 | public void setNoLock(boolean noLock) {} 26 | 27 | public boolean getFollowSong() { 28 | return true; 29 | } 30 | 31 | public void setChooseTextSize(boolean big) {} 32 | public boolean getChoosedTextSize() { 33 | return true; 34 | } 35 | public int getBigTextSize() { 36 | return 17; 37 | } 38 | public int getNormalTextSize() { 39 | return 15; 40 | } 41 | public float getTextSizeRatio() { 42 | return 1.1f; 43 | } 44 | 45 | 46 | public long getSongID() { 47 | return -1; 48 | } 49 | public void setSongID(long songID) {} 50 | 51 | public boolean getSaveSongPos() { 52 | return false; 53 | } 54 | 55 | public int getSongPos() { 56 | return -1; 57 | } 58 | public void setSongPos(int songPos) {} 59 | 60 | public Filter getFilter() { 61 | return Filter.FOLDER; 62 | } 63 | public void setFilter(Filter filter) {} 64 | 65 | public RepeatMode getRepeatMode() { 66 | return RepeatMode.REPEAT_ALL; 67 | } 68 | public void setRepeatMode(RepeatMode repeatMode) {} 69 | 70 | public String getRootFolders() { 71 | return ""; 72 | } 73 | 74 | 75 | public int getDefaultFold() { 76 | return 0; 77 | } 78 | 79 | public boolean getUnfoldSubGroup() { 80 | return true; 81 | } 82 | 83 | public int getUnfoldSubGroupThreshold() { 84 | return 20; 85 | } 86 | 87 | public boolean getEnableShake() { 88 | return false; 89 | } 90 | 91 | public void setEnableShake(boolean shakeEnabled) {} 92 | 93 | public float getShakeThreshold() { 94 | return 100; 95 | } 96 | 97 | public boolean getMediaButtonStartAppShake() { return true; } 98 | 99 | public boolean getVibrate() { return true; } 100 | 101 | public void setShuffle(boolean shuffle) {}; 102 | public boolean getShuffle() { return false; } 103 | 104 | public boolean getScrobble() { return false; } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/Row.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.res.Resources; 22 | import android.util.TypedValue; 23 | 24 | import java.util.HashMap; 25 | import java.util.Map; 26 | 27 | public class Row { 28 | // level from the left 29 | protected int level; 30 | // position of the row within the unfolded rows array 31 | protected int genuinePos; 32 | protected int typeface; 33 | // null if no parent 34 | protected Row parent; 35 | 36 | // must be set outside before calling setText 37 | public static int backgroundColor; 38 | public static int levelOffset; 39 | 40 | public Row(int position, int theLevel, int theTypeface) { 41 | genuinePos = position; 42 | level = theLevel; 43 | typeface = theTypeface; 44 | parent = null; 45 | } 46 | 47 | public void setGenuinePos(int position) { genuinePos = position; } 48 | public int getGenuinePos() { return genuinePos; } 49 | 50 | public Row getParent() { return parent; } 51 | public void setParent(Row parent) { this.parent = parent; } 52 | 53 | public int getLevel() { 54 | return level; 55 | } 56 | 57 | public void setLevel(int level) { 58 | this.level = level; 59 | } 60 | 61 | public void setView(RowViewHolder holder, Main main, int position) { 62 | holder.layout.setBackgroundColor(backgroundColor); 63 | holder.text.setTypeface(null, typeface); 64 | holder.text.setPadding(convertDpToPixels(level * levelOffset, holder.layout.getResources()), 0, 0, 0); 65 | } 66 | 67 | protected String getStringOffset() { 68 | String offset = "", s = " "; 69 | for(int i = level ; i > 0 ; i--) { 70 | offset += s; 71 | } 72 | return offset; 73 | } 74 | 75 | // cache result 76 | private static Map converted = new HashMap<>(); 77 | public static int convertDpToPixels(int dp, Resources resources) { 78 | int px; 79 | if (converted.containsKey(dp)) { 80 | px = converted.get(dp); 81 | } 82 | else { 83 | px = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, 84 | resources.getDisplayMetrics()); 85 | converted.put(dp, px); 86 | } 87 | return px; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /misc/artist.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /misc/loop.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 27 | 28 | 35 | 36 | #f30000 37 | 38 | #fff0f0f0 39 | #ffff0000 40 | #ffffffff 41 | #ffffffff 42 | #88000000 43 | #88353535 44 | #88000000 45 | #88353535 46 | #88000000 47 | #88353535 48 | 53 | 54 | 64 | 65 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /misc/TODO.txt: -------------------------------------------------------------------------------- 1 | # todo 2 | 3 | 4 | put everything related to view into XML 5 | fix lock/unlock not working on some (lots of) devices 6 | fix curr play icon when on last song row 7 | disable bluetooth on call? 8 | volume from app icon 9 | action bar for settings 10 | add slash at the end to folder? 11 | make settings icon fatter 12 | Fix rescan on every android version - on rescan finished, reinitSongs 13 | stop at the end of first stack / go to the next stack (go to beginning if at the end) 14 | adjust brightness when on no lock 15 | show cur song played in total when group folded : i.e. 5/13 (the group has 13 songs and the fifth is selected) 16 | zoom make letter (and button) bigger or smaller 17 | guess "smart" track number (2 < 11, song file name vs id tag, ...) 18 | long press on back button kill the app 19 | option: relock on pause even if unlocked 20 | 21 | 22 | # misc 23 | 24 | 22" at 1600x1200 25 | sqrt(1600*1600+1200*1200) 26 | 2000.00000000000000000000 27 | 2000/22 28 | 90.90909090909090909090 dpi 29 | hdpi:240 30 | xhdp:320 31 | 32 | http://androiddrawables.com/ 33 | http://stackoverflow.com/questions/8507726/sending-sms-to-from-a-device-from-to-an-android-virtual-device 34 | # make icon: 35 | http://romannurik.github.io/AndroidAssetStudio/icons-actionbar.html 36 | /opt/android-sdk-linux/platforms/android-10/data/res/ 37 | http://android-holo-colors.com/ 38 | 39 | # search free icon 40 | https://www.iconfinder.com/icons/103855/speaker_volume_icon#size=128 41 | https://www.iconfinder.com/icons/208018/audio_play_sound_start_video_icon#size=128 42 | https://www.iconfinder.com/icons/111044/closed_lock_secure_icon#size=64 43 | https://www.iconfinder.com/icons/344692/arrow_audio_media_music_outline_play_player_right_sound_video_icon#size=128 44 | 45 | # perf tips 46 | https://developer.android.com/training/articles/perf-tips.html 47 | 48 | # back key 49 | http://android-developers.blogspot.fr/2009/12/back-and-other-hard-keys-three-stories.html 50 | 51 | # listview 52 | http://www.vogella.com/tutorials/AndroidListView/article.html#androidlists 53 | http://udinic.wordpress.com/2011/07/01/selectablelistview-make-selection-work/ 54 | https://github.com/beworker/pinned-section-listview 55 | 56 | http://stackoverflow.com/questions/6208315/in-android-how-do-i-query-mediastore-only-for-files-in-a-specific-path-or-alte 57 | 58 | # list source code 59 | /opt/android-sdk-linux/sources/android-21/java/util/ArrayList.java 60 | 61 | # audio focus 62 | http://developer.android.com/guide/topics/media/mediaplayer.html#audiofocus 63 | 64 | # unicode table 65 | http://unicode-table.com/en/#028C 66 | 67 | # zoom 68 | http://android-developers.blogspot.fr/2010/06/making-sense-of-multitouch.html 69 | https://developer.android.com/training/gestures/multi.html 70 | 71 | # get f-droid installations number 72 | wget https://gitlab.com/fdroid/fdroiddata/raw/master/stats/total_downloads_app.txt -O - 2>/dev/null | sed 's/\([^ ]*\) \([^ ]*\)/\2 \1/' | sort -nr | less -N 73 | wget https://gitlab.com/fdroid/fdroiddata/raw/master/stats/total_downloads_app_version.txt -O - 2>/dev/null | grep souch.smp 74 | 75 | 76 | # example metadata f-droid 77 | https://gitlab.com/fdroid/fdroiddata/blob/master/metadata/org.adaway.txt 78 | 79 | setprop persist.sys.language sr;setprop persist.sys.country SR;stop;sleep 5;start 80 | setprop persist.sys.language fr;setprop persist.sys.country FR;stop;sleep 5;start 81 | 82 | # beat detection 83 | https://github.com/ddf/Minim/blob/master/src/ddf/minim/analysis/BeatDetect.java 84 | 85 | 86 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/OnSwipeTouchListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.Context; 22 | import android.view.GestureDetector; 23 | import android.view.GestureDetector.SimpleOnGestureListener; 24 | import android.view.MotionEvent; 25 | import android.view.View; 26 | import android.view.View.OnTouchListener; 27 | 28 | 29 | /** thanks to https://stackoverflow.com/questions/4139288/android-how-to-handle-right-to-left-swipe-gestures?rq=1 */ 30 | /** 31 | * Detects left and right swipes across a view. 32 | */ 33 | public class OnSwipeTouchListener implements OnTouchListener { 34 | 35 | private final GestureDetector gestureDetector; 36 | 37 | public OnSwipeTouchListener(Context context) { 38 | gestureDetector = new GestureDetector(context, new GestureListener()); 39 | } 40 | 41 | public void onSwipeLeft() { 42 | } 43 | 44 | public void onSwipeRight() { 45 | } 46 | 47 | public void onSwipeTop() { 48 | } 49 | 50 | public void onSwipeBottom() { 51 | } 52 | 53 | public void performClick() { 54 | } 55 | 56 | public boolean onTouch(View v, MotionEvent event) { 57 | return gestureDetector.onTouchEvent(event); 58 | } 59 | 60 | private final class GestureListener extends SimpleOnGestureListener { 61 | 62 | private static final int SWIPE_DISTANCE_THRESHOLD = 50; 63 | private static final int SWIPE_VELOCITY_THRESHOLD = 50; 64 | 65 | @Override 66 | public boolean onDown(MotionEvent e) { 67 | return true; 68 | } 69 | 70 | @Override 71 | public boolean onSingleTapUp(MotionEvent e) { 72 | performClick(); 73 | return true; 74 | } 75 | 76 | @Override 77 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 78 | float distanceX = e2.getX() - e1.getX(); 79 | float distanceY = e2.getY() - e1.getY(); 80 | if (Math.abs(distanceX) > Math.abs(distanceY) && Math.abs(distanceX) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { 81 | if (distanceX > 0) 82 | onSwipeRight(); 83 | else 84 | onSwipeLeft(); 85 | 86 | return true; 87 | } 88 | else if (Math.abs(distanceY) > Math.abs(distanceX) && Math.abs(distanceY) > SWIPE_DISTANCE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { 89 | if (distanceY > 0) 90 | onSwipeBottom(); 91 | else 92 | onSwipeTop(); 93 | 94 | return true; 95 | } 96 | return false; 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /misc/Hammer_and_sickle.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 23 | 25 | image/svg+xml 26 | 28 | 29 | 30 | 31 | 32 | 34 | 54 | 60 | 65 | 66 | -------------------------------------------------------------------------------- /misc/unfolded.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/Scrobble.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.Context; 22 | import android.content.Intent; 23 | import android.util.Log; 24 | 25 | public class Scrobble { 26 | private Rows rows; 27 | private Parameters params; 28 | private Context context; 29 | 30 | // from API spcecification 31 | public static final int SCROBBLE_START = 0; 32 | public static final int SCROBBLE_RESUME = 1; 33 | public static final int SCROBBLE_PAUSE = 2; 34 | public static final int SCROBBLE_COMPLETE = 3; 35 | 36 | private boolean started; 37 | private String artist; 38 | private String album; 39 | private String track; 40 | private int duration; 41 | 42 | 43 | public Scrobble(Rows rows, Parameters params, Context ctx) { 44 | this.rows = rows; 45 | this.params = params; 46 | this.context = ctx; 47 | 48 | started = false; 49 | } 50 | 51 | // can be called with SCROBBLE_COMPLETE state twice or more 52 | public void send(int scrobbleState) { 53 | if (!params.getScrobble()) 54 | return; 55 | 56 | RowSong rowSong = rows.getCurrSong(); 57 | if (rowSong == null) { 58 | Log.w("MusicService", "scrobbleSend exit as rowSong is null!"); 59 | return; 60 | } 61 | 62 | if (scrobbleState == SCROBBLE_START) { 63 | started = true; 64 | // save scrobble info for next state 65 | artist = rowSong.getArtist(); 66 | album = rowSong.getAlbum(); 67 | track = rowSong.getTitle(); 68 | duration = rowSong.getDuration(); 69 | } else if (scrobbleState == SCROBBLE_COMPLETE) { 70 | // send complete only if SCROBBLE_START was send before 71 | if (!started) 72 | return; 73 | 74 | started = false; 75 | } 76 | 77 | Intent bCast; 78 | // from https://github.com/tgwizard/sls/blob/master/Developer%27s%20API.md 79 | // do not enable Simple Last.FM Droid broadcast as Simple Last.FM Droid handles Scrobble Droid broadcast 80 | /* 81 | bCast = new Intent("com.adam.aslfms.notify.playstatechanged"); 82 | bCast.putExtra("state", scrobbleState); 83 | bCast.putExtra("app-name", context.getResources().getString(R.string.app_name)); 84 | bCast.putExtra("app-package", context.getPackageName()); 85 | bCast.putExtra("artist", artist); 86 | bCast.putExtra("album", album); 87 | bCast.putExtra("track", track); 88 | bCast.putExtra("duration", duration); 89 | bCast.putExtra("source", "P"); 90 | context.sendBroadcast(bCast); 91 | */ 92 | 93 | // from https://code.google.com/p/scrobbledroid/wiki/DeveloperAPI 94 | bCast = new Intent("net.jjc1138.android.scrobbler.action.MUSIC_STATUS"); 95 | bCast.putExtra("playing", scrobbleState == SCROBBLE_START || scrobbleState == SCROBBLE_RESUME); 96 | bCast.putExtra("artist", artist); 97 | bCast.putExtra("album", album); 98 | bCast.putExtra("track", track); 99 | bCast.putExtra("secs", duration); 100 | bCast.putExtra("source", "P"); 101 | context.sendBroadcast(bCast); 102 | 103 | Log.d("MusicService", "scrobbleSend " + scrobbleState + " : " + artist + " - " + track); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /misc/loop_group.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Moved to gitlab](https://gitlab.com/souch/SMP) 2 | 3 | 4 | ## SicMu Player for Android 5 | 6 | Every songs of the phone are put in a unique big song list. 7 | 8 | Songs are sorted and grouped by folders, artists, albums and album's track. 9 | 10 | Works on old slow small devices (from Android froyo 2.2). 11 | 12 | 13 | 3.5" screen: 14 | 15 | ![Tree folder list](misc/screenshots/screen3.5_treefolder.png)  16 | ![Artist list](misc/screenshots/screen3.5_artist.png) 17 | ![Menu option](misc/screenshots/screen3.5_menu_options_small.png) 18 | 19 | [Video](http://youtu.be/LGyjDfwimzA) 20 | 21 | [More screenshots](Screenshots.md) 22 | 23 | ### Installation 24 | 25 | [Get it on F-Droid](https://f-droid.org/repository/browse/?fdid=souch.smp) 26 | [Get it on Google Play](https://play.google.com/store/apps/details?id=souch.smp) 27 | 28 | ### Detailed features 29 | 30 | - sorted by artists, albums and track number 31 | - or sorted by folder tree, useful for big music list 32 | - or sorted by folders, artists, albums and track number, flattening folder hierarchy 33 | - groups can be folded / unfolded 34 | - repeat mode (all, group, one track) 35 | - shake the phone to go to next song 36 | - show current playing song in the list 37 | - notification when playing 38 | - seek bar 39 | - disable / enable lockscreen 40 | - configurable font size 41 | - on app startup, scroll to last song played 42 | - play mp3, ogg, flac, midi, wav, mp4, 3gp... see android mediaplayer supported media formats (depends on android version). 43 | - bluetooth support (play through bluetooth device) 44 | - media buttons support (next, prev, play/pause) from external device (bluetooth headphones...) 45 | - light and fast: starts in 0.5s and uses 10Mo of RAM with 5Go of music (1000 files, 100 folders) on a 700MHz ARM processor. 46 | - support [Simple Last.fm Scrobbler](https://github.com/tgwizard/sls) or [Scrobble Droid](https://code.google.com/p/scrobbledroid) (disabled by default in settings) 47 | 48 | 49 | ### Help 50 | 51 | - see help section in app's settings 52 | 53 | 54 | ### Todo (perhaps :-) 55 | 56 | - group by genre? 57 | - quick jump with letter in the right (like in contact)? 58 | - search? 59 | - pinned section (upper group level stay at top until another one appears)? 60 | - swipe to go to list of song <-> song details 61 | - mp3 tag editor ? 62 | - playlist? 63 | - audioeffect/equalizer 64 | - turning disc speed follow musics beat 65 | 66 | Detailed todo list available in [TODO.txt](misc/TODO.txt). 67 | 68 | 69 | ### Credits 70 | 71 | Lot's of time saved thanks to Sue Smith's [tutorials on creating a Music Player on Android](http://code.tutsplus.com/tutorials/create-a-music-player-on-android-project-setup--mobile-22764). 72 | 73 | Use some icons done by Daniele De Santis (Creative Commons Attribution 3.0 Unported), found on iconfinder.com. 74 | 75 | Seekbar style created by Jérôme Van Der Linden (Creative Commons Attribution 3.0 Unported), found on http://android-holo-colors.com. 76 | 77 | RepeatingImageButton.java and MediaButtonIntentReceiver.java file mostly copied from official android music player (Apache License, Version 2.0). 78 | 79 | 80 | ### Developer 81 | 82 | Compiled with Android Studio. 83 | Non regression tests are available in the androidTest folder. 84 | Tested on Gingerbread (2.3.6), Nexus 4 JellyBean (4.1.2), Samsung S3 (4.3), Nexus 5 Lollipop (5.0). 85 | 86 | Feel free to add GitHub issues (feature request, bugs...). 87 | If you need a feature that is in the todolist, open a feature request on github to speed up its development. 88 | 89 | A UML class diagram describe a bit the architecture for people that would want to develop the software [UmlClass.png](misc/UmlClass.png). 90 | 91 | SicMu player pronounced zicmu. S is for Super Simple Sorted Souch player. 92 | 93 | 94 | ### Donation 95 | 96 | If you don't know what to do with your money or want to make me smile the whole day: 97 | [donate](http://rodolphe.souchaud.free.fr/donate) 98 | 99 | 100 | ### License 101 | 102 | SicMu Player is licensed under the GPLv3. See file [LICENSE](LICENSE) for more details. 103 | 104 | -------------------------------------------------------------------------------- /misc/shake.svg: -------------------------------------------------------------------------------- 1 | 2 | image/svg+xml -------------------------------------------------------------------------------- /app/src/androidTest/java/souch/smp/PathTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.test.AndroidTestCase; 22 | import android.util.Log; 23 | 24 | import java.util.ArrayList; 25 | 26 | public class PathTest extends AndroidTestCase { 27 | 28 | public void setUp() throws Exception { 29 | super.setUp(); 30 | Log.d("PathTest", "===================================="); 31 | } 32 | 33 | public void testGetFolderEmpty() throws Exception { 34 | tryGetFolder("", "."); 35 | } 36 | 37 | public void testGetFolderUsual() throws Exception { 38 | Path.rootFolders = "/mnt/sdcard"; 39 | tryGetFolder("/mnt/sdcard/toto/tata.mp3", "toto"); 40 | } 41 | 42 | public void testGetFolderUsual2() throws Exception { 43 | Path.rootFolders = "/mnt/sdcard"; 44 | tryGetFolder("/mnt/sdcard/toto/titi/tata.mp3", "toto/titi"); 45 | } 46 | 47 | public void testGetFolderUsualSlashRootFolder() throws Exception { 48 | Path.rootFolders = "/mnt/sdcard/"; 49 | tryGetFolder("/mnt/sdcard/toto/titi/tata.mp3", "toto/titi"); 50 | } 51 | 52 | public void testGetFolderAllRootFolder() throws Exception { 53 | Path.rootFolders = "/mnt/sdcard"; 54 | tryGetFolder("/mnt/sdcard/tata.mp3", "."); 55 | 56 | Path.rootFolders = "/mnt/sdcard/"; 57 | tryGetFolder("/mnt/sdcard/tata.mp3", "."); 58 | } 59 | 60 | public void testGetFolderMangleRootFolder() throws Exception { 61 | Path.rootFolders = "/mnt/sdcard"; 62 | tryGetFolder("/mnt/sdcard.mp3", "."); 63 | 64 | Path.rootFolders = "/mnt/sdcard/"; 65 | tryGetFolder("/mnt/sdcard.mp3", "/mnt"); 66 | } 67 | 68 | private void tryGetFolder(String path, String expectedFolder) throws Exception { 69 | String folder = Path.getFolder(path); 70 | if (!folder.equals(expectedFolder)) { 71 | String msg = "Expected '" + expectedFolder + "' got: '" + folder + "'"; 72 | Log.d("PathTest", msg); 73 | throw new Exception(msg); 74 | } 75 | } 76 | 77 | 78 | public void testTokenizeFolderUsual() throws Exception { 79 | tryTokenizeFolder("/mnt/sdcard/toto", new String[]{"mnt", "sdcard", "toto"}); 80 | tryTokenizeFolder("/mnt/sdcard/toto/", new String[]{"mnt", "sdcard", "toto"}); 81 | tryTokenizeFolder("/mnt/sdcard/toto/o", new String[]{"mnt", "sdcard", "toto", "o"}); 82 | } 83 | 84 | public void testTokenizeFolderOne() throws Exception { 85 | tryTokenizeFolder("/mnt/", new String[]{"mnt"}); 86 | tryTokenizeFolder("/mnt", new String[]{"mnt"}); 87 | } 88 | 89 | public void testTokenizeFolderStrange() throws Exception { 90 | tryTokenizeFolder("/./", new String[]{"."}); 91 | tryTokenizeFolder(".", new String[]{"."}); 92 | tryTokenizeFolder("/toot///yo", new String[]{"toot", "yo"}); 93 | tryTokenizeFolder("/toot///", new String[]{"toot"}); 94 | tryTokenizeFolder("//", new String[]{}); 95 | tryTokenizeFolder("/", new String[]{}); 96 | tryTokenizeFolder("", new String[]{}); 97 | } 98 | 99 | private void tryTokenizeFolder(String folder, String[] expectedFolders) throws Exception { 100 | ArrayList folders = Path.tokenizeFolder(folder); 101 | if (folders.size() != expectedFolders.length) { 102 | String msg = "Expected folder length'" + expectedFolders.length + "' got: '" + folders.size() + "'"; 103 | Log.d("PathTest", msg); 104 | throw new Exception(msg); 105 | } 106 | for(int i = 0; i < folders.size(); i++) { 107 | if (!folders.get(i).equals(expectedFolders[i])) { 108 | String msg = "Expected folder " + expectedFolders[i] + "' got: '" + folders.get(i) + "'"; 109 | Log.d("PathTest", msg); 110 | throw new Exception(msg); 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RepeatingImageButton.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file has been copied from official android music player (Apache License, Version 2.0). 18 | package souch.smp; 19 | 20 | import android.content.Context; 21 | import android.os.SystemClock; 22 | import android.util.AttributeSet; 23 | import android.view.KeyEvent; 24 | import android.view.MotionEvent; 25 | import android.view.View; 26 | import android.widget.ImageButton; 27 | 28 | /** 29 | * A button that will repeatedly call a 'listener' method 30 | * as long as the button is pressed. 31 | */ 32 | public class RepeatingImageButton extends ImageButton { 33 | 34 | private long mStartTime; 35 | private int mRepeatCount; 36 | private RepeatListener mListener; 37 | private long mInterval = 500; 38 | 39 | public RepeatingImageButton(Context context) { 40 | this(context, null); 41 | } 42 | 43 | public RepeatingImageButton(Context context, AttributeSet attrs) { 44 | this(context, attrs, android.R.attr.imageButtonStyle); 45 | } 46 | 47 | public RepeatingImageButton(Context context, AttributeSet attrs, int defStyle) { 48 | super(context, attrs, defStyle); 49 | setFocusable(true); 50 | setLongClickable(true); 51 | } 52 | 53 | /** 54 | * Sets the listener to be called while the button is pressed and 55 | * the interval in milliseconds with which it will be called. 56 | * @param l The listener that will be called 57 | * @param interval The interval in milliseconds for calls 58 | */ 59 | public void setRepeatListener(RepeatListener l, long interval) { 60 | mListener = l; 61 | mInterval = interval; 62 | } 63 | 64 | @Override 65 | public boolean performLongClick() { 66 | mStartTime = SystemClock.elapsedRealtime(); 67 | mRepeatCount = 0; 68 | post(mRepeater); 69 | return true; 70 | } 71 | 72 | @Override 73 | public boolean onTouchEvent(MotionEvent event) { 74 | if (event.getAction() == MotionEvent.ACTION_UP) { 75 | // remove the repeater, but call the hook one more time 76 | removeCallbacks(mRepeater); 77 | if (mStartTime != 0) { 78 | doRepeat(true); 79 | mStartTime = 0; 80 | } 81 | } 82 | return super.onTouchEvent(event); 83 | } 84 | 85 | @Override 86 | public boolean onKeyDown(int keyCode, KeyEvent event) { 87 | switch (keyCode) { 88 | case KeyEvent.KEYCODE_DPAD_CENTER: 89 | case KeyEvent.KEYCODE_ENTER: 90 | // need to call super to make long press work, but return 91 | // true so that the application doesn't get the down event. 92 | super.onKeyDown(keyCode, event); 93 | return true; 94 | } 95 | return super.onKeyDown(keyCode, event); 96 | } 97 | 98 | @Override 99 | public boolean onKeyUp(int keyCode, KeyEvent event) { 100 | switch (keyCode) { 101 | case KeyEvent.KEYCODE_DPAD_CENTER: 102 | case KeyEvent.KEYCODE_ENTER: 103 | // remove the repeater, but call the hook one more time 104 | removeCallbacks(mRepeater); 105 | if (mStartTime != 0) { 106 | doRepeat(true); 107 | mStartTime = 0; 108 | } 109 | } 110 | return super.onKeyUp(keyCode, event); 111 | } 112 | 113 | private Runnable mRepeater = new Runnable() { 114 | public void run() { 115 | doRepeat(false); 116 | if (isPressed()) { 117 | postDelayed(this, mInterval); 118 | } 119 | } 120 | }; 121 | 122 | private void doRepeat(boolean last) { 123 | long now = SystemClock.elapsedRealtime(); 124 | if (mListener != null) { 125 | mListener.onRepeat(this, now - mStartTime, last ? -1 : mRepeatCount++); 126 | } 127 | } 128 | 129 | public interface RepeatListener { 130 | /** 131 | * This method will be called repeatedly at roughly the interval 132 | * specified in setRepeatListener(), for as long as the button 133 | * is pressed. 134 | * @param v The button as a View. 135 | * @param duration The number of milliseconds the button has been pressed so far. 136 | * @param repeatcount The number of previous calls in this sequence. 137 | * If this is going to be the last call in this sequence (i.e. the user 138 | * just stopped pressing the button), the value will be -1. 139 | */ 140 | void onRepeat(View v, long duration, int repeatcount); 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RowGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.graphics.Typeface; 22 | import android.util.TypedValue; 23 | import android.widget.TextView; 24 | 25 | public class RowGroup extends Row { 26 | protected String name; 27 | protected boolean folded; 28 | protected boolean selected; 29 | private int color; 30 | private int nbRowSong; 31 | public static Filter rowType; 32 | protected static int textSize = 18; 33 | 34 | // must be set outside before calling setText 35 | public static int normalTextColor; 36 | public static int playingTextColor; 37 | 38 | public RowGroup(int pos, int level, String name, int typeface, int color) { 39 | super(pos, level, typeface); 40 | this.name = name; 41 | folded = false; 42 | selected = false; 43 | this.color = color; 44 | } 45 | 46 | public String getName() { return name; } 47 | 48 | public boolean isFolded() { return folded; } 49 | public void setFolded(boolean fold) { folded = fold; } 50 | 51 | public void setSelected(boolean selected) { this.selected = selected; } 52 | public boolean isSelected() { return selected; } 53 | 54 | // get number of songs (excluding RowGroup) inside this group 55 | public int nbRowSong() { return nbRowSong; } 56 | public void incNbRowSong() { nbRowSong++; } 57 | 58 | public void setView(RowViewHolder holder, Main main, int position) { 59 | super.setView(holder, main, position); 60 | 61 | float factor = 1.5f; 62 | if (main.getMusicSrv().getRows().isLastRow(position)) 63 | factor = 3f; 64 | holder.layout.getLayoutParams().height = convertDpToPixels((int) (textSize * factor), 65 | holder.layout.getResources()); 66 | 67 | setText(holder.text); 68 | setDuration(holder.duration); 69 | holder.image.setImageResource(android.R.color.transparent); 70 | 71 | holder.layout.setBackgroundColor(color); 72 | } 73 | 74 | private void setText(TextView text) { 75 | String prefix = ""; 76 | if (rowType == Filter.TREE) { 77 | if (isFolded()) 78 | prefix = "| "; 79 | else 80 | prefix = "\\ "; 81 | 82 | } 83 | text.setText(prefix + name); 84 | 85 | if (isFolded() && isSelected()) 86 | text.setTextColor(playingTextColor); 87 | else 88 | text.setTextColor(normalTextColor); 89 | 90 | text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize); 91 | //text.setPaintFlags(text.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); 92 | //text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16); 93 | } 94 | 95 | private void setDuration(TextView duration) { 96 | String rightSpace = getStringOffset(); 97 | //super.setText(text); 98 | if (isFolded()) { 99 | if (isSelected()) 100 | duration.setTextColor(playingTextColor); 101 | else 102 | duration.setTextColor(normalTextColor); 103 | duration.setText(nbRowSong + " |" + rightSpace); 104 | } 105 | else { 106 | duration.setText("/" + rightSpace); 107 | duration.setTextColor(normalTextColor); 108 | } 109 | 110 | duration.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize); 111 | duration.setTypeface(null, typeface == Typeface.ITALIC ? Typeface.NORMAL : typeface); 112 | /* 113 | duration.setBackgroundColor(Color.argb(0x88, 0x30, 0x30, 0x30)); 114 | duration.setId(position); 115 | duration.setOnClickListener(new View.OnClickListener() { 116 | public void onClick(View durationView) { 117 | Log.d("Main", "durationView.getId(): " + durationView.getId()); 118 | durationView.setBackgroundColor(Color.argb(0x88, 0x65, 0x65, 0x65)); 119 | 120 | class InvertFold implements Runnable { 121 | View view; 122 | InvertFold(View view) { this.view = view; } 123 | public void run() { 124 | main.invertFold(view.getId()); 125 | // todo: reset highlight color for a few ms after invertFold? 126 | } 127 | } 128 | durationView.postDelayed(new InvertFold(durationView), 200); 129 | } 130 | }); 131 | */ 132 | } 133 | 134 | 135 | public String toString() { 136 | return "Group pos: " + genuinePos + " level: " + level + " name: " + name; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/ParametersImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.Context; 22 | import android.content.SharedPreferences; 23 | import android.preference.PreferenceManager; 24 | 25 | public class ParametersImpl implements Parameters { 26 | private Context context; 27 | public ParametersImpl(Context context) { 28 | this.context = context; 29 | } 30 | 31 | private SharedPreferences getPref() { 32 | return PreferenceManager.getDefaultSharedPreferences(context); 33 | } 34 | private SharedPreferences.Editor getEditor() { 35 | return getPref().edit(); 36 | } 37 | 38 | public boolean getNoLock() { 39 | return getPref().getBoolean(PrefKeys.NO_LOCK.name(), false); 40 | } 41 | public void setNoLock(boolean noLock) { 42 | getEditor().putBoolean(PrefKeys.NO_LOCK.name(), noLock).commit(); 43 | } 44 | 45 | public boolean getFollowSong() { 46 | return getPref().getBoolean(PrefKeys.FOLLOW_SONG.name(), true); 47 | } 48 | 49 | public void setChooseTextSize(boolean big) { 50 | getEditor().putBoolean(PrefKeys.TEXT_SIZE_CHOOSED.name(), big).commit(); 51 | } 52 | public boolean getChoosedTextSize() { 53 | return getPref().getBoolean(PrefKeys.TEXT_SIZE_CHOOSED.name(), 54 | Boolean.valueOf(context.getString(R.string.settings_text_size_choosed_default))); 55 | } 56 | public int getBigTextSize() { 57 | return Integer.valueOf(getPref().getString(PrefKeys.TEXT_SIZE_BIG.name(), 58 | context.getString(R.string.settings_text_size_big_default))); 59 | } 60 | public int getNormalTextSize() { 61 | return Integer.valueOf(getPref().getString(PrefKeys.TEXT_SIZE_NORMAL.name(), 62 | context.getString(R.string.settings_text_size_regular_default))); 63 | } 64 | public float getTextSizeRatio() { 65 | return Float.valueOf(getPref().getString(PrefKeys.TEXT_SIZE_RATIO.name(), 66 | context.getString(R.string.settings_text_size_ratio_default))); 67 | } 68 | 69 | 70 | public long getSongID() { 71 | return getPref().getLong(PrefKeys.SONG_ID.name(), -1); 72 | } 73 | public void setSongID(long songID) { 74 | getEditor().putLong(PrefKeys.SONG_ID.name(), songID).commit(); 75 | } 76 | 77 | public boolean getSaveSongPos() { 78 | return getPref().getBoolean(PrefKeys.SAVE_SONG_POS.name(), false); 79 | } 80 | 81 | public int getSongPos() { 82 | return getPref().getInt(PrefKeys.SONG_POS.name(), -1); 83 | } 84 | public void setSongPos(int songPos) { 85 | getEditor().putInt(PrefKeys.SONG_POS.name(), songPos).commit(); 86 | } 87 | 88 | 89 | public Filter getFilter() { 90 | return Filter.valueOf(getPref().getString(PrefKeys.FILTER.name(), Filter.TREE.name())); 91 | } 92 | public void setFilter(Filter filter) { 93 | getEditor().putString(PrefKeys.FILTER.name(), filter.name()).commit(); 94 | } 95 | 96 | public RepeatMode getRepeatMode() { 97 | return RepeatMode.valueOf(getPref().getString(PrefKeys.REPEAT_MODE.name(), RepeatMode.REPEAT_ALL.name())); 98 | } 99 | public void setRepeatMode(RepeatMode repeatMode) { 100 | getEditor().putString(PrefKeys.REPEAT_MODE.name(), repeatMode.name()).commit(); 101 | } 102 | 103 | public String getRootFolders() { 104 | return getPref().getString(PrefKeys.ROOT_FOLDERS.name(), Path.getMusicStoragesStr(context)); 105 | } 106 | 107 | 108 | public int getDefaultFold() { 109 | return Integer.valueOf(getPref().getString(PrefKeys.DEFAULT_FOLD.name(), "0")); 110 | } 111 | 112 | public boolean getUnfoldSubGroup() { 113 | return getPref().getBoolean(PrefKeys.UNFOLD_SUBGROUP.name(), false); 114 | } 115 | 116 | public int getUnfoldSubGroupThreshold() { 117 | return Integer.valueOf(getPref().getString(PrefKeys.UNFOLD_SUBGROUP_THRESHOLD.name(), 118 | context.getString(R.string.settings_unfold_subgroup_threshold_default))); 119 | } 120 | 121 | public boolean getEnableShake() { 122 | return getPref().getBoolean(PrefKeys.ENABLE_SHAKE.name(), false); 123 | } 124 | 125 | public void setEnableShake(boolean shakeEnabled) { 126 | getEditor().putBoolean(PrefKeys.ENABLE_SHAKE.name(), shakeEnabled).commit(); 127 | } 128 | 129 | public float getShakeThreshold() { 130 | return Float.valueOf(getPref().getString(PrefKeys.SHAKE_THRESHOLD.name(), 131 | context.getString(R.string.settings_default_shake_threshold))); 132 | } 133 | 134 | public boolean getMediaButtonStartAppShake() { 135 | return getPref().getBoolean(PrefKeys.MEDIA_BUTTON_START_APP.name(), true); 136 | } 137 | 138 | public boolean getVibrate() { 139 | return getPref().getBoolean(PrefKeys.VIBRATE.name(), true); 140 | } 141 | 142 | public boolean getShuffle() { 143 | return getPref().getBoolean(PrefKeys.SHUFFLE.name(), false); 144 | } 145 | 146 | public void setShuffle(boolean shuffle) { 147 | getEditor().putBoolean(PrefKeys.SHUFFLE.name(), shuffle).commit(); 148 | } 149 | 150 | public boolean getScrobble() { 151 | return getPref().getBoolean(PrefKeys.SCROBBLE.name(), false); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/MediaButtonIntentReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | * 16 | */ 17 | 18 | // This file has been heavily copied from official android music player (Apache License, Version 2.0). 19 | // modified to remove shuffle mode 20 | package souch.smp; 21 | 22 | 23 | import android.content.BroadcastReceiver; 24 | import android.content.Context; 25 | import android.content.Intent; 26 | import android.media.AudioManager; 27 | import android.os.Handler; 28 | import android.os.Message; 29 | import android.view.KeyEvent; 30 | 31 | public class MediaButtonIntentReceiver extends BroadcastReceiver { 32 | 33 | // private static final int MSG_LONGPRESS_TIMEOUT = 1; 34 | // private static final int LONG_PRESS_DELAY = 1000; 35 | 36 | private static long mLastClickTime = 0; 37 | // private static boolean mDown = false; 38 | 39 | // souch: disable shuffle mode support 40 | /* 41 | private static boolean mLaunched = false; 42 | 43 | private static Handler mHandler = new Handler() { 44 | @Override 45 | public void handleMessage(Message msg) { 46 | switch (msg.what) { 47 | case MSG_LONGPRESS_TIMEOUT: 48 | if (!mLaunched) { 49 | Context context = (Context)msg.obj; 50 | Intent i = new Intent(); 51 | i.putExtra("autoshuffle", "true"); 52 | i.setClass(context, MusicBrowserActivity.class); 53 | i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); 54 | context.startActivity(i); 55 | mLaunched = true; 56 | } 57 | break; 58 | } 59 | } 60 | }; 61 | */ 62 | 63 | @Override 64 | public void onReceive(Context context, Intent intent) { 65 | String intentAction = intent.getAction(); 66 | if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) { 67 | Intent i = new Intent(context, MusicService.class); 68 | i.setAction(MusicService.SERVICECMD); 69 | i.putExtra(MusicService.CMDNAME, MusicService.CMDPAUSE); 70 | context.startService(i); 71 | } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { 72 | KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 73 | 74 | if (event == null) { 75 | return; 76 | } 77 | 78 | int keycode = event.getKeyCode(); 79 | int action = event.getAction(); 80 | long eventtime = event.getEventTime(); 81 | 82 | // single quick press: pause/resume. 83 | // double press: next track 84 | // long press: start auto-shuffle mode. 85 | 86 | String command = null; 87 | switch (keycode) { 88 | case KeyEvent.KEYCODE_MEDIA_STOP: 89 | command = MusicService.CMDSTOP; 90 | break; 91 | case KeyEvent.KEYCODE_HEADSETHOOK: 92 | case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 93 | command = MusicService.CMDTOGGLEPAUSE; 94 | break; 95 | case KeyEvent.KEYCODE_MEDIA_NEXT: 96 | command = MusicService.CMDNEXT; 97 | break; 98 | case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 99 | command = MusicService.CMDPREVIOUS; 100 | break; 101 | case KeyEvent.KEYCODE_MEDIA_PAUSE: 102 | command = MusicService.CMDPAUSE; 103 | break; 104 | case KeyEvent.KEYCODE_MEDIA_PLAY: 105 | command = MusicService.CMDPLAY; 106 | break; 107 | } 108 | 109 | if (command != null) { 110 | if (action == KeyEvent.ACTION_DOWN) { 111 | /*if (mDown) { 112 | if ((MusicService.CMDTOGGLEPAUSE.equals(command) || 113 | MusicService.CMDPLAY.equals(command)) 114 | && mLastClickTime != 0 115 | && eventtime - mLastClickTime > LONG_PRESS_DELAY) { 116 | mHandler.sendMessage(mHandler.obtainMessage(MSG_LONGPRESS_TIMEOUT, context)); 117 | } 118 | } 119 | else */ 120 | if (event.getRepeatCount() == 0) { 121 | // only consider the first event in a sequence, not the repeat events, 122 | // so that we don't trigger in cases where the first event went to 123 | // a different app (e.g. when the user ends a phone call by 124 | // long pressing the headset button) 125 | 126 | // The service may or may not be running, but we need to send it 127 | // a command. 128 | Intent i = new Intent(context, MusicService.class); 129 | i.setAction(MusicService.SERVICECMD); 130 | 131 | if (keycode == KeyEvent.KEYCODE_HEADSETHOOK && eventtime - mLastClickTime < 300) { 132 | i.putExtra(MusicService.CMDNAME, MusicService.CMDNEXT); 133 | context.startService(i); 134 | mLastClickTime = 0; 135 | } else { 136 | i.putExtra(MusicService.CMDNAME, command); 137 | context.startService(i); 138 | mLastClickTime = eventtime; 139 | } 140 | 141 | //mLaunched = false; 142 | //mDown = true; 143 | } 144 | } /* else { 145 | //mHandler.removeMessages(MSG_LONGPRESS_TIMEOUT); 146 | mDown = false; 147 | } 148 | if (isOrderedBroadcast()) { 149 | abortBroadcast(); 150 | } 151 | */ 152 | } 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /app/src/main/res/xml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 55 | 56 | 62 | 63 | 69 | 70 | 76 | 77 | 81 | 82 | 83 | 84 | 85 | 86 | 91 | 92 | 97 | 98 | 103 | 104 | 109 | 110 | 114 | 115 | 120 | 121 | 126 | 127 | 128 | 129 | 132 | 133 | 136 | 137 | 140 | 141 | 144 | 145 | 149 | 150 | 151 | 152 | 153 | 154 | 157 | 158 | 159 | 162 | 163 | 164 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /app/src/main/java/souch/smp/RowSong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * SicMu Player - Lightweight music player for Android 3 | * Copyright (C) 2015 Mathieu Souchaud 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | package souch.smp; 20 | 21 | import android.content.ContentUris; 22 | import android.content.Context; 23 | import android.graphics.Bitmap; 24 | import android.graphics.BitmapFactory; 25 | import android.graphics.Typeface; 26 | import android.net.Uri; 27 | import android.provider.MediaStore; 28 | import android.util.TypedValue; 29 | import android.widget.ImageView; 30 | import android.widget.TextView; 31 | import android.database.Cursor; 32 | 33 | import java.io.File; 34 | 35 | public class RowSong extends Row { 36 | private long id; 37 | private long albumId; 38 | private String title; 39 | private String artist; 40 | private String album; 41 | private int duration; 42 | private int track; 43 | private int year; 44 | // full filename 45 | private String path; 46 | // folder of the path (i.e. last folder containing the file's song) 47 | private String folder; 48 | 49 | protected static int textSize = 15; 50 | 51 | // must be set outside before calling setText 52 | public static int normalSongTextColor; 53 | public static int normalSongDurationTextColor; 54 | 55 | public RowSong(int pos, int level, long songID, String songTitle, String songArtist, String songAlbum, 56 | int dur, int songTrack, String songPath, long albumId, int year) { 57 | super(pos, level, Typeface.NORMAL); 58 | id = songID; 59 | title = songTitle; 60 | artist = songArtist; 61 | album = songAlbum; 62 | duration = dur; 63 | track = songTrack; 64 | path = songPath; 65 | this.albumId = albumId; 66 | this.year = year; 67 | if(path != null) { 68 | folder = Path.getFolder(path); 69 | } 70 | } 71 | 72 | public long getID(){return id;} 73 | public String getTitle(){return title;} 74 | public int getYear(){return year;} 75 | public String getArtist(){return artist;} 76 | public String getAlbum(){return album;} 77 | public int getDuration(){return duration;} 78 | public int getTrack(){return track;} 79 | public String getPath(){return path;} 80 | public String getFolder(){return folder;} 81 | public long getAlbumId(){return albumId;} 82 | 83 | 84 | public void setView(RowViewHolder holder, Main main, int position) { 85 | super.setView(holder, main, position); 86 | 87 | float factor = 1.5f; 88 | if (main.getMusicSrv().getRows().isLastRow(position)) 89 | factor = 3f; 90 | holder.layout.getLayoutParams().height = convertDpToPixels((int) (textSize * factor), 91 | holder.layout.getResources()); 92 | 93 | setText(holder.text); 94 | setDuration(holder.duration); 95 | setCurrIcon(holder.image, main); 96 | } 97 | 98 | private void setText(TextView text) { 99 | text.setText(title); 100 | text.setTextColor(normalSongTextColor); 101 | text.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize); 102 | } 103 | 104 | private void setDuration(TextView duration) { 105 | duration.setText(secondsToMinutes(getDuration()) + getStringOffset()); 106 | duration.setTextColor(normalSongDurationTextColor); 107 | duration.setTextSize(TypedValue.COMPLEX_UNIT_DIP, textSize); 108 | duration.setTypeface(null, typeface); 109 | /* 110 | duration.setBackgroundColor(Color.argb(0x00, 0x0, 0x0, 0x0)); 111 | duration.setOnClickListener(null); 112 | */ 113 | } 114 | 115 | private void setCurrIcon(ImageView img, Main main) { 116 | int currIcon = android.R.color.transparent; 117 | if (this == main.getMusicSrv().getRows().getCurrSong()) { 118 | if (main.getMusicSrv().playingLaunched()) 119 | currIcon = R.drawable.ic_curr_play; 120 | else 121 | currIcon = R.drawable.ic_curr_pause; 122 | } 123 | img.setImageResource(currIcon); 124 | // useful only for the tests 125 | img.setTag(currIcon); 126 | } 127 | 128 | public String toString() { 129 | return "Song pos: " + genuinePos + " level: " + level + " ID: " + id + " artist: " + artist + 130 | " album: " + album + " title: " + title + " " + 131 | secondsToMinutes(duration) + " track:" + track + " path: " + path; 132 | } 133 | 134 | static public String secondsToMinutes(int duration){ 135 | long seconds = duration; 136 | long minutes = seconds / 60; 137 | seconds = seconds % 60; 138 | return String.valueOf(minutes) + (seconds < 10 ? ":0" : ":") + String.valueOf(seconds); 139 | } 140 | 141 | 142 | public boolean delete(Context context) { 143 | if ((new File(path)).delete()) { 144 | // delete it from media store too 145 | Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, id); 146 | context.getContentResolver().delete(uri, null, null); 147 | 148 | return true; 149 | } 150 | return false; 151 | } 152 | 153 | public Bitmap getAlbumBmp(Context context) { 154 | return getAlbumBmp(context, 0); 155 | } 156 | 157 | /** if imageNum > 0: try to get Nth bitmap from same folder 158 | * @return null if bitmap not found 159 | */ 160 | public Bitmap getAlbumBmp(Context context, int imageNum) { 161 | Bitmap bmp = null; 162 | try { 163 | if (imageNum == 0) { 164 | // search using media store 165 | Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, 166 | new String[]{MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART}, 167 | MediaStore.Audio.Albums._ID + "=?", 168 | new String[]{String.valueOf(albumId)}, 169 | null); 170 | if (cursor.moveToFirst()) { 171 | String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART)); 172 | bmp = BitmapFactory.decodeFile(path); 173 | } 174 | } 175 | 176 | // search manually in song's path 177 | if (bmp == null && path != null) { 178 | File dir = new File(path).getParentFile(); 179 | if (dir.exists() && dir.isDirectory()) { 180 | File[] files = dir.listFiles(); 181 | if (files != null) 182 | for (File file : files) { 183 | if (Path.isImage(file)) { 184 | if (imageNum == 0) { 185 | // found 186 | bmp = BitmapFactory.decodeFile(file.getAbsolutePath()); 187 | break; 188 | } 189 | imageNum--; 190 | } 191 | 192 | } 193 | } 194 | } 195 | } 196 | catch(Exception e) { 197 | bmp = null; 198 | } 199 | return bmp; 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /app/src/main/res/values-sr/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 19 | 20 | 21 | ЗикаМу плејер 22 | 23 | Поставке 24 | Протрес. иск. 25 | Протрес. укљ. 26 | 27 | Поређај по фасцикли 28 | Поређај по извођачу 29 | 30 | Пуштање 31 | 32 | Не могу да привилегујем звучни излаз! Поново покрените апликацију! 33 | 34 | Поставке 35 | 36 | Сажми 37 | Рашири 38 | 39 | Приказ песама 40 | Стање фасцикли по покретању 41 | 42 | Сажете 43 | Раширене 44 | 45 | Рашири подгрупе 46 | Омогућено: раширивање групе раширује све подгрупе и песме. 47 | Рашири подгрупе ако група 48 | има мање од %d песама 49 | 50 | 51 | Фонт приказа песама 52 | Изаберите величину фонта 53 | Нормални фонт 54 | Велики фонт 55 | Однос величине текста извођач/песма 56 | 57 | 58 | Поново скенирај 59 | Поновна претрага медија фајлова. 60 | Андроид Киткет онемогућио поновно скенирање. 61 | Скенирање медија окинуто... 62 | 63 | Медија тастери аутоматски покрећу 64 | Медија тастери покрећу апликацију ако већ није покренута. 65 | 66 | Клизај на нову пуштену песму 67 | Клизај на песму када почне пуштање 68 | 69 | Вибрирај на додир 70 | Завибрирај на кратко по додиру на дугмад или списак песама. 71 | 72 | Корена фасцикла 73 | Путања %s не постоји! 74 | 75 | Протресање 76 | Протресање пушта следећу песму. 77 | Праг силе протресања 78 | Ваш уређај нема акцелерометар. Ова функција је онемогућена. 79 | 80 | 81 | Помоћ 82 | Ако сте мало изгубљени. 83 | 84 | Пуштање песме 85 | Тапните на песму да бисте је пустили. 86 | Пуштање песме из групе 87 | Тапните и држите групу да бисте пустили прву песму. 88 | Сажимање/раширивање групе 89 | Тапните групу да бисте је сажели/раширили. 90 | Клизање на текућу песму 91 | Притисните дугме десно од дугмета „следећа“ да бисте клизали на песму која се пушта. 92 | Онемогућавање закључавања екрана 93 | Притисните дугме-катанац да бисте онемогућили екран закључавања (спречава закључавање само кад је апликација у првом плану; не ради на неким уређајима). 94 | Корена фасцикла 95 | Можете да прилагодите корену фасциклу: користи се само за скривање првог дела путање фасцикли када су песме поређане по фасцикли. 96 | Позадина 97 | У току пуштања музике притисак на почетни тастер или тастер за назад ће да затвори списак песама и настави да пушта музику у позадини. 98 | Напуштање 99 | Апликација ће да изађе по притиску тастера за назад ако музика није пуштена. Ако не, Андроид ће аутоматски да је затвори ако зафали меморије. 100 | Заустављање 101 | Апликација ће остати у меморији по притиску на почетни тастер ако музика није пуштена, али Андроид ће аутоматски да је затвори ако зафали меморије. 102 | Медија тастери 103 | Медија тастери (нпр. на блутут слушалицама) могу да контролишу апликацију (следећа, претходна, пауза/пуштање). 104 | Медија тастери аутоматски покрећу 105 | Ако је апликација затворена, медија тастер ће да је покрене. Да бисте ово онемогућили искључите опцију „Медија тастери аутоматски покрећу“. 106 | 107 | 108 | Разно 109 | 110 | О програму 111 | Подаци о апликацији и аутору. 112 | 113 | Издање 114 | Аутор 115 | Mathieu Souchaud 116 | Изворни кôд 117 | Лиценца 118 | ГПЛв3 119 | Донација 120 | Кликните овде ако би вам живот био тежак без ове апликације. 121 | 122 | Посебне захвале 123 | Иконе 124 | Daniele De Santis & WPZOOM (иконе са iconfinder.com) 125 | Упутства 126 | Sue Smith (упутства за прављење музичког плејера за Андроид) 127 | Превод 128 | Младен Пејаковић (српски), Mehmet Gülmen (Türkçe), Jerônimo Cordoni Pellegrini (Português) 129 | 130 | 131 | --------------------------------------------------------------------------------