├── app
├── .gitignore
├── libs
│ ├── gnsdk.jar
│ ├── gnsdk_helpers.jar
│ └── jaudiotagger-2.2.4.jar
├── src
│ ├── main
│ │ ├── ic_launcher-web.png
│ │ ├── jniLibs
│ │ │ ├── x86
│ │ │ │ ├── libgabi++_shared.so
│ │ │ │ ├── libgnmc_decoder.1.3.1.so
│ │ │ │ └── libgnsdk_java_marshal.1.3.1.so
│ │ │ ├── armeabi
│ │ │ │ ├── libgabi++_shared.so
│ │ │ │ ├── libgnmc_decoder.1.3.1.so
│ │ │ │ └── libgnsdk_java_marshal.1.3.1.so
│ │ │ ├── arm64-v8a
│ │ │ │ ├── libgabi++_shared.so
│ │ │ │ ├── libgnmc_decoder.1.3.1.so
│ │ │ │ └── libgnsdk_java_marshal.1.3.1.so
│ │ │ └── armeabi-v7a
│ │ │ │ ├── libgabi++_shared.so
│ │ │ │ ├── libgnmc_decoder.1.3.1.so
│ │ │ │ └── libgnsdk_java_marshal.1.3.1.so
│ │ ├── res
│ │ │ ├── mipmap-hdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-hdpi
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-mdpi
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ └── ic_launcher.png
│ │ │ ├── drawable-xhdpi
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-xxhdpi
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable
│ │ │ │ ├── ic_stop_white_24dp.png
│ │ │ │ ├── dark_background.xml
│ │ │ │ ├── black_background.xml
│ │ │ │ ├── background_custom_toast.xml
│ │ │ │ ├── custom_scrollbar_thumb.xml
│ │ │ │ ├── ic_stop_white_24px.xml
│ │ │ │ ├── ic_play_arrow_white_24px.xml
│ │ │ │ ├── tab_selector.xml
│ │ │ │ ├── ic_done_white.xml
│ │ │ │ ├── ic_stop_black_24dp.xml
│ │ │ │ ├── ic_equalizer_white_24px.xml
│ │ │ │ ├── ic_play_arrow_black_24dp.xml
│ │ │ │ ├── ic_add_white_24px.xml
│ │ │ │ ├── divider_item_listview.xml
│ │ │ │ ├── ic_delete_white_24px.xml
│ │ │ │ ├── ic_star_white.xml
│ │ │ │ ├── ic_done_white_24px.xml
│ │ │ │ ├── linear_gradient_black_to_transparent.xml
│ │ │ │ ├── linear_gradient_dark_to_transparent.xml
│ │ │ │ ├── linear_gradient_transparent_to_black.xml
│ │ │ │ ├── linear_gradient_transparent_to_dark.xml
│ │ │ │ ├── ic_music_note_white_24px.xml
│ │ │ │ ├── ic_folder_white_24px.xml
│ │ │ │ ├── ic_delete_white.xml
│ │ │ │ ├── ic_photo_white_24px.xml
│ │ │ │ ├── ic_star_white_24px.xml
│ │ │ │ ├── ic_star_black_24dp.xml
│ │ │ │ ├── ic_sd_storage_black_24px.xml
│ │ │ │ ├── ic_sd_storage_white_24px.xml
│ │ │ │ ├── ic_close_white_24px.xml
│ │ │ │ ├── ic_folder_white.xml
│ │ │ │ ├── ic_info_black_24dp.xml
│ │ │ │ ├── tab_indicator_default.xml
│ │ │ │ ├── tab_indicator_selected.xml
│ │ │ │ ├── ic_check_box_white_24px.xml
│ │ │ │ ├── ic_description_white.xml
│ │ │ │ ├── ic_done_all_white.xml
│ │ │ │ ├── ic_star_half_white.xml
│ │ │ │ ├── ic_description_grey_24dp.xml
│ │ │ │ ├── ic_edit_white_24px.xml
│ │ │ │ ├── ic_queue_music_white_24px.xml
│ │ │ │ ├── ic_photo_white.xml
│ │ │ │ ├── ic_email_white_24px.xml
│ │ │ │ ├── ic_insert_drive_file_white_24px.xml
│ │ │ │ ├── ic_error_outline_white.xml
│ │ │ │ ├── ic_add_to_photos_white_24px.xml
│ │ │ │ ├── ic_photo_library_black_24dp.xml
│ │ │ │ ├── background_splash.xml
│ │ │ │ ├── ic_format_list_numbered_white_24px.xml
│ │ │ │ ├── ic_build_white_24px.xml
│ │ │ │ ├── ic_access_time_black_24dp.xml
│ │ │ │ ├── ic_edit_white.xml
│ │ │ │ ├── ic_star_border_white.xml
│ │ │ │ ├── ic_description_white_24px.xml
│ │ │ │ ├── ic_done_all_white_24px.xml
│ │ │ │ ├── ic_star_border_white_24px.xml
│ │ │ │ ├── ic_star_half_white_24px.xml
│ │ │ │ ├── ic_date_range_white_24px.xml
│ │ │ │ ├── ic_save_white_24px.xml
│ │ │ │ ├── ic_refresh_white_24px.xml
│ │ │ │ ├── ic_album_white_24px.xml
│ │ │ │ ├── ic_album_white_48px.xml
│ │ │ │ ├── ic_photo_library_white_24px.xml
│ │ │ │ ├── ic_error_outline_white_24px.xml
│ │ │ │ ├── ic_build_white.xml
│ │ │ │ ├── ic_cloud_download_white_24px.xml
│ │ │ │ ├── ic_search_white_24px.xml
│ │ │ │ ├── ic_account_circle_white_24px.xml
│ │ │ │ ├── ic_highlight_off_white_material.xml
│ │ │ │ ├── ic_access_time_white_24px.xml
│ │ │ │ ├── ic_photo_filter_white_24px.xml
│ │ │ │ ├── ic_highlight_off_white_24px.xml
│ │ │ │ ├── ic_high_quality_white_24px.xml
│ │ │ │ ├── ic_library_music_white_24px.xml
│ │ │ │ ├── ic_high_quality_black_24dp.xml
│ │ │ │ ├── ic_speaker_white_24px.xml
│ │ │ │ ├── ic_data_usage_white_24px.xml
│ │ │ │ ├── ic_access_time_white.xml
│ │ │ │ ├── ic_photo_size_select_large_white_24px.xml
│ │ │ │ ├── ic_sentiment_very_satisfied_white_24px.xml
│ │ │ │ ├── ic_public_white_24px.xml
│ │ │ │ ├── ic_help_black_24dp.xml
│ │ │ │ ├── ic_av_timer_black_24dp.xml
│ │ │ │ ├── ic_av_timer_white_24px.xml
│ │ │ │ ├── ic_sentiment_neutral_white_24px.xml
│ │ │ │ ├── ic_surround_sound_white_24px.xml
│ │ │ │ ├── ic_surround_sound_black_24dp.xml
│ │ │ │ ├── ic_touch_app_white_24px.xml
│ │ │ │ ├── ic_hearing_black_24dp.xml
│ │ │ │ ├── ic_hearing_white_24px.xml
│ │ │ │ ├── ic_magic_wand_auto_fix_button.xml
│ │ │ │ ├── ic_android_white_24px.xml
│ │ │ │ └── ic_settings_black_24dp.xml
│ │ │ ├── drawable-hdpi-v11
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-hdpi-v9
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-mdpi-v11
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-mdpi-v9
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-v21
│ │ │ │ ├── ic_stop_white_24dp.png
│ │ │ │ └── ic_menu_share.xml
│ │ │ ├── drawable-xhdpi-v11
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-xhdpi-v9
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── drawable-xxhdpi-v9
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── values
│ │ │ │ ├── drawables.xml
│ │ │ │ ├── ids.xml
│ │ │ │ ├── attrs.xml
│ │ │ │ ├── colors.xml
│ │ │ │ ├── dimens.xml
│ │ │ │ └── styles.xml
│ │ │ ├── drawable-xxhdpi-v11
│ │ │ │ └── ic_stat_name.png
│ │ │ ├── xml
│ │ │ │ ├── file_paths.xml
│ │ │ │ ├── pref_headers.xml
│ │ │ │ ├── pref_data_sync.xml
│ │ │ │ └── pref_general.xml
│ │ │ ├── layout
│ │ │ │ ├── search_view_layout.xml
│ │ │ │ ├── activity_fullscreen_viewer.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── fragment_screen_slide_page3.xml
│ │ │ │ ├── fragment_screen_slide_page2.xml
│ │ │ │ ├── fragment_screen_slide_page4.xml
│ │ │ │ ├── activity_questions.xml
│ │ │ │ ├── fragment_screen_slide_page5.xml
│ │ │ │ ├── nav_header_select_folder.xml
│ │ │ │ ├── question_item.xml
│ │ │ │ ├── content_main.xml
│ │ │ │ ├── app_bar_select_folder.xml
│ │ │ │ ├── fragment_screen_slide_page.xml
│ │ │ │ ├── activity_scrolling_about.xml
│ │ │ │ ├── activity_screen_slide.xml
│ │ │ │ └── activity_transparent.xml
│ │ │ ├── values-w820dp
│ │ │ │ └── dimens.xml
│ │ │ ├── anim
│ │ │ │ └── blink.xml
│ │ │ ├── menu
│ │ │ │ ├── cab_menu.xml
│ │ │ │ ├── menu_details_track_dialog.xml
│ │ │ │ ├── activity_select_folder_drawer.xml
│ │ │ │ └── menu_main_activity.xml
│ │ │ ├── animator
│ │ │ │ └── default_z_transformation_card_view.xml
│ │ │ └── values-v21
│ │ │ │ └── styles.xml
│ │ └── java
│ │ │ └── mx
│ │ │ └── dev
│ │ │ └── franco
│ │ │ └── automusictagfixer
│ │ │ ├── utilities
│ │ │ ├── RequiredPermissions.java
│ │ │ ├── GnErrorCodes.java
│ │ │ ├── MyGlideModule.java
│ │ │ ├── StringUtilities.java
│ │ │ ├── Settings.java
│ │ │ ├── SimpleMediaPlayer.java
│ │ │ ├── Constants.java
│ │ │ └── FileSaver.java
│ │ │ ├── ScreenSlidePageFragment.java
│ │ │ ├── ScreenSlidePageFragment2.java
│ │ │ ├── ScreenSlidePageFragment3.java
│ │ │ ├── ScreenSlidePageFragment4.java
│ │ │ ├── ScreenSlidePageFragment5.java
│ │ │ ├── services
│ │ │ ├── ConnectivityChangesDetector.java
│ │ │ ├── ServiceHelper.java
│ │ │ ├── ScheduleJobService.java
│ │ │ ├── JobManager.java
│ │ │ ├── Job.java
│ │ │ └── DetectorRemovableMediaStorages.java
│ │ │ ├── database
│ │ │ └── TrackContract.java
│ │ │ ├── FullscreenViewerActivity.java
│ │ │ ├── list
│ │ │ ├── QuestionItem.java
│ │ │ └── FaqAdapter.java
│ │ │ ├── receivers
│ │ │ └── ResponseReceiver.java
│ │ │ ├── transitions
│ │ │ └── DetailsTransition.java
│ │ │ ├── QuestionsActivity.java
│ │ │ ├── SplashActivity.java
│ │ │ ├── AutoMusicTagFixer.java
│ │ │ ├── ScrollingAboutActivity.java
│ │ │ ├── AppCompatPreferenceActivity.java
│ │ │ └── TransparentActivity.java
│ └── test
│ │ └── java
│ │ └── mx
│ │ └── dev
│ │ └── franco
│ │ └── automusictagfixer
│ │ └── ExampleUnitTest.java
├── fabric.properties
└── proguard-rules.pro
├── _config.yml
├── settings.gradle
├── gradle.properties
├── gradlew.bat
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/libs/gnsdk.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/libs/gnsdk.jar
--------------------------------------------------------------------------------
/app/libs/gnsdk_helpers.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/libs/gnsdk_helpers.jar
--------------------------------------------------------------------------------
/app/libs/jaudiotagger-2.2.4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/libs/jaudiotagger-2.2.4.jar
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libgabi++_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/x86/libgabi++_shared.so
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-hdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-mdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libgabi++_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi/libgabi++_shared.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libgnmc_decoder.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/x86/libgnmc_decoder.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable/ic_stop_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libgabi++_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/arm64-v8a/libgabi++_shared.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libgabi++_shared.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi-v7a/libgabi++_shared.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-hdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-hdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-mdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-mdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_stop_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-v21/ic_stop_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xhdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xhdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi-v9/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xxhdpi-v9/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/values/drawables.xml:
--------------------------------------------------------------------------------
1 |
2 | - @android:drawable/ic_menu_share
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libgnmc_decoder.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi/libgnmc_decoder.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi-v11/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/res/drawable-xxhdpi-v11/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libgnmc_decoder.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/arm64-v8a/libgnmc_decoder.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libgnmc_decoder.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi-v7a/libgnmc_decoder.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libgnsdk_java_marshal.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/x86/libgnsdk_java_marshal.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libgnsdk_java_marshal.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi/libgnsdk_java_marshal.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libgnsdk_java_marshal.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/arm64-v8a/libgnsdk_java_marshal.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libgnsdk_java_marshal.1.3.1.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/BitconFeng/AutoTagFixer/HEAD/app/src/main/jniLibs/armeabi-v7a/libgnsdk_java_marshal.1.3.1.so
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/search_view_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/dark_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/black_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_custom_toast.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/fabric.properties:
--------------------------------------------------------------------------------
1 | #Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public.
2 | #Tue Jan 09 19:18:07 CST 2018
3 | apiSecret=f327a25e69cb920705e1d97e5e80eee9e270cfa36533248f96cb223e38f7bfa7
4 | apiKey=3d4995f2cd3e5757faec4a2dadce6e00f2d0814e
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/custom_scrollbar_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_arrow_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_equalizer_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_arrow_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/divider_item_listview.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/blink.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/linear_gradient_black_to_transparent.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/linear_gradient_dark_to_transparent.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/linear_gradient_transparent_to_black.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/linear_gradient_transparent_to_dark.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_music_note_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/RequiredPermissions.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | /**
4 | * Created by franco on 23/03/17.
5 | */
6 |
7 | public final class RequiredPermissions {
8 | public static final int WRITE_EXTERNAL_STORAGE_PERMISSION = 1;
9 | public static boolean ACCESS_GRANTED_FILES = false;
10 | public static final int REQUEST_PERMISSION_SAF = 1000;
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sd_storage_black_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sd_storage_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_folder_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_indicator_default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_indicator_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check_box_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_description_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done_all_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_half_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_description_grey_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_queue_music_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_email_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_insert_drive_file_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error_outline_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_to_photos_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_library_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 | -
8 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_format_list_numbered_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_build_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_access_time_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_border_white.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_description_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_done_all_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_border_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_star_half_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_date_range_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_save_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_refresh_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_album_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_album_white_48px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_library_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_error_outline_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/test/java/mx/dev/franco/automusictagfixer/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_build_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud_download_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/cab_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_account_circle_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_highlight_off_white_material.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_access_time_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_filter_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_highlight_off_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_high_quality_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_library_music_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_high_quality_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_speaker_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_data_usage_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_access_time_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_size_select_large_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sentiment_very_satisfied_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_public_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_help_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_headers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScreenSlidePageFragment.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * Created by franco on 10/11/16.
11 | */
12 |
13 | public class ScreenSlidePageFragment extends Fragment {
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
16 | ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page, container, false);
17 | return rootView;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScreenSlidePageFragment2.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * Created by franco on 10/11/16.
11 | */
12 |
13 | public class ScreenSlidePageFragment2 extends Fragment{
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
16 | ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page2, container, false);
17 | return rootView;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScreenSlidePageFragment3.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * Created by franco on 10/11/16.
11 | */
12 |
13 | public class ScreenSlidePageFragment3 extends Fragment{
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
16 | ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page3, container, false);
17 | return rootView;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScreenSlidePageFragment4.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * Created by franco on 10/11/16.
11 | */
12 |
13 | public class ScreenSlidePageFragment4 extends Fragment{
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
16 | ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page4, container, false);
17 | return rootView;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScreenSlidePageFragment5.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v4.app.Fragment;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 |
9 | /**
10 | * Created by franco on 10/11/16.
11 | */
12 |
13 | public class ScreenSlidePageFragment5 extends Fragment{
14 | @Override
15 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
16 | ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_screen_slide_page5, container, false);
17 | return rootView;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_av_timer_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_av_timer_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 | #fbc02d
7 | #fff263
8 | #c49000
9 |
10 | #000000
11 | #ffffff
12 | #4000
13 | #212121
14 | #424242
15 |
16 | #66000000
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_data_sync.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 |
5 |
6 |
7 | 0dp
8 | 8dp
9 | 24dp
10 | 55dp
11 | 105dp
12 | 155dp
13 | 205dp
14 | 48dp
15 | 180dp
16 | 16dp
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v21/ic_menu_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_sentiment_neutral_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/ConnectivityChangesDetector.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.ConnectivityManager;
7 |
8 | /**
9 | * Created by franco on 26/12/17.
10 | */
11 |
12 | public final class ConnectivityChangesDetector extends BroadcastReceiver {
13 | @Override
14 | public void onReceive(Context context, Intent intent) {
15 | String action = intent.getAction();
16 | if(action != null && action.equals(ConnectivityManager.CONNECTIVITY_ACTION)){
17 | ConnectivityDetector.withContext(context).startCheckingConnection();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/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 | org.gradle.jvmargs=-Xmx1536m
13 |
14 | # When configured, Gradle will run in incubating parallel mode.
15 | # This option should only be used with decoupled projects. More details, visit
16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
17 | # org.gradle.parallel=true
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_surround_sound_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_surround_sound_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_touch_app_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/GnErrorCodes.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import android.content.Context;
4 |
5 | import mx.dev.franco.automusictagfixer.R;
6 | import mx.dev.franco.automusictagfixer.list.AudioItem;
7 |
8 | /**
9 | * Created by franco on 19/03/18.
10 | */
11 |
12 | public class GnErrorCodes {
13 | public static String getMessage(Context context, long errorCode, String... params){
14 | String msg = null;
15 | switch ((int) errorCode){
16 | case 0x90820042:
17 | case 0x90b30042:
18 | msg = String.format(context.getString(R.string.file_already_added), AudioItem.getFilename(params[0]));
19 | break;
20 |
21 | }
22 | context = null;
23 | return msg;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/default_z_transformation_card_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
12 |
13 |
14 | -
15 |
16 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hearing_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_hearing_white_24px.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_fullscreen_viewer.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_magic_wand_auto_fix_button.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_android_white_24px.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/MyGlideModule.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import android.content.Context;
4 |
5 | import com.bumptech.glide.GlideBuilder;
6 | import com.bumptech.glide.annotation.GlideModule;
7 | import com.bumptech.glide.load.engine.cache.LruResourceCache;
8 | import com.bumptech.glide.module.AppGlideModule;
9 |
10 | /**
11 | * Created by franco on 4/12/16.
12 | */
13 |
14 | @GlideModule
15 | public final class MyGlideModule extends AppGlideModule {
16 | @Override
17 | public void applyOptions(Context context, GlideBuilder builder) {
18 | super.applyOptions(context, builder);
19 | setMemoryCache(context, builder);
20 | }
21 |
22 | public MyGlideModule() {
23 | super();
24 | }
25 | public void setMemoryCache(Context context, GlideBuilder builder) {
26 | int memoryCacheSizeBytes = 1024 * 1024 * 20; // 20mb
27 | builder.setMemoryCache(new LruResourceCache(memoryCacheSizeBytes));
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/database/TrackContract.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.database;
2 |
3 | import android.provider.BaseColumns;
4 |
5 | /**
6 | * Created by franco on 7/03/17.
7 | */
8 |
9 | public final class TrackContract {
10 | public TrackContract(){}
11 |
12 | public static class TrackData implements BaseColumns{
13 | public static final String TABLE_NAME = "tracks_table";
14 | public static final String MEDIASTORE_ID = "media_store_id";
15 | public static final String TITLE = "title";
16 | public static final String ARTIST = "artist";
17 | public static final String ALBUM = "album";
18 | public static final String DATA = "_data";
19 | public static final String IS_PROCESSING = "is_processing";
20 | public static final String IS_SELECTED = "is_selected";
21 | public static final String STATUS = "status"; //P for "processed", I for "incomplete data", NA for "no data avaliable", N for "no processed"
22 | }
23 |
24 | }
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/FullscreenViewerActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.content.Intent;
4 | import android.graphics.BitmapFactory;
5 | import android.os.Bundle;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.widget.ImageView;
8 |
9 | /**
10 | * An example full-screen activity that shows and hides the system UI (i.e.
11 | * status bar and navigation/system bar) with user interaction.
12 | */
13 | public class FullscreenViewerActivity extends AppCompatActivity {
14 |
15 |
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 |
21 | setContentView(R.layout.activity_fullscreen_viewer);
22 | Intent bundle = getIntent();
23 | byte[] cover = bundle.getByteArrayExtra("cover");
24 | ImageView imageView = findViewById(R.id.imageContainerViewer);
25 | imageView.setImageBitmap(BitmapFactory.decodeByteArray(cover,0,cover.length-1));
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_details_track_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/list/QuestionItem.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.list;
2 |
3 | /**
4 | * Created by franco on 7/11/17.
5 | */
6 |
7 | public final class QuestionItem {
8 | int mId = -1;
9 | private String mQuestion = "";
10 | private String mAnswer = "";
11 | private boolean mExpanded = false;
12 |
13 |
14 | public int getId() {
15 | return mId;
16 | }
17 |
18 | public void setId(int id) {
19 | this.mId = id;
20 | }
21 |
22 | public String getQuestion() {
23 | return mQuestion;
24 | }
25 |
26 | public void setQuestion(String question) {
27 | this.mQuestion = question;
28 | }
29 |
30 | public String getAnswer() {
31 | return mAnswer;
32 | }
33 |
34 | public void setAnswer(String answer) {
35 | this.mAnswer = answer;
36 | }
37 |
38 | public boolean isExpanded(){
39 | return this.mExpanded;
40 | }
41 |
42 | public void setExpanded(boolean expanded){
43 | this.mExpanded = expanded;
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/receivers/ResponseReceiver.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Handler;
7 |
8 | /**
9 | * Created by franco on 23/03/18.
10 | */
11 |
12 | public class ResponseReceiver extends BroadcastReceiver {
13 | private Handler mHandler;
14 | private OnResponse mCallback;
15 |
16 | public interface OnResponse{
17 | void onResponse(Intent intent);
18 | }
19 |
20 | public ResponseReceiver(OnResponse callback, Handler handler){
21 | mCallback = callback;
22 | mHandler = handler;
23 | }
24 |
25 | @Override
26 | public void onReceive(Context context, final Intent intent) {
27 | if(mCallback != null && mHandler != null){
28 | mHandler.post(new Runnable() {
29 | @Override
30 | public void run() {
31 | mCallback.onResponse(intent);
32 | }
33 | });
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
17 |
18 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/transitions/DetailsTransition.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.transitions;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.transition.ChangeBounds;
7 | import android.transition.ChangeImageTransform;
8 | import android.transition.ChangeTransform;
9 | import android.transition.TransitionSet;
10 | import android.util.AttributeSet;
11 |
12 | /**
13 | * Transition that performs almost exactly like {@link android.transition.AutoTransition}, but has an
14 | * added {@link ChangeImageTransform} to support properly scaling up our gorgeous kittens.
15 | *
16 | * @author bherbst
17 | */
18 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
19 | public class DetailsTransition extends TransitionSet {
20 | public DetailsTransition() {
21 | init();
22 | }
23 |
24 | /**
25 | * This constructor allows us to use this transition in XML
26 | */
27 | public DetailsTransition(Context context, AttributeSet attrs) {
28 | super(context, attrs);
29 | init();
30 | }
31 |
32 | private void init() {
33 | setOrdering(ORDERING_TOGETHER);
34 | addTransition(new ChangeBounds()).
35 | addTransition(new ChangeTransform()).
36 | addTransition(new ChangeImageTransform());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_screen_slide_page3.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
21 |
22 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_select_folder_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_screen_slide_page2.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
22 |
23 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_screen_slide_page4.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
22 |
23 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/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/franco/Android/Sdk/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 | -dontwarn org.jaudiotagger.**
19 | -dontwarn com.google.android.gms.**
20 | -dontwarn com.crashlytics.**
21 |
22 | -keep class com.gracenote.** { *; }
23 | -keep class org.jaudiotagger.** { *; }
24 | -keep class android.support.v7.widget.SearchView { *; }
25 | -keep class com.google.** { *; }
26 | -keep class com.android.** { *; }
27 | #Fabric uses annotations internally
28 | -keepattributes *Annotation*
29 | #In order to provide the most meaningful crash reports
30 | -keepattributes SourceFile,LineNumberTable
31 | #Crashlytics will still function without this rule, but your crash reports will not include proper file names or line numbers.
32 | #if using custom exceptions:
33 | -keep public class * extends java.lang.Exception
34 | #To skip running ProGuard on Crashlytics
35 | -keep class com.crashlytics.** { *; }
36 | #Exclude R from ProGuard to enable the font addon auto detection
37 | -keep class .R
38 | -keep class **.R$* {
39 | ;
40 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_questions.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
13 |
14 |
19 |
20 |
21 |
22 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_screen_slide_page5.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
12 |
13 |
22 |
23 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_select_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
17 |
18 |
24 |
25 |
33 |
34 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/question_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
17 |
27 |
28 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/ServiceHelper.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.app.ActivityManager;
4 | import android.content.Context;
5 |
6 | import static android.content.Context.ACTIVITY_SERVICE;
7 |
8 | /**
9 | * Created by franco on 30/10/17.
10 | */
11 |
12 | public class ServiceHelper {
13 | private static ServiceHelper sServiceHelper;
14 | private String mService;
15 | private Context mContext;
16 | private ServiceHelper(Context context){
17 | mContext = context.getApplicationContext();
18 | }
19 |
20 | /**
21 | * Creates (if is not created) and return a single instance
22 | * of this helper
23 | * @param context
24 | * @return ServicerHelper singleton
25 | */
26 | public static ServiceHelper withContext(Context context){
27 | if(sServiceHelper == null)
28 | sServiceHelper = new ServiceHelper(context);
29 | return sServiceHelper;
30 | }
31 |
32 | /**
33 | * Service to verify if is running
34 | * @param service String name of service, regularly is the name returned by
35 | * YourServiceClass.class.getName()
36 | * @return ServicerHelper object
37 | */
38 | public ServiceHelper withService(String service){
39 | mService = service;
40 | return this;
41 | }
42 |
43 | /**
44 | * Check if service is running.
45 | * @return True if is running, false otherwise.
46 | */
47 | public boolean isServiceRunning() {
48 | ActivityManager manager = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE);
49 | for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)){
50 | if(mService.equals(service.service.getClassName())) {
51 | return true;
52 | }
53 | }
54 | return false;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
24 |
25 |
29 |
30 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/ScheduleJobService.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.app.job.JobParameters;
4 | import android.app.job.JobService;
5 | import android.util.Log;
6 |
7 | /**
8 | * Created by franco on 6/07/17.
9 | */
10 |
11 | public class ScheduleJobService extends JobService {
12 | /**
13 | * Callback when service start, here is when we execute our
14 | * task in background, so an intensive task
15 | * needs to run in another thread because
16 | * this callback it executes on UI Thread
17 | * @param params Are the parameters with was built
18 | * the job
19 | * @return true for execute the code
20 | */
21 |
22 | @Override
23 | public boolean onStartJob(final JobParameters params) {
24 | Log.d("ONSTART","onstart");
25 |
26 | //We set context and initialize the GNSDK API if it was not before.
27 | boolean shouldInitialize = (ConnectivityDetector.sIsConnected && !GnService.sApiInitialized);
28 | if(shouldInitialize) {
29 | //GnService.API_INITIALIZED_AFTER_CONNECTED flag indicates
30 | //that service was not initialized from Splash.
31 | //is useful to inform to user in MainActivity
32 | //that API of GNSDK has been initialized
33 | GnService.withContext(getApplicationContext()).initializeAPI(GnService.API_INITIALIZED_AFTER_CONNECTED);
34 | }
35 | //if already should not initialize it, we finalize this job
36 | jobFinished(params, !shouldInitialize);
37 | return true;
38 | }
39 |
40 | /**
41 | * If case Job stops abruptly, we can handle here, if we
42 | * want to restart, we need to return true, false if not.
43 | * This callback it executes on UI Thread too
44 | * @param params Are the parameters with was built
45 | * the job
46 | * @return
47 | */
48 | @Override
49 | public boolean onStopJob(JobParameters params) {
50 | Log.d("ONSTOP","onstop");
51 | return true;
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_select_folder.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
38 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/JobManager.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.app.job.JobInfo;
4 | import android.app.job.JobScheduler;
5 | import android.content.Context;
6 | import android.util.SparseArray;
7 |
8 | /**
9 | * Created by franco on 12/01/18.
10 | * This simple JobManager helps us to
11 | * control jobs started and don't recreate it
12 | * again
13 | */
14 |
15 | public final class JobManager {
16 | private SparseArray jobs = new SparseArray();
17 | private static Context sContext;
18 | private static JobManager sJobManager = new JobManager();
19 |
20 | private JobManager(){
21 |
22 | }
23 |
24 | /**
25 | * Set conetext to use this JobManager
26 | * @param context
27 | * @return
28 | */
29 | public static JobManager withContext(Context context){
30 | if(sContext == null)
31 | sContext = context;
32 | return sJobManager;
33 | }
34 |
35 | /**
36 | * Adds JobInfo object to current
37 | * jobs list running
38 | * @param jobInfo
39 | */
40 | public void addJob(JobInfo jobInfo ){
41 | jobs.append(jobInfo.getId(), jobInfo);
42 | }
43 |
44 | /**
45 | * Cancel all jobs running and removes
46 | * from list
47 | */
48 | public void cancelAllJobs(){
49 | JobScheduler jobScheduler = (JobScheduler) sContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
50 |
51 | if (jobScheduler != null) {
52 | jobScheduler.cancelAll();
53 | }
54 |
55 | if(hasJobs())
56 | jobs.clear();
57 |
58 | }
59 |
60 | /**
61 | * Check if there are jobs running
62 | * @return true if there are jobs running, false otherwise
63 | */
64 | private boolean hasJobs(){
65 | return (jobs.size() > 0);
66 | }
67 |
68 | /**
69 | * Check if any job with
70 | * the id provided is running
71 | * @param id job ID
72 | * @return JobInfo object, null if doesn't exist
73 | */
74 | public JobInfo getJobById(int id) {
75 | if(!hasJobs())
76 | return null;
77 |
78 | return (JobInfo) jobs.get(id);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_screen_slide_page.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
22 |
23 |
36 |
37 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_scrolling_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
26 |
27 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/Job.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.app.job.JobInfo;
4 | import android.app.job.JobScheduler;
5 | import android.content.ComponentName;
6 | import android.content.Context;
7 | import android.os.Build;
8 |
9 | /**
10 | * Created by franco on 6/07/17.
11 | */
12 |
13 | public class Job {
14 | public static final int ID_JOB = 1;
15 | /**
16 | * Here we schedule our task and constraints to execute,
17 | * in this case a periodic task, that will try to initialize the API
18 | * Gracenote
19 | * @param context
20 | */
21 | public static void scheduleJob(Context context){
22 |
23 | //Don't create a job if is running
24 | if(null != JobManager.withContext(context).getJobById(ID_JOB))
25 | return;
26 |
27 | //Component we want to execute
28 | //we need to pass context and name of our extended JobService class
29 | //that will execute the task
30 | ComponentName serviceComponent = new ComponentName(context.getApplicationContext(), ScheduleJobService.class);
31 | //this builder object are the requirements
32 | //needed to execute our task, in this case, we need
33 | //that our task executes every 5 seconds
34 | JobInfo.Builder builder = new JobInfo.Builder(ID_JOB, serviceComponent);
35 | //Using setMinimumLatency with setOverrideDeadline together,
36 | //it makes something like minimum and maximum limit to execute the code, is useful
37 | //because minimum time for setPeriodic in Nougat are 15 minutes, so if you require
38 | //to execute your task in lower range of time is not going to work.
39 | if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
40 | //minimum latency means the min limit in milliseconds JobScheduler has to wait to execute the code
41 | builder.setMinimumLatency(5000);
42 | //setOverrideDeadline means the max limit in milliseconds in which your code is
43 | //going to execute.
44 | builder.setOverrideDeadline(5000);
45 | }
46 | //For android <= M there is no problem in use setPeriodic (instead of two before), with less than 15 minutes
47 | else {
48 | builder.setPeriodic(5000);
49 | }
50 |
51 | //time to schedule task
52 | JobScheduler jobScheduler = (JobScheduler) context.getApplicationContext().getSystemService(Context.JOB_SCHEDULER_SERVICE);
53 | JobInfo job = builder.build();
54 | JobManager.withContext(context).addJob(job);
55 | jobScheduler.schedule(job);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_screen_slide.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
27 |
28 |
34 |
35 |
47 |
48 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/StringUtilities.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | import mx.dev.franco.automusictagfixer.R;
7 |
8 | /**
9 | * Created by franco on 21/06/17.
10 | * Helper class containing some useful
11 | * static methods for validating strings
12 | */
13 |
14 | public final class StringUtilities {
15 | /**
16 | *
17 | * @param str is the input entered by user
18 | * @return true if string is empty, false otherwise
19 | */
20 | public static boolean isFieldEmpty(String str) {
21 | return str.isEmpty();
22 | }
23 |
24 | /**
25 | *
26 | * @param dirtyString
27 | * We replace all invalid characters because
28 | * compatibility problems when showing the information
29 | * about song
30 | * @return sanitized string
31 | */
32 | public static String sanitizeString(String dirtyString) {
33 | return dirtyString.replaceAll("[^\\w\\s()&_\\-\\]\\[\'#.:$]", "");
34 | }
35 |
36 | /**
37 | *
38 | * @param str is the input entered by user
39 | * @return true string contains another chararacter, false otherwise
40 | */
41 | public static boolean hasNotAllowedCharacters(String str){
42 | Pattern pattern = Pattern.compile("[^\\w\\s()&_\\-\\]\\[\'#.:$]");
43 | Matcher matcher = pattern.matcher(str);
44 | return matcher.find();
45 | }
46 |
47 | public static String sanitizeFilename(String dirtyFileName){
48 | if(dirtyFileName != null && !dirtyFileName.equals(""))
49 | return dirtyFileName.replaceAll("[^\\w\\s()&_\\-\\]\\[\'#.:$/]", "");
50 |
51 | return "";
52 | }
53 |
54 | /**
55 | *
56 | * @param str is the input entered by user
57 | * @return trimmed string
58 | */
59 | public static String trimString(String str){
60 | return str.trim();
61 | }
62 |
63 | /**
64 | *
65 | * @param id is the id of element
66 | * @param str is the input entered by user
67 | * @return true if string is too long, false otherwise
68 | */
69 | public static boolean isTooLong(int id, String str){
70 | boolean isTooLong = false;
71 | switch (id){
72 | case R.id.track_name_details:
73 | case R.id.artist_name_details:
74 | case R.id.album_name_details:
75 | isTooLong = str.length() >= 81;
76 | break;
77 | case R.id.track_number:
78 | case R.id.track_year:
79 | isTooLong = str.length() >= 5;
80 | break;
81 | case R.id.track_genre:
82 | isTooLong = str.length() >=31;
83 | break;
84 | }
85 | return isTooLong;
86 | }
87 | }
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/list/FaqAdapter.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.list;
2 |
3 | import android.animation.LayoutTransition;
4 | import android.support.annotation.NonNull;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.LayoutInflater;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.LinearLayout;
10 | import android.widget.TextView;
11 |
12 | import java.util.List;
13 |
14 | import mx.dev.franco.automusictagfixer.R;
15 |
16 | /**
17 | * Created by franco on 21/03/18.
18 | */
19 |
20 | public class FaqAdapter extends RecyclerView.Adapter {
21 | private List mList;
22 | private OnItemClick mListener;
23 |
24 | public interface OnItemClick{
25 | void onItemClick(int position, View view);
26 | }
27 |
28 | public FaqAdapter(List list, OnItemClick listener){
29 | mList = list;
30 | mListener = listener;
31 | }
32 |
33 | @NonNull
34 | @Override
35 | public QuestionItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
36 | LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
37 | View v = layoutInflater.inflate(R.layout.question_item, parent, false);
38 | return new QuestionItemHolder(v, mListener);
39 | }
40 |
41 | @Override
42 | public void onBindViewHolder(@NonNull QuestionItemHolder holder, int position) {
43 | QuestionItem questionItem = mList.get(position);
44 | holder.mQuestion.setText(questionItem.getQuestion());
45 | holder.mAnswer.setText(questionItem.getAnswer());
46 | }
47 |
48 | @Override
49 | public int getItemCount() {
50 | if(mList != null)
51 | return mList.size();
52 | return 0;
53 | }
54 |
55 | public class QuestionItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
56 | public TextView mQuestion;
57 | public TextView mAnswer;
58 | public LinearLayout mContainer;
59 | public OnItemClick mListener;
60 |
61 | QuestionItemHolder(View root, OnItemClick listener){
62 | super(root);
63 | mQuestion = root.findViewById(R.id.question);
64 | mAnswer = root.findViewById(R.id.answer);
65 | mContainer = root.findViewById(R.id.container_questiom);
66 | mListener = listener;
67 | root.setOnClickListener(this);
68 | //Enable animations on this layout
69 | mContainer.getLayoutTransition()
70 | .enableTransitionType(LayoutTransition.CHANGING);
71 | }
72 |
73 | @Override
74 | public void onClick(View v) {
75 | if(mListener != null){
76 | mListener.onItemClick(getAdapterPosition(), v);
77 | }
78 | }
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/QuestionsActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.os.Bundle;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.support.v7.widget.LinearLayoutManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.support.v7.widget.Toolbar;
8 | import android.view.View;
9 |
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | import mx.dev.franco.automusictagfixer.list.FaqAdapter;
14 | import mx.dev.franco.automusictagfixer.list.QuestionItem;
15 |
16 | public class QuestionsActivity extends AppCompatActivity implements FaqAdapter.OnItemClick{
17 |
18 | private List mQuestionItems;
19 | private FaqAdapter mFaqAdapter;
20 | private RecyclerView mRecyclerView;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 |
26 | setContentView(R.layout.activity_questions);
27 | //Set an action bar
28 | Toolbar toolbar = findViewById(R.id.toolbar);
29 | setSupportActionBar(toolbar);
30 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
31 | @Override
32 | public void onClick(View v) {
33 | QuestionsActivity.super.onBackPressed();
34 | }
35 | });
36 |
37 | //Get action bar from toolbar
38 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
39 | getSupportActionBar().setTitle(getString(R.string.faq));
40 |
41 | mQuestionItems = new ArrayList<>();
42 | String[] questions = getResources().getStringArray(R.array.questions);
43 |
44 | String[] answers = getResources().getStringArray(R.array.answers);
45 |
46 | mRecyclerView = findViewById(R.id.questions_recyclerview);
47 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
48 | mRecyclerView.setHasFixedSize(true);
49 | mRecyclerView.setItemViewCacheSize(10);
50 | mFaqAdapter = new FaqAdapter(mQuestionItems, this);
51 | mRecyclerView.setAdapter(mFaqAdapter);
52 |
53 | for(int y = 0 ; y < questions.length ; y++){
54 | QuestionItem questionItem = new QuestionItem();
55 | questionItem.setQuestion(questions[y]);
56 | questionItem.setAnswer(answers[y]);
57 | mQuestionItems.add(questionItem);
58 | mFaqAdapter.notifyItemInserted(mQuestionItems.size()-1);
59 | }
60 |
61 | }
62 |
63 | @Override
64 | public void onItemClick(int position, View view) {
65 | View answer = view.findViewById(R.id.answer);
66 | if(answer.getVisibility() == View.GONE){
67 | answer.setVisibility(View.VISIBLE);
68 | }
69 | else {
70 | answer.setVisibility(View.GONE);
71 | }
72 | }
73 |
74 | @Override
75 | protected void onDestroy(){
76 | mQuestionItems.clear();
77 | mQuestionItems = null;
78 | mFaqAdapter = null;
79 | mRecyclerView = null;
80 | super.onDestroy();
81 | }
82 |
83 |
84 | }
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/Settings.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | /**
4 | * Created by franco on 19/05/17.
5 | */
6 |
7 | import com.gracenote.gnsdk.GnImageSize;
8 |
9 | /**
10 | * This class help us to store the values from settings in order to
11 | * do not call SharedPreferences every time we need to check the value.
12 | * Some have been declared as volatiles because they are accessed by more than
13 | * 1 thread.
14 | */
15 | public class Settings {
16 | public static boolean BACKGROUND_CORRECTION = false;
17 | //If true, the automatized process of correction
18 | //will change the file name with the same name of title song, default value true
19 | public static volatile boolean SETTING_RENAME_FILE_AUTOMATIC_MODE = true;
20 | //if true, the trackId title, will be applied as file, this implies
21 | //that file will be renamed
22 | public static volatile boolean SETTING_RENAME_FILE_SEMI_AUTOMATIC_MODE = true;
23 | //If is true, when user edit the metadata of audio file,
24 | //the title the user types, will be the same for the file name, default value false
25 | public static volatile boolean SETTING_RENAME_FILE_MANUAL_MODE = true;
26 | //Determine when user edit manually an audio file, if he types strange
27 | //characters like "$" or "#", these automatically will be replace by empty character if this setting
28 | //is true, otherwise it will be shown an alert indicating that data entered by user is not valid
29 | public static volatile boolean SETTING_REPLACE_STRANGE_CHARS_MANUAL_MODE = true;
30 | //default sort is by ascendant location
31 | public static int SETTING_SORT = 0;
32 | public static boolean SETTING_USE_EMBED_PLAYER = true;
33 | //Determine the size of downloaded cover art, default value is not download cover art.
34 | public static volatile GnImageSize SETTING_SIZE_ALBUM_ART = GnImageSize.kImageSizeUnknown;
35 | //if true, will be overwritten all tags found by service in automatic mode
36 | //else, only missing tags will be written
37 | public static volatile boolean SETTING_OVERWRITE_ALL_TAGS_AUTOMATIC_MODE = false;
38 |
39 | public static boolean SETTING_AUTO_UPDATE_LIST = false;
40 |
41 | public static boolean ALL_CHECKED = false;
42 |
43 | public static boolean ENABLE_SD_CARD_ACCESS = false;
44 |
45 | public static GnImageSize setValueImageSize(String preferenceSaved){
46 | GnImageSize size = null;
47 | switch (preferenceSaved){
48 | case "-1":
49 | size = null;
50 | break;
51 | case "0":
52 | size = GnImageSize.kImageSizeThumbnail;
53 | break;
54 | case "1":
55 | size = GnImageSize.kImageSizeSmall;
56 | break;
57 | case "5":
58 | size = GnImageSize.kImageSizeMedium;
59 | break;
60 | case "7":
61 | size = GnImageSize.kImageSize720;
62 | break;
63 | case "10":
64 | size = GnImageSize.kImageSize1080;
65 | break;
66 | case "1000":
67 | size= GnImageSize.kImageSizeXLarge;
68 | break;
69 | }
70 | return size;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/pref_general.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
15 |
20 |
21 |
23 |
28 |
29 |
30 |
32 |
37 |
42 |
43 |
51 |
53 |
58 |
59 |
60 |
62 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
14 |
17 |
18 |
19 |
22 |
23 |
24 |
30 |
31 |
32 |
35 |
36 |
37 |
40 |
41 |
45 |
46 |
47 |
56 |
57 |
60 |
61 |
64 |
65 |
66 |
67 |
70 |
71 |
72 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/SplashActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.Manifest;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.content.pm.PackageManager;
8 | import android.net.Uri;
9 | import android.os.Bundle;
10 | import android.preference.PreferenceManager;
11 | import android.support.v4.content.ContextCompat;
12 | import android.support.v7.app.AppCompatActivity;
13 |
14 | import mx.dev.franco.automusictagfixer.services.ConnectivityDetector;
15 | import mx.dev.franco.automusictagfixer.services.GnService;
16 | import mx.dev.franco.automusictagfixer.utilities.Constants;
17 | import mx.dev.franco.automusictagfixer.utilities.RequiredPermissions;
18 | import mx.dev.franco.automusictagfixer.utilities.Settings;
19 |
20 | /**
21 | * Created by franco on 6/11/16.
22 | */
23 |
24 | public class SplashActivity extends AppCompatActivity{
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState){
28 | super.onCreate(savedInstanceState);
29 | ConnectivityDetector.withContext(this).setStartedFrom(GnService.API_INITIALIZED_FROM_SPLASH).startCheckingConnection();
30 |
31 |
32 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
33 |
34 | //Get default or saved values of settings
35 | Settings.SETTING_RENAME_FILE_AUTOMATIC_MODE = preferences.getBoolean("key_rename_file_automatic_mode", true);
36 | Settings.SETTING_RENAME_FILE_MANUAL_MODE = preferences.getBoolean("key_rename_file_manual_mode", true);
37 | Settings.SETTING_REPLACE_STRANGE_CHARS_MANUAL_MODE = preferences.getBoolean("key_replace_strange_chars_manual_mode",true);
38 | Settings.ALL_CHECKED = preferences.getBoolean(Constants.ALL_ITEMS_CHECKED,false);
39 | Settings.SETTING_OVERWRITE_ALL_TAGS_AUTOMATIC_MODE = preferences.getBoolean("key_overwrite_all_tags_automatic_mode", true);
40 | Settings.SETTING_RENAME_FILE_SEMI_AUTOMATIC_MODE = preferences.getBoolean("key_rename_file_semi_automatic_mode", true);
41 | Settings.SETTING_USE_EMBED_PLAYER = preferences.getBoolean("key_use_embed_player",true);
42 | Settings.BACKGROUND_CORRECTION = preferences.getBoolean("key_background_service", true);
43 | String imageSizeSaved = preferences.getString("key_size_album_art","1000");
44 | Settings.SETTING_SIZE_ALBUM_ART = Settings.setValueImageSize(imageSizeSaved);
45 | Settings.SETTING_AUTO_UPDATE_LIST = preferences.getBoolean("key_auto_update_list", false);
46 | Settings.ENABLE_SD_CARD_ACCESS = preferences.getBoolean("key_enable_sd_card_access", false);
47 |
48 |
49 |
50 |
51 | //Is first use of app?
52 | SharedPreferences preferences2 = getSharedPreferences(Constants.Application.FULL_QUALIFIED_NAME, Context.MODE_PRIVATE);
53 | String uriString = preferences2.getString(Constants.URI_TREE, null);
54 | Constants.URI_SD_CARD = uriString != null ? Uri.parse(uriString) : null;
55 | boolean firstTime = preferences2.getBoolean("first", true);
56 | Settings.SETTING_SORT = preferences2.getInt(Constants.SORT_KEY, 0);
57 | //do we have permission to access files?
58 | RequiredPermissions.ACCESS_GRANTED_FILES = ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
59 |
60 | if (firstTime) {
61 | //Is first app use
62 | Intent intent = new Intent(this, ScreenSlidePagerActivity.class);
63 | startActivity(intent);
64 | } else {
65 |
66 | Intent intent = new Intent(this, MainActivity.class);
67 | startActivity(intent);
68 |
69 | }
70 |
71 | finish();
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/AutoMusicTagFixer.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.app.Application;
4 | import android.content.Intent;
5 | import android.content.IntentFilter;
6 | import android.content.res.Configuration;
7 | import android.net.ConnectivityManager;
8 | import android.os.Build;
9 |
10 | import com.crashlytics.android.Crashlytics;
11 | import com.crashlytics.android.core.CrashlyticsCore;
12 | import com.squareup.leakcanary.LeakCanary;
13 |
14 | import io.fabric.sdk.android.Fabric;
15 | import mx.dev.franco.automusictagfixer.services.ConnectivityChangesDetector;
16 | import mx.dev.franco.automusictagfixer.services.DetectorRemovableMediaStorages;
17 | import mx.dev.franco.automusictagfixer.utilities.StorageHelper;
18 |
19 |
20 | /**
21 | * Created by franco on 26/12/17.
22 | */
23 |
24 | public final class AutoMusicTagFixer extends Application {
25 | private ConnectivityChangesDetector mConnectivityChangesDetector;
26 | private IntentFilter mIntentFilter;
27 |
28 | private IntentFilter mIntentFilterMediaMounted;
29 | private IntentFilter mIntentFilterMediaUnmounted;
30 | private DetectorRemovableMediaStorages mDetectorRemovableMediaStorages;
31 | public static boolean IS_LOLLIPOP = Build.VERSION.SDK_INT < Build.VERSION_CODES.M;
32 | // Called when the application is starting, before any other application objects have been created.
33 | // Overriding this method is totally optional!
34 | @Override
35 | public void onCreate() {
36 | super.onCreate();
37 | //Fabric.with(this, new Crashlytics());
38 | // Set up Crashlytics, disabled for debug builds
39 | Crashlytics crashlyticsKit = new Crashlytics.Builder()
40 | .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
41 | .build();
42 |
43 | // Initialize Fabric with the debug-disabled crashlytics.
44 | Fabric.with(this, crashlyticsKit);
45 | //Detect connectivity changes
46 | mConnectivityChangesDetector = new ConnectivityChangesDetector();
47 | mIntentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
48 |
49 | registerReceiver(mConnectivityChangesDetector,mIntentFilter);
50 |
51 | //Detect if a media is removed or added while app is running
52 | mDetectorRemovableMediaStorages = new DetectorRemovableMediaStorages(getApplicationContext());
53 | mIntentFilterMediaMounted = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED);
54 | mIntentFilterMediaMounted.addDataScheme("file");
55 | mIntentFilterMediaUnmounted = new IntentFilter(Intent.ACTION_MEDIA_UNMOUNTED);
56 | mIntentFilterMediaUnmounted.addDataScheme("file");
57 |
58 | registerReceiver(mDetectorRemovableMediaStorages, mIntentFilterMediaMounted);
59 | registerReceiver(mDetectorRemovableMediaStorages, mIntentFilterMediaUnmounted);
60 | StorageHelper.getInstance(getApplicationContext()).detectStorages();
61 |
62 | if (LeakCanary.isInAnalyzerProcess(this)) {
63 | // This process is dedicated to LeakCanary for heap analysis.
64 | // You should not init your app in this process.
65 | return;
66 | }
67 | LeakCanary.install(this);
68 | }
69 |
70 | // Called by the system when the device configuration changes while your component is running.
71 | // Overriding this method is totally optional!
72 | @Override
73 | public void onConfigurationChanged(Configuration newConfig) {
74 | super.onConfigurationChanged(newConfig);
75 | }
76 |
77 | // This is called when the overall system is running low on memory,
78 | // and would like actively running processes to tighten their belts.
79 | // Overriding this method is totally optional!
80 | @Override
81 | public void onLowMemory() {
82 | super.onLowMemory();
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/SimpleMediaPlayer.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import android.content.Context;
4 | import android.media.MediaPlayer;
5 | import android.os.PowerManager;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.Log;
8 |
9 | import java.io.IOException;
10 |
11 | import mx.dev.franco.automusictagfixer.list.AudioItem;
12 | import mx.dev.franco.automusictagfixer.list.TrackAdapter;
13 |
14 | /**
15 | * Created by franco on 29/03/17.
16 | */
17 |
18 | public final class SimpleMediaPlayer extends MediaPlayer implements MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
19 |
20 | private static SimpleMediaPlayer sMediaPlayer;
21 | private AudioItem mCurrentAudioItem;
22 | private long mCurrentPosition = -1;
23 | private TrackAdapter mAdapter;
24 |
25 | /**
26 | * Don't let instantiate this class, we need only one instance,
27 | * so we use a singleton pattern in order to make this.
28 | */
29 | private SimpleMediaPlayer(Context context){
30 | super();
31 | setVolume(1f,1f);
32 | setWakeMode(context.getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
33 | setOnCompletionListener(this);
34 | setOnErrorListener(this);
35 | }
36 |
37 | /**
38 | *
39 | * @param context
40 | * @return An unique instance of SimpleMediaPlayer.
41 | */
42 | public static SimpleMediaPlayer getInstance(Context context){
43 | if(sMediaPlayer == null){
44 | sMediaPlayer = new SimpleMediaPlayer(context);
45 | }
46 | return sMediaPlayer;
47 | }
48 |
49 | public void setAdapter(TrackAdapter mAdapter){
50 | this.mAdapter = mAdapter;
51 | }
52 |
53 | public RecyclerView.Adapter getAdapter(){
54 | return this.mAdapter;
55 | }
56 |
57 | /**
58 | * Play a preview of audiofile.
59 | * @param position
60 | * @throws IOException
61 | * @throws InterruptedException
62 | */
63 |
64 | public void playPreview(int position) throws IOException, InterruptedException {
65 | //Stops current audio
66 | if(mCurrentPosition == position && sMediaPlayer.isPlaying()) {
67 | sMediaPlayer.stop();
68 | sMediaPlayer.reset();
69 | return;
70 | }
71 |
72 | //If user plays different audio file
73 | //search in adapter, if not, take the current mCurrentAudioItem
74 | if(mCurrentPosition != position){
75 | mCurrentAudioItem = mAdapter.getAudioItemByPosition(position);
76 | mCurrentPosition = position;
77 | }
78 | sMediaPlayer.setDataSource(mCurrentAudioItem.getAbsolutePath());
79 | sMediaPlayer.prepare();
80 |
81 | sMediaPlayer.start();
82 | }
83 |
84 |
85 | /**
86 | * Get the position from current item_list playing.
87 | * @return
88 | */
89 | public long getCurrentPosition2() {
90 | return mCurrentPosition;
91 | }
92 | /**
93 | * Implementation of completion interface for
94 | * handling correctly the ends of song if is playing.
95 | * @param mp
96 | */
97 | @Override
98 | public void onCompletion(MediaPlayer mp) {
99 | Log.d("OnCompletion","OnCompletion");
100 | onCompletePlayback();
101 | }
102 |
103 | /**
104 | * If song reaches its end, then we stop and reset player
105 | * for having it ready for next playback, and doesn't throw
106 | * any error.
107 | */
108 |
109 | public void onCompletePlayback(){
110 | mAdapter.notifyItemChanged((int)getCurrentPosition2());
111 | sMediaPlayer.stop();
112 | sMediaPlayer.reset();
113 | }
114 |
115 | @Override
116 | public boolean onError(MediaPlayer mp, int what, int extra) {
117 | try{
118 | onCompletePlayback();
119 | }
120 | catch (Exception e){
121 | e.printStackTrace();
122 | }
123 | return false;
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/ScrollingAboutActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 | import android.support.design.widget.FloatingActionButton;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.support.v7.widget.Toolbar;
9 | import android.view.View;
10 | import android.widget.TextView;
11 |
12 | public class ScrollingAboutActivity extends AppCompatActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | super.onCreate(savedInstanceState);
17 | //Set layout of activity
18 | setContentView(R.layout.activity_scrolling_about);
19 | //Set an action bar
20 | Toolbar toolbar = findViewById(R.id.toolbar);
21 | setSupportActionBar(toolbar);
22 | toolbar.setNavigationOnClickListener(new View.OnClickListener() {
23 | @Override
24 | public void onClick(View v) {
25 | ScrollingAboutActivity.super.onBackPressed();
26 | }
27 | });
28 |
29 | //Set UI elements
30 | FloatingActionButton fab = findViewById(R.id.fab);
31 | TextView jaudiotagger = findViewById(R.id.audiotagger);
32 | TextView glide = findViewById(R.id.glide);
33 | TextView gnsdk = findViewById(R.id.gnsdk);
34 | TextView drawer = findViewById(R.id.drawer_image);
35 | TextView crashlytics = findViewById(R.id.crashlytics_lib);
36 | TextView iconics = findViewById(R.id.iconics_lib);
37 |
38 | //Set listener for UI elements
39 | fab.setOnClickListener(new View.OnClickListener() {
40 | @Override
41 | public void onClick(View view) {
42 | openInExternalApp(Intent.ACTION_SENDTO, "mailto: dark.yellow.studios@gmail.com");
43 | }
44 | });
45 |
46 | jaudiotagger.setOnClickListener(new View.OnClickListener() {
47 | @Override
48 | public void onClick(View v) {
49 | openInExternalApp(Intent.ACTION_VIEW, "http://www.jthink.net/jaudiotagger/");
50 | }
51 | });
52 |
53 | glide.setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | openInExternalApp(Intent.ACTION_VIEW, "https://github.com/bumptech/glide");
57 | }
58 | });
59 |
60 | gnsdk.setOnClickListener(new View.OnClickListener() {
61 | @Override
62 | public void onClick(View v) {
63 | openInExternalApp(Intent.ACTION_VIEW, "https://developer.gracenote.com/gnsdk");
64 | }
65 | });
66 |
67 | drawer.setOnClickListener(new View.OnClickListener() {
68 | @Override
69 | public void onClick(View v) {
70 | openInExternalApp(Intent.ACTION_VIEW, "https://tgs266.deviantart.com/");
71 | }
72 | });
73 |
74 | crashlytics.setOnClickListener(new View.OnClickListener() {
75 | @Override
76 | public void onClick(View v) {
77 | openInExternalApp(Intent.ACTION_VIEW, "https://fabric.io/kits/android/crashlytics");
78 | }
79 | });
80 | iconics.setOnClickListener(new View.OnClickListener() {
81 | @Override
82 | public void onClick(View v) {
83 | openInExternalApp(Intent.ACTION_VIEW, "https://github.com/mikepenz/Android-Iconics");
84 | }
85 | });
86 | //Get action bar from toolbar
87 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
88 | getSupportActionBar().setTitle(getString(R.string.about));
89 | }
90 |
91 | /**
92 | * Receives an action and let the system show you
93 | * the apps that can handle this action
94 | * @param action
95 | * @param msg
96 | */
97 | private void openInExternalApp(String action, String msg){
98 | Uri uri = Uri.parse(msg);
99 | Intent intent = new Intent(action, uri);
100 | startActivity(intent);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/services/DetectorRemovableMediaStorages.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.services;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.os.Build;
8 | import android.preference.PreferenceManager;
9 | import android.support.v4.content.ContextCompat;
10 | import android.support.v4.content.LocalBroadcastManager;
11 | import android.util.Log;
12 | import android.view.Gravity;
13 | import android.view.View;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import mx.dev.franco.automusictagfixer.R;
18 | import mx.dev.franco.automusictagfixer.utilities.Constants;
19 | import mx.dev.franco.automusictagfixer.utilities.Settings;
20 | import mx.dev.franco.automusictagfixer.utilities.StorageHelper;
21 |
22 | /**
23 | * Created by franco on 12/01/18.
24 | */
25 |
26 | public final class DetectorRemovableMediaStorages extends BroadcastReceiver{
27 | private LocalBroadcastManager mLocalBroadcastManager;
28 | private Context mContext;
29 |
30 | public DetectorRemovableMediaStorages(Context context){
31 | mContext = context;
32 | mLocalBroadcastManager = LocalBroadcastManager.getInstance(mContext);
33 | }
34 |
35 | @Override
36 | public void onReceive(Context context, Intent intent) {
37 | Log.d("media","works");
38 | String action = intent.getAction();
39 | Toast toast = Toast.makeText(context, "", Toast.LENGTH_LONG);
40 | View view = toast.getView();
41 | TextView text = view.findViewById(android.R.id.message);
42 | text.setTextColor(ContextCompat.getColor(context, R.color.grey_900));
43 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
44 | text.setTextAppearance(R.style.CustomToast);
45 | }
46 | else {
47 | text.setTextAppearance(context,R.style.CustomToast);
48 | }
49 | view.setBackground(ContextCompat.getDrawable(context, R.drawable.background_custom_toast) );
50 | toast.setGravity(Gravity.CENTER, 0, 0);
51 |
52 | if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
53 | text.setText(context.getString(R.string.media_mounted));
54 | }
55 | else if(action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
56 | text.setText(context.getString(R.string.media_unmounted));
57 | //Revoke permission to write to SD card and remove URI from shared preferences.
58 | if(Constants.URI_SD_CARD != null) {
59 | int takeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
60 | context.getContentResolver().releasePersistableUriPermission(Constants.URI_SD_CARD, takeFlags);
61 | Constants.URI_SD_CARD = null;
62 | Settings.ENABLE_SD_CARD_ACCESS = false;
63 | }
64 |
65 | SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.Application.FULL_QUALIFIED_NAME, Context.MODE_PRIVATE);
66 | SharedPreferences.Editor editor = sharedPreferences.edit();
67 | editor.remove(Constants.URI_TREE);
68 | editor.apply();
69 |
70 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
71 | SharedPreferences.Editor e = preferences.edit();
72 | e.putBoolean("key_enable_sd_card_access",false);
73 | e.commit();
74 | }
75 |
76 | toast.show();
77 | //Reload number of storages availables
78 | StorageHelper.getInstance(context).getBasePaths().clear();
79 | StorageHelper.getInstance(context).detectStorages();
80 |
81 | boolean isServiceRunning = ServiceHelper.withContext(context).withService(FixerTrackService.CLASS_NAME).isServiceRunning();
82 | //if media has mounted or unmounted, stop service to avoid
83 | //inconsistency in data
84 | if(isServiceRunning){
85 | Intent intentStopService = new Intent();
86 | intentStopService.setAction(Constants.Actions.ACTION_STOP_SERVICE);
87 | intentStopService.putExtra(Constants.Actions.ACTION_STOP_SERVICE, Constants.StopsReasons.CANCEL_TASK);
88 | mLocalBroadcastManager.sendBroadcast(intent);
89 | }
90 |
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/AppCompatPreferenceActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.content.SharedPreferences;
4 | import android.content.res.Configuration;
5 | import android.os.Bundle;
6 | import android.preference.PreferenceActivity;
7 | import android.preference.PreferenceManager;
8 | import android.support.annotation.LayoutRes;
9 | import android.support.annotation.NonNull;
10 | import android.support.annotation.Nullable;
11 | import android.support.v7.app.ActionBar;
12 | import android.support.v7.app.AppCompatDelegate;
13 | import android.support.v7.widget.Toolbar;
14 | import android.view.MenuInflater;
15 | import android.view.MenuItem;
16 | import android.view.View;
17 | import android.view.ViewGroup;
18 |
19 | /**
20 | * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls
21 | * to be used with AppCompat.
22 | */
23 | public abstract class AppCompatPreferenceActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
24 |
25 | private AppCompatDelegate mDelegate;
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | getDelegate().installViewFactory();
30 | getDelegate().onCreate(savedInstanceState);
31 | super.onCreate(savedInstanceState);
32 | }
33 |
34 | @Override
35 | protected void onPostCreate(Bundle savedInstanceState) {
36 | super.onPostCreate(savedInstanceState);
37 | getDelegate().onPostCreate(savedInstanceState);
38 | }
39 |
40 | public ActionBar getSupportActionBar() {
41 | return getDelegate().getSupportActionBar();
42 | }
43 |
44 | public void setSupportActionBar(@Nullable Toolbar toolbar) {
45 | getDelegate().setSupportActionBar(toolbar);
46 | }
47 |
48 | @NonNull
49 | @Override
50 | public MenuInflater getMenuInflater() {
51 | return getDelegate().getMenuInflater();
52 | }
53 |
54 | @Override
55 | public void setContentView(@LayoutRes int layoutResID) {
56 | getDelegate().setContentView(layoutResID);
57 | }
58 |
59 | @Override
60 | public void setContentView(View view) {
61 | getDelegate().setContentView(view);
62 | }
63 |
64 | @Override
65 | public void setContentView(View view, ViewGroup.LayoutParams params) {
66 | getDelegate().setContentView(view, params);
67 | }
68 |
69 | @Override
70 | public void addContentView(View view, ViewGroup.LayoutParams params) {
71 | getDelegate().addContentView(view, params);
72 | }
73 |
74 | @Override
75 | protected void onPostResume() {
76 | super.onPostResume();
77 | getDelegate().onPostResume();
78 | }
79 |
80 | @Override
81 | protected void onTitleChanged(CharSequence title, int color) {
82 | super.onTitleChanged(title, color);
83 | getDelegate().setTitle(title);
84 | }
85 |
86 | @Override
87 | public void onConfigurationChanged(Configuration newConfig) {
88 | super.onConfigurationChanged(newConfig);
89 | getDelegate().onConfigurationChanged(newConfig);
90 | }
91 |
92 | @Override
93 | protected void onStop() {
94 | super.onStop();
95 | getDelegate().onStop();
96 | }
97 |
98 | @Override
99 | protected void onDestroy() {
100 | super.onDestroy();
101 | getDelegate().onDestroy();
102 | }
103 |
104 | public void invalidateOptionsMenu() {
105 | getDelegate().invalidateOptionsMenu();
106 | }
107 |
108 | private AppCompatDelegate getDelegate() {
109 | if (mDelegate == null) {
110 | mDelegate = AppCompatDelegate.create(this, null);
111 | }
112 | return mDelegate;
113 | }
114 |
115 | @Override
116 | public void onBackPressed() {
117 | super.onBackPressed();
118 | }
119 |
120 | @Override
121 | public boolean onOptionsItemSelected(MenuItem item) {
122 | int id = item.getItemId();
123 | if (id == android.R.id.home) {
124 | onBackPressed();
125 | return true;
126 | }
127 | return super.onOptionsItemSelected(item);
128 | }
129 |
130 | @Override
131 | protected void onResume(){
132 | super.onResume();
133 | PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
134 | }
135 |
136 | @Override
137 | protected void onPause(){
138 | super.onPause();
139 | PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
111 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/TransparentActivity.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer;
2 |
3 | import android.app.Activity;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.os.Build;
8 | import android.os.Bundle;
9 | import android.preference.PreferenceManager;
10 | import android.support.v4.content.ContextCompat;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.view.Gravity;
13 | import android.view.View;
14 | import android.widget.Button;
15 | import android.widget.ImageButton;
16 | import android.widget.TextView;
17 | import android.widget.Toast;
18 |
19 | import mx.dev.franco.automusictagfixer.utilities.Constants;
20 | import mx.dev.franco.automusictagfixer.utilities.RequiredPermissions;
21 | import mx.dev.franco.automusictagfixer.utilities.Settings;
22 |
23 | public class TransparentActivity extends AppCompatActivity {
24 | private boolean mSuccess = false;
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_transparent);
30 | Button button = findViewById(R.id.request_permission_button);
31 | button.setOnClickListener(new View.OnClickListener() {
32 | @Override
33 | public void onClick(View v) {
34 | Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
35 | startActivityForResult(intent, RequiredPermissions.REQUEST_PERMISSION_SAF);
36 | }
37 | });
38 |
39 | ImageButton closeInstructions = findViewById(R.id.close_instructions);
40 | closeInstructions.setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | finish();
44 | }
45 | });
46 |
47 | }
48 |
49 | @Override
50 | public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
51 | if (requestCode == RequiredPermissions.REQUEST_PERMISSION_SAF && resultCode == Activity.RESULT_OK) {
52 | // The document selected by the user won't be returned in the intent.
53 | // Instead, a URI to that document will be contained in the return intent
54 | // provided to this method as a parameter. Pull that uri using "resultData.getData()"
55 | if (resultData != null) {
56 | //Save root Uri of SD card
57 | Constants.URI_SD_CARD = resultData.getData();
58 |
59 | // Persist access permissions.
60 | // Persist access permissions.
61 | final int takeFlags = resultData.getFlags()
62 | & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
63 | getContentResolver().takePersistableUriPermission(Constants.URI_SD_CARD, takeFlags);
64 |
65 | SharedPreferences sharedPreferences = getSharedPreferences(Constants.Application.FULL_QUALIFIED_NAME, Context.MODE_PRIVATE);
66 | SharedPreferences.Editor editor = sharedPreferences.edit();
67 | editor.putString(Constants.URI_TREE, Constants.URI_SD_CARD.toString());
68 | editor.apply();
69 | mSuccess = true;
70 | Settings.ENABLE_SD_CARD_ACCESS = true;
71 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
72 | SharedPreferences.Editor e = preferences.edit();
73 | e.putBoolean("key_enable_sd_card_access",true);
74 | e.commit();
75 | }
76 | }
77 | else {
78 | mSuccess = false;
79 | }
80 | finish();
81 | }
82 |
83 | @Override
84 | public void onDestroy(){
85 | Toast toast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_LONG);
86 | View view = toast.getView();
87 | TextView text = view.findViewById(android.R.id.message);
88 | text.setTextColor(ContextCompat.getColor(this.getApplicationContext(), R.color.grey_900));
89 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
90 | text.setTextAppearance(R.style.CustomToast);
91 | } else {
92 | text.setTextAppearance(this.getApplicationContext(), R.style.CustomToast);
93 | }
94 | view.setBackground(ContextCompat.getDrawable(getApplicationContext(), R.drawable.background_custom_toast));
95 | toast.setGravity(Gravity.CENTER, 0, 0);
96 |
97 | String msg;
98 | if(mSuccess){
99 | msg = getString(R.string.permission_granted);
100 | toast.setDuration(Toast.LENGTH_SHORT);
101 | }
102 | else {
103 | msg = getString(R.string.permission_granted_fail);
104 | }
105 |
106 | text.setText(msg);
107 | toast.show();
108 |
109 | super.onDestroy();
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_transparent.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
19 |
29 |
39 |
40 |
50 |
51 |
59 |
60 |
61 |
70 |
71 |
72 |
81 |
82 |
83 |
92 |
93 |
102 |
103 |
112 |
113 |
122 |
123 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoMusicTagFixer
2 | ********************************************************************************************************************************
3 | -VERY IMPORTANT:
4 | 1. This app is Beta version yet.
5 | 2. This app uses an ACR technology powered by Gracenote, visit https://developer.gracenote.com/gnsdk for more information.
6 | 3. This app uses the awesome jAudioTagger library, visit http://www.jthink.net/jaudiotagger/ for more information.
7 | 4. This app uses the amazing Glide library, visit https://github.com/bumptech/glide for more information.
8 | 5- This app and source code is made for Android >= 5, so maybe doesn't work on Android <= 4 BUT you can fork it and adapt tou your needs!!
9 | ********************************************************************************************************************************
10 | - NOTICE!: Now the app is published under beta state, so you can directly download by join it to beta program, click in below link:
11 |
12 | https://play.google.com/apps/testing/mx.dev.franco.automusictagfixer
13 |
14 | What does it do?
15 | - For every audio file you have in your smartphone (all supported audio types by Android and jAudioTagger library), it will generate an audio fingerprint, then will connect to an ACR server and will download the correct data for every song, later will allow you to correct the song with this downloaded information; in other words, it will make a Shazam-like recognition but not from audio recorded, but over audio files you have and will correct their meta tags, including filename.
16 |
17 | For what?
18 | - The objective of this app is to correct meta tags from your audio files to help you maintain your musical library more organized.
19 |
20 | What does it offer?
21 | - Automatic, semiautomatic and manual correction for your audio files.
22 | - It will be totally free(if license of ACR service allows me), open source and ad free.
23 |
24 | What corrects?
25 | - Automatic, semi automatic and manual mode allows to correct title, artist, album, genre, track number, publication track year, cover art and filename (it will apply the same name of title, if is ON on Settings app).
26 | - Download cover mode only corrects the cover art.
27 |
28 |
29 | Features:
30 | - Tags correction for your audio files. It currently fully supports Mp3, Mp4 (Mp4 audio, M4a and M4p audio) Ogg Vorbis, Flac and Wma, there is limited support for Wav and Real formats.(http://www.jthink.net/jaudiotagger/index.jsp).
31 | - Full support for files both non removable external storage(better known as internal or shared storage) and removable storage(SD Card).
32 | - Material Design UI with dark theme for battery save on AMOLED displays.
33 | - Automatic mode: Allows select one or more songs from list and correct them without user intervention.
34 | - Semi automatic mode: Downloads track information, but requires confirmation from user to apply found tags.
35 | - Manual mode: Allows to edit tags manually, including cover art.
36 | - Download cover mode: Downloads only the cover art and allows save it as embbed cover art or indepedent image file.
37 | - Extraction and saved of cover art from audio file.
38 | - Basic media player integrated(no forward nor backward, only playing funcionality).
39 | - Additional display of song data like: file size, channels, file type, resolution, frequency and speed in Kbps.
40 | - Search widget integrated in list.
41 | - One-button selection for selecting all tracks, for use in automatic mode.
42 | - First app use tutorial (after splash screen).
43 | - Different sort types for list in main activity.
44 | - Correction indicator for knowing what songs are already corrected, what songs are missing data, what songs are no corrected yet and what songs can not correct with this app(are not supported).
45 | - Current correction progress indicator for every song when automatic and semi automatic modes are used.
46 | - Automatic and manual updating of list, in case songs are added or removed from your smartphone.
47 | - The correction made, including cover art, is made over the file itself, means that changes are visible to every media player able to read ID3 tags(most nowadays).
48 | - For MP3 files, in any mode of correction, ID3 tags version 1 will be automatically converted to ID3 version 2, this conversion will allow to write covers over the file itself(and other tags) to mp3 files, because ID3 version 1 has not support for some tags.
49 | - Background correction (with notification in status bar indicating the progress of task an ability to stop it from here) no matter if you close the app.
50 | - Crashlytics to report back to developer issues and crashes.
51 |
52 | How to build it?
53 |
54 | 1. Download zip and import project from Android Studio, or import directly from Android Studio using the repo URL.
55 | 2. Enter here and register an account: https://developer.gracenote.com/gnsdk.
56 | 3. Once you have registered, go to MyAccount -> My Apps in top menu.
57 | 4. Create a new app, follow the instructions to create it.
58 | 5. Once you have created the app, use the info provided from it and put the corresponding values into these fields in GnService class:
59 |
60 | public static final String sGnsdkLicenseString;
61 | public static final String sGnsdkClientId;
62 | public static final String sGnsdkClientTag;
63 |
64 | 6. Then, in Android Studio go to Build -> Build APK.
65 | 7. When apk is generated, copy it to your device and install it.
66 | 8. That's all!!!, Hope you enjoy correcting your songs in an easier way, and mainly: FREE.
67 |
68 | NOTE: It is very important that you create a new application as indicated in steps 4 and 5, because each free registered application has a consultation quota that you can do at a given time.
69 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/Constants.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import android.net.Uri;
4 |
5 | import mx.dev.franco.automusictagfixer.BuildConfig;
6 |
7 | /**
8 | * Created by franco on 27/10/17.
9 | */
10 |
11 | public class Constants {
12 | public static final String MEDIA_STORE_ID = "media_store_id";
13 | public static final String AUDIO_ITEM = "audio_item";
14 | public static final String POSITION = "position";
15 | public static final String COMPLETE_READ = "complete_read";
16 | public static final String SORT_KEY = "key_default_sort";
17 | public static final String ALL_ITEMS_CHECKED = "all_items_checked";
18 | public static final String ACTION_OPEN_MAIN_ACTIVITY = "action_open_main_activity";
19 | public static final String URI_TREE = "uri_tree";
20 |
21 | public static Uri URI_SD_CARD = null;
22 |
23 | public static class Application{
24 | public static String FULL_QUALIFIED_NAME = BuildConfig.APPLICATION_ID;
25 | }
26 |
27 | public static class CorrectionModes {
28 | public static String MODE = "correction_mode";
29 | public static final int AUTOMATIC = 0;
30 | public static final int SEMI_AUTOMATIC = 1;
31 | public static final int MANUAL = 2;
32 | public static final int VIEW_INFO = 3;
33 | }
34 |
35 | public static class TrackModes{
36 | public static String SINGLE_TRACK = "single_track";
37 | public static boolean SINGLE = true;
38 | public static boolean MULTIPLE = false;
39 | }
40 |
41 | public static class Actions {
42 | public static final String ACTION_SHOW_NOTIFICATION = BuildConfig.APPLICATION_ID + "." + "action_show_notification";
43 | public static final String ACTION_NOT_FOUND = BuildConfig.APPLICATION_ID + "." + "action_not_found";
44 | public static final String ACTION_DONE = BuildConfig.APPLICATION_ID + "." + "action_done";
45 | public static final String ACTION_DONE_DETAILS = BuildConfig.APPLICATION_ID + "." + "action_done_details";
46 | public static final String ACTION_CANCEL_TASK = BuildConfig.APPLICATION_ID + "." + "action_cancel";
47 | public static final String ACTION_CANCEL_TRACK_ID = BuildConfig.APPLICATION_ID + "." + "action_cancel_track_id";
48 | public static final String ACTION_FAIL = BuildConfig.APPLICATION_ID + "." + "action_fail";
49 | public static final String ACTION_COMPLETE_TASK = BuildConfig.APPLICATION_ID + "." + "action_complete_task";
50 | public static final String ACTION_SET_AUDIOITEM_PROCESSING = BuildConfig.APPLICATION_ID + "." + "action_set_audioitem_processing";
51 | public static final String ACTION_START_TASK = BuildConfig.APPLICATION_ID + "." +"action_start_task";
52 |
53 | public static final String ACTION_SHOULD_CONTINUE = BuildConfig.APPLICATION_ID + "." + "action_should_continue";
54 | public static final String ACTION_INTERNET_CONNECTION = BuildConfig.APPLICATION_ID + "." + "action_internet_connection";
55 | public static final String ACTION_CONNECTION_LOST = BuildConfig.APPLICATION_ID + "." + "action_connection_lost" ;
56 | public static final String ACTION_ERROR = BuildConfig.APPLICATION_ID + "." + "action_error" ;
57 | public static final String ACTION_STOP_SERVICE = BuildConfig.APPLICATION_ID + "." + "action_stop_service";
58 |
59 | public static final String ACTION_REQUEST_UPDATE_LIST = BuildConfig.APPLICATION_ID + "." + "action_request_update_list";
60 | }
61 |
62 | public static class Activities {
63 | public static final String FROM_EDIT_MODE = "from_edit_mode";
64 | public static final boolean DETAILS_ACTIVITY = true;
65 | }
66 |
67 | public static class GnServiceActions{
68 | public static final String ACTION_API_INITIALIZED = BuildConfig.APPLICATION_ID + "." +"action_api_initialized";
69 | public static final String API_ERROR = BuildConfig.APPLICATION_ID + "." + "api_error";
70 | }
71 |
72 | public static class Conditions {
73 | public static final int NO_INTERNET_CONNECTION = 2;
74 | public static final int NO_INITIALIZED_API = 1;
75 |
76 | }
77 |
78 | public static class StopsReasons {
79 | public static final int CONTINUE_TASK = -1;
80 | public static final int NORMAL_TERMINATION_TASK = 0;
81 | public static final int USER_CANCEL_TASK = 1;
82 | public static final int CANCEL_TASK = 2;
83 | public static final int ERROR_TASK = 3;
84 | public static final int LOST_CONNECTION_TASK = 4;
85 | public static final int REMOVABLE_MEDIA_CHANGE = 5;
86 |
87 | }
88 |
89 | public static class State{
90 | public static final String BEGIN_PROCESSING = "kMusicIdFileCallbackStatusProcessingBegin";
91 | public static final String QUERYING_INFO = "kMusicIdFileCallbackStatusFileInfoQuery";
92 | public static final String COMPLETE_IDENTIFICATION = "kMusicIdFileCallbackStatusProcessingComplete";
93 | public static final String STATUS_ERROR = "kMusicIdFileCallbackStatusError";
94 | public static final String STATUS_PROCESSING_ERROR = "kMusicIdFileCallbackStatusProcessingError";
95 |
96 | public static final String BEGIN_PROCESSING_MSG = "Iniciando corrección";
97 | public static final String QUERYING_INFO_MSG = "Solicitando información";
98 | public static final String COMPLETE_IDENTIFICATION_MSG = "Identificación completa";
99 | public static final String STATUS_ERROR_MSG = "Error";
100 | public static final String STATUS_PROCESSING_ERROR_MSG = "Error al procesar ";
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/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 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/app/src/main/java/mx/dev/franco/automusictagfixer/utilities/FileSaver.java:
--------------------------------------------------------------------------------
1 | package mx.dev.franco.automusictagfixer.utilities;
2 |
3 | import android.os.Environment;
4 | import android.util.Log;
5 |
6 | import java.io.File;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.text.DateFormat;
10 | import java.text.ParseException;
11 | import java.text.SimpleDateFormat;
12 | import java.util.Date;
13 |
14 | /**
15 | * Created by franco on 3/10/17.
16 | */
17 |
18 | public final class FileSaver {
19 | private static final String SLASH = "/";
20 | private static final String AUTO_MUSIC_TAG_FIXER_FOLDER_NAME = "Covers";
21 | private static final String EXTENSION = "jpg";
22 | private static final String DOT = ".";
23 | public static final String NULL_DATA = "null data";
24 | public static final String NO_EXTERNAL_STORAGE_WRITABLE = "no external storage writable";
25 | public static final String INPUT_OUTPUT_ERROR = "i/o error";
26 |
27 | /**
28 | *
29 | * @param data Image data
30 | * @param title The title of song if exist
31 | * @param artist The artist of song if exist
32 | * @param album The album of song if exist
33 | * @return string absolute path where image was saved or
34 | * any other string representing the error.
35 | * @throws IOException
36 | */
37 | public static String saveImageFile(byte[] data, String title, String artist, String album) throws IOException {
38 |
39 | //No data to write
40 | if(data == null)
41 | return NULL_DATA;
42 |
43 | //External storage es not writable
44 | if(!isExternalStorageWritable()){
45 | Log.e("error", "no external storage writable");
46 | return NO_EXTERNAL_STORAGE_WRITABLE;
47 | }
48 |
49 |
50 | //Retrieve folder app, and if doesn't exist create it before
51 | File pathToFile = getAlbumStorageDir(AUTO_MUSIC_TAG_FIXER_FOLDER_NAME);
52 |
53 | //File object representing the new image file
54 | File imageFileCreated = null;
55 | try {
56 | imageFileCreated = createFile(pathToFile, title, artist, album);
57 | }
58 | catch (ParseException e){
59 | e.printStackTrace();
60 | return INPUT_OUTPUT_ERROR;
61 | }
62 |
63 | //Stream to write
64 | FileOutputStream fos = null;
65 | try {
66 | fos = new FileOutputStream(imageFileCreated);
67 | fos.write(data);
68 | fos.flush();
69 | fos.close();
70 | } catch (IOException e) {
71 | e.printStackTrace();
72 | if(fos != null){
73 | fos.close();
74 | fos = null;
75 | }
76 | return INPUT_OUTPUT_ERROR;
77 | }
78 | return imageFileCreated.getAbsolutePath();
79 |
80 | }
81 |
82 | /**
83 | * Generates filename, appending the
84 | * current data and time to avoid repeat
85 | * file names
86 | * @param pathToFile Absolute path where will be saved the image
87 | * @param title The title of song if exist
88 | * @param artist The artist of song if exist
89 | * @param album The album of song if exist
90 | * @return File representing the image
91 | */
92 | private static File createFile(File pathToFile, String title, String artist, String album) throws ParseException {
93 | //Get and format date
94 | Date date = new Date();
95 | DateFormat now = new SimpleDateFormat("yyyyMMdd_HHmmss");
96 | String newFileName = null;
97 | //Name of image maybe title, artist, album or filename provided from pathToFile
98 | if(!title.equals("")) {
99 | newFileName = title + "_" + now.format(date);
100 | }
101 | else if(!artist.equals("")) {
102 | newFileName = artist + "_" + now.format(date);
103 | }
104 | else if(!album.equals("")){
105 | newFileName = album + "_" + now.format(date);
106 | }
107 | else {
108 | //get only name without extension
109 | newFileName = pathToFile.getName().split(".")[0] + "_" + now.format(date);
110 | }
111 |
112 | return new File(pathToFile.getAbsolutePath() + SLASH + newFileName + DOT + EXTENSION);
113 | }
114 |
115 | /**
116 | * Checks if external storage is available for read and write
117 | * */
118 | private static boolean isExternalStorageWritable() {
119 | String state = Environment.getExternalStorageState();
120 | return Environment.MEDIA_MOUNTED.equals(state);
121 | }
122 |
123 | /**
124 | *Checks if external storage is available for reading at least
125 | */
126 | private static boolean isExternalStorageReadable() {
127 | String state = Environment.getExternalStorageState();
128 | return (Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state));
129 | }
130 |
131 | /**
132 | * Get the directory for the user's public pictures directory.
133 | * @param albumName Folder/subfolder name assigned to save covers as image files
134 | * @return File representing the absolute path where images
135 | * are going to be saved
136 | */
137 | private static File getAlbumStorageDir(String albumName) {
138 |
139 | File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), albumName);
140 | if (!file.mkdirs()) {
141 | Log.d("info","folder already created");
142 | }
143 | return file;
144 | }
145 | }
146 |
--------------------------------------------------------------------------------