├── app ├── .gitignore ├── src │ └── main │ │ ├── aidl │ │ └── com │ │ │ └── yjl │ │ │ └── funk │ │ │ ├── model │ │ │ └── MusicTrack.aidl │ │ │ └── IFunkService.aidl │ │ ├── res │ │ ├── drawable-xxhdpi │ │ │ ├── ic_album.png │ │ │ ├── ic_close.png │ │ │ ├── ic_cycle.png │ │ │ ├── ic_like.png │ │ │ ├── ic_menu.png │ │ │ ├── ic_more.png │ │ │ ├── ic_pause.png │ │ │ ├── ic_play.png │ │ │ ├── ic_tag.png │ │ │ ├── ic_author.png │ │ │ ├── ic_playing.png │ │ │ ├── ic_repeat.png │ │ │ ├── ic_search.png │ │ │ ├── ic_shuffle.png │ │ │ ├── toolbar_bg.png │ │ │ ├── billboard_bg.png │ │ │ ├── default_cover.png │ │ │ ├── ic_album_info.png │ │ │ ├── ic_download.png │ │ │ ├── ic_downloaded.png │ │ │ ├── ic_hot_bill.png │ │ │ ├── ic_launcher.png │ │ │ ├── ic_like_white.png │ │ │ ├── ic_listener.png │ │ │ ├── ic_menu_about.png │ │ │ ├── ic_menu_exit.png │ │ │ ├── ic_menu_more.png │ │ │ ├── ic_music_more.png │ │ │ ├── ic_new_bill.png │ │ │ ├── ic_play_all.png │ │ │ ├── ic_play_large.png │ │ │ ├── ic_play_list.png │ │ │ ├── ic_play_pink.png │ │ │ ├── ic_skip_next.png │ │ │ ├── ic_skip_prev.png │ │ │ ├── to_next_white.png │ │ │ ├── toast_frame.9.png │ │ │ ├── head_navigation.png │ │ │ ├── ic_close_search.png │ │ │ ├── ic_menu_search.png │ │ │ ├── ic_music_detail.png │ │ │ ├── ic_notification.png │ │ │ ├── ic_pause_black.png │ │ │ ├── ic_pause_large.png │ │ │ ├── ic_status_empty.png │ │ │ ├── ic_tag_drawble.png │ │ │ ├── bg_loadingdialog.png │ │ │ ├── ic_launcher_round.png │ │ │ ├── ic_menu_settings.png │ │ │ ├── ic_multiple_choice.png │ │ │ ├── ic_play_list_black.png │ │ │ ├── ic_seek_bar_thumb.png │ │ │ ├── ic_skip_next_large.png │ │ │ ├── ic_skip_prev_large.png │ │ │ ├── default_cover_small.png │ │ │ ├── ic_arrow_back_white.png │ │ │ ├── ic_check_white_48dp.png │ │ │ ├── ic_clear_white_48dp.png │ │ │ ├── ic_status_no_network.png │ │ │ ├── ic_error_outline_white_48dp.png │ │ │ └── ic_info_outline_white_48dp.png │ │ ├── drawable-hdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── drawable-mdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── drawable-xhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── drawable-xxxhdpi │ │ │ ├── ic_launcher.png │ │ │ └── ic_launcher_round.png │ │ ├── drawable │ │ │ ├── card_foreground.xml │ │ │ ├── shape_album_cover.xml │ │ │ ├── btn_action_bg_selector.xml │ │ │ ├── divider_line_vertical.xml │ │ │ ├── shape_radius_black_trans_bg.xml │ │ │ ├── shape_playing_tag.xml │ │ │ ├── btn_ripple_background.xml │ │ │ ├── common_ripple.xml │ │ │ ├── default_load_cover.xml │ │ │ ├── default_load_cover_small.xml │ │ │ ├── default_load_cover_circle.xml │ │ │ └── style_progress_seek_bar.xml │ │ ├── layout │ │ │ ├── rv_footer.xml │ │ │ ├── headlayout_navigation.xml │ │ │ ├── view_play_lrc.xml │ │ │ ├── loading_dialog.xml │ │ │ ├── fragment_my_music.xml │ │ │ ├── fragment_artist_intro.xml │ │ │ ├── fragment_artist_album.xml │ │ │ ├── view_loading.xml │ │ │ ├── item_album_circle_view.xml │ │ │ ├── view_status_empty.xml │ │ │ ├── view_status_no_netwotk.xml │ │ │ ├── toast_layout.xml │ │ │ ├── fragment_tab.xml │ │ │ ├── fragment_album_list.xml │ │ │ ├── view_play_album.xml │ │ │ ├── include_music_toolbar.xml │ │ │ ├── view_music_detail.xml │ │ │ ├── fragment_search.xml │ │ │ ├── item_special_album.xml │ │ │ ├── fragment_artist_hot_song.xml │ │ │ ├── dialog_album_info.xml │ │ │ ├── layout_notification.xml │ │ │ └── item_special_music.xml │ │ ├── anim │ │ │ ├── slide_out.xml │ │ │ └── slide_in.xml │ │ ├── values │ │ │ ├── array.xml │ │ │ ├── strings.xml │ │ │ ├── dimens.xml │ │ │ ├── colors.xml │ │ │ ├── attrs.xml │ │ │ └── styles.xml │ │ └── menu │ │ │ └── navigation_menu.xml │ │ ├── java │ │ └── com │ │ │ └── yjl │ │ │ └── funk │ │ │ ├── imageloader │ │ │ ├── frescohelper │ │ │ │ ├── listener │ │ │ │ │ └── LoadFrescoListener.java │ │ │ │ └── MyBitmapMemoryCacheParamsSupplier.java │ │ │ ├── processors │ │ │ │ ├── internal │ │ │ │ │ ├── Utils.java │ │ │ │ │ └── RSBlur.java │ │ │ │ ├── GrayscalePostprocessor.java │ │ │ │ ├── ColorFilterPostprocessor.java │ │ │ │ └── MaskPostprocessor.java │ │ │ └── frescoview │ │ │ │ ├── BaseFrescoImageView.java │ │ │ │ └── FrescoController.java │ │ │ ├── widget │ │ │ ├── PagerIndicator.java │ │ │ ├── lrc │ │ │ │ ├── LrcUtils.java │ │ │ │ └── LrcFinder.java │ │ │ ├── NetWorkErrorView.java │ │ │ ├── DataEmptyView.java │ │ │ ├── AlbumCircleView.java │ │ │ ├── ColorfulFontTextView.java │ │ │ ├── LoadingDialog.java │ │ │ ├── ToastyUtils.java │ │ │ └── AlbumIntroDialog.java │ │ │ ├── network │ │ │ ├── HttpCallback.java │ │ │ ├── HttpInterceptor.java │ │ │ ├── JsonCallback.java │ │ │ └── HttpException.java │ │ │ ├── model │ │ │ ├── MusicEvent.java │ │ │ ├── AlbumList3.java │ │ │ ├── Lrc.java │ │ │ ├── AblumList1.java │ │ │ ├── AlbumList2.java │ │ │ ├── AlbumList.java │ │ │ ├── ArtistAlbumList.java │ │ │ ├── ArtistSongList.java │ │ │ ├── NewAlbumListData.java │ │ │ ├── ArtistList.java │ │ │ ├── FragmentName.java │ │ │ ├── SearchResult.java │ │ │ ├── PlayModeEnum.java │ │ │ ├── AlbumInfo.java │ │ │ ├── OnlineSongList.java │ │ │ ├── Search.java │ │ │ ├── DownloadInfo.java │ │ │ └── Billboard.java │ │ │ ├── audiocache │ │ │ ├── file │ │ │ │ ├── FileNameGenerator.java │ │ │ │ ├── DiskUsage.java │ │ │ │ ├── UnlimitedDiskUsage.java │ │ │ │ ├── MusicFileNameGenerator.java │ │ │ │ ├── TotalSizeLruDiskUsage.java │ │ │ │ ├── TotalCountLruDiskUsage.java │ │ │ │ ├── LruDiskUsage.java │ │ │ │ └── Files.java │ │ │ ├── CacheListener.java │ │ │ ├── sourcestorage │ │ │ │ ├── SourceInfoStorage.java │ │ │ │ ├── SourceInfoStorageFactory.java │ │ │ │ └── NoSourceInfoStorage.java │ │ │ ├── headers │ │ │ │ ├── EmptyHeadersInjector.java │ │ │ │ └── HeaderInjector.java │ │ │ ├── Cache.java │ │ │ ├── InterruptedProxyCacheException.java │ │ │ ├── SourceInfo.java │ │ │ ├── ProxyCacheException.java │ │ │ ├── ByteArraySource.java │ │ │ ├── Preconditions.java │ │ │ ├── Config.java │ │ │ ├── Source.java │ │ │ ├── ByteArrayCache.java │ │ │ ├── IgnoreHostProxySelector.java │ │ │ ├── GetRequest.java │ │ │ ├── StorageUtils.java │ │ │ └── ProxyCacheUtils.java │ │ │ ├── ui │ │ │ ├── base │ │ │ │ ├── BaseFragment.java │ │ │ │ └── BaseMusicActivity.java │ │ │ ├── adapter │ │ │ │ ├── PlayPagerAdapter.java │ │ │ │ ├── NewSpecialSongAdapter.java │ │ │ │ ├── NewAlbumListAdapter.java │ │ │ │ └── OnlineMusicListAdapter.java │ │ │ └── fragment │ │ │ │ ├── MyMusicFragment.java │ │ │ │ └── ArtistIntroFragment.java │ │ │ ├── utils │ │ │ ├── RxBus.java │ │ │ ├── ScreenUtils.java │ │ │ ├── DensityUtils.java │ │ │ ├── AppUtil.java │ │ │ ├── Preferences.java │ │ │ └── FileUtils.java │ │ │ ├── player │ │ │ └── Constants.java │ │ │ ├── receiver │ │ │ └── MediaButtonIntentReceiver.java │ │ │ ├── MyApplication.java │ │ │ ├── service │ │ │ └── ServiceStub.java │ │ │ └── handler │ │ │ └── MusicPlayerHandler.java │ │ └── AndroidManifest.xml ├── proguard-rules.pro └── build.gradle ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .idea ├── copyright │ └── profiles_settings.xml ├── vcs.xml ├── inspectionProfiles │ ├── profiles_settings.xml │ └── Project_Default.xml ├── modules.xml ├── runConfigurations.xml ├── gradle.xml ├── compiler.xml └── misc.xml ├── screenshot ├── Screenshot_2017-12-07-13-45-44-08.png ├── Screenshot_2017-12-07-13-46-27-90.png ├── Screenshot_2017-12-07-13-46-34-50.png ├── Screenshot_2017-12-07-13-46-56-22.png ├── Screenshot_2017-12-07-13-47-02-78.png ├── Screenshot_2017-12-07-13-47-12-16.png ├── Screenshot_2017-12-07-13-47-36-30.png └── Screenshot_2017-12-07-13-49-16-30.png ├── .gitignore ├── gradle.properties ├── README.md └── gradlew.bat /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/yjl/funk/model/MusicTrack.aidl: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | parcelable MusicTrack; 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_album.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_album.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_close.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_cycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_cycle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_like.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_like.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_pause.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_tag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_tag.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_author.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_author.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_playing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_playing.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_repeat.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_shuffle.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/toolbar_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/toolbar_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/billboard_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/billboard_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/default_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/default_cover.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_album_info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_album_info.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_download.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_downloaded.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_downloaded.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_hot_bill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_hot_bill.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_like_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_like_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_listener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_listener.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu_about.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu_exit.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu_more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_music_more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_music_more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_new_bill.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_new_bill.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play_all.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play_list.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play_pink.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_next.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_skip_next.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_prev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_skip_prev.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/to_next_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/to_next_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/toast_frame.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/toast_frame.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-45-44-08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-45-44-08.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-46-27-90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-46-27-90.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-46-34-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-46-34-50.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-46-56-22.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-46-56-22.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-47-02-78.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-47-02-78.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-47-12-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-47-12-16.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-47-36-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-47-36-30.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2017-12-07-13-49-16-30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/screenshot/Screenshot_2017-12-07-13-49-16-30.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/head_navigation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/head_navigation.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_close_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_close_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu_search.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_music_detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_music_detail.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_notification.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_pause_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_pause_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_pause_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_pause_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_status_empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_status_empty.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_tag_drawble.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_tag_drawble.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/bg_loadingdialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/bg_loadingdialog.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_menu_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_menu_settings.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_multiple_choice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_multiple_choice.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_play_list_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_play_list_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_seek_bar_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_seek_bar_thumb.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_next_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_skip_next_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_skip_prev_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_skip_prev_large.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/default_cover_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/default_cover_small.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_arrow_back_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_arrow_back_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_check_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_check_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_clear_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_status_no_network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_status_no_network.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_error_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_error_outline_white_48dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_info_outline_white_48dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TONYYAM/funk/HEAD/app/src/main/res/drawable-xxhdpi/ic_info_outline_white_48dp.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/card_foreground.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_album_cover.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_action_bg_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/divider_line_vertical.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_radius_black_trans_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Oct 31 16:58:16 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/frescohelper/listener/LoadFrescoListener.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.frescohelper.listener; 2 | 3 | import android.graphics.Bitmap; 4 | 5 | public interface LoadFrescoListener { 6 | void onSuccess(Bitmap bitmap); 7 | 8 | void onFail(); 9 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/PagerIndicator.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | public interface PagerIndicator { 4 | 5 | public void setNum(int num); 6 | 7 | public int getTotal(); 8 | 9 | public void setSelected(int index); 10 | 11 | public int getCurrentIndex(); 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/res/layout/rv_footer.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_playing_tag.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_ripple_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/common_ripple.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/network/HttpCallback.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.network; 2 | 3 | /** 4 | * Created by hzwangchenyan on 2017/2/8. 5 | */ 6 | public abstract class HttpCallback { 7 | public abstract void onSuccess(T t); 8 | 9 | public abstract void onFail(HttpException e); 10 | 11 | public void onFinish() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/MusicEvent.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by tonyy on 2017/11/18. 5 | */ 6 | 7 | public class MusicEvent { 8 | private String msg; 9 | 10 | public MusicEvent(String msg) { 11 | this.msg = msg; 12 | } 13 | 14 | public String getMsg() { 15 | return msg; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/AlbumList3.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/6. 5 | */ 6 | 7 | public class AlbumList3 { 8 | private AlbumList2 RM; 9 | 10 | public AlbumList2 getRM() { 11 | return RM; 12 | } 13 | 14 | public void setRM(AlbumList2 RM) { 15 | this.RM = RM; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/FileNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import com.yjl.funk.model.MusicTrack; 4 | 5 | /** 6 | * Generator for files to be used for caching. 7 | * 8 | * @author Alexey Danilov (danikula@gmail.com). 9 | */ 10 | public interface FileNameGenerator { 11 | 12 | String generate(MusicTrack track); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/DiskUsage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Declares how {@link FileCache} will use disc space. 8 | * 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public interface DiskUsage { 12 | 13 | void touch(File file) throws IOException; 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/default_load_cover.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/CacheListener.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * Listener for cache availability. 7 | * 8 | * @author Egor Makovsky (yahor.makouski@gmail.com) 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public interface CacheListener { 12 | 13 | void onCacheAvailable(File cacheFile, String url, int percentsAvailable); 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/Lrc.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | 4 | /** 5 | * JavaBean 6 | * Created by hzwangchenyan on 2016/1/13. 7 | */ 8 | public class Lrc { 9 | private String lrcContent; 10 | 11 | public String getLrcContent() { 12 | return lrcContent; 13 | } 14 | 15 | public void setLrcContent(String lrcContent) { 16 | this.lrcContent = lrcContent; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/AblumList1.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/6. 7 | */ 8 | 9 | public class AblumList1 { 10 | private List list; 11 | 12 | public List getList() { 13 | return list; 14 | } 15 | 16 | public void setList(List list) { 17 | this.list = list; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/default_load_cover_small.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/AlbumList2.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/6. 5 | */ 6 | 7 | public class AlbumList2 { 8 | private AblumList1 album_list; 9 | 10 | public AblumList1 getAlbum_list() { 11 | return album_list; 12 | } 13 | 14 | public void setAlbum_list(AblumList1 album_list) { 15 | this.album_list = album_list; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/default_load_cover_circle.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_out.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/AlbumList.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/10. 7 | */ 8 | 9 | public class AlbumList { 10 | List album_list; 11 | 12 | public List getAlbum_list() { 13 | return album_list; 14 | } 15 | 16 | public void setAlbum_list(List album_list) { 17 | this.album_list = album_list; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/ArtistAlbumList.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/9. 7 | */ 8 | 9 | public class ArtistAlbumList { 10 | List albumlist; 11 | 12 | public List getAlbumlist() { 13 | return albumlist; 14 | } 15 | 16 | public void setAlbumlist(List albumlist) { 17 | this.albumlist = albumlist; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/ArtistSongList.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/9. 7 | */ 8 | 9 | public class ArtistSongList { 10 | List songList; 11 | 12 | public List getSongList() { 13 | return songList; 14 | } 15 | 16 | public void setSongList(List songList) { 17 | this.songList = songList; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/res/anim/slide_in.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/UnlimitedDiskUsage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | /** 7 | * Unlimited version of {@link DiskUsage}. 8 | * 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public class UnlimitedDiskUsage implements DiskUsage { 12 | 13 | @Override 14 | public void touch(File file) throws IOException { 15 | // do nothing 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/sourcestorage/SourceInfoStorage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.sourcestorage; 2 | 3 | 4 | import com.yjl.funk.audiocache.SourceInfo; 5 | 6 | /** 7 | * Storage for {@link SourceInfo}. 8 | * 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public interface SourceInfoStorage { 12 | 13 | SourceInfo get(String url); 14 | 15 | void put(String url, SourceInfo sourceInfo); 16 | 17 | void release(); 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/headlayout_navigation.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/NewAlbumListData.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/6. 5 | */ 6 | 7 | public class NewAlbumListData { 8 | private AlbumList3 plaze_album_list; 9 | 10 | public AlbumList3 getPlaze_album_list() { 11 | return plaze_album_list; 12 | } 13 | 14 | public void setPlaze_album_list(AlbumList3 plaze_album_list) { 15 | this.plaze_album_list = plaze_album_list; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 放克音乐 5 | 我的音乐 6 | 7 | 8 | 热门歌曲 9 | 专辑 10 | 歌手信息 11 | 12 | 13 | 单曲 14 | 专辑 15 | 歌手 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/ArtistList.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/10. 7 | */ 8 | 9 | public class ArtistList { 10 | private List artist_list; 11 | 12 | public List getArtist_list() { 13 | return artist_list; 14 | } 15 | 16 | public void setArtist_list(List artist_list) { 17 | this.artist_list = artist_list; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/headers/EmptyHeadersInjector.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.headers; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Empty {@link HeaderInjector} implementation. 8 | * 9 | * @author Lucas Nelaupe (https://github.com/lucas34). 10 | */ 11 | public class EmptyHeadersInjector implements HeaderInjector { 12 | 13 | @Override 14 | public Map addHeaders(String url) { 15 | return new HashMap<>(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_play_lrc.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/loading_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/FragmentName.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/10. 5 | */ 6 | 7 | public class FragmentName { 8 | public final static String TAB = "TAB"; 9 | public final static String BILLBOARD = "BILLBOARD"; 10 | public final static String NEW_ALBUM = "NEW_ALBUM"; 11 | public final static String ALBUM_INFO = "ALBUM_INFO"; 12 | public final static String ARTIST_INFO = "ARTIST_INFO"; 13 | public final static String SEARCH = "SEARCH"; 14 | public final static String PLAYING = "PLAYING"; 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/Cache.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | /** 4 | * Cache for proxy. 5 | * 6 | * @author Alexey Danilov (danikula@gmail.com). 7 | */ 8 | public interface Cache { 9 | 10 | long available() throws ProxyCacheException; 11 | 12 | int read(byte[] buffer, long offset, int length) throws ProxyCacheException; 13 | 14 | void append(byte[] data, int length) throws ProxyCacheException; 15 | 16 | void close() throws ProxyCacheException; 17 | 18 | void complete() throws ProxyCacheException; 19 | 20 | boolean isCompleted(); 21 | } 22 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/SearchResult.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/10. 5 | */ 6 | 7 | public class SearchResult { 8 | int error_code; 9 | private Search result; 10 | 11 | public int getError_code() { 12 | return error_code; 13 | } 14 | 15 | public void setError_code(int error_code) { 16 | this.error_code = error_code; 17 | } 18 | 19 | public Search getResult() { 20 | return result; 21 | } 22 | 23 | public void setResult(Search result) { 24 | this.result = result; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_my_music.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/sourcestorage/SourceInfoStorageFactory.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.sourcestorage; 2 | 3 | import android.content.Context; 4 | 5 | /** 6 | * Simple factory for {@link SourceInfoStorage}. 7 | * 8 | * @author Alexey Danilov (danikula@gmail.com). 9 | */ 10 | public class SourceInfoStorageFactory { 11 | 12 | public static SourceInfoStorage newSourceInfoStorage(Context context) { 13 | return new DatabaseSourceInfoStorage(context); 14 | } 15 | 16 | public static SourceInfoStorage newEmptySourceInfoStorage() { 17 | return new NoSourceInfoStorage(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/lrc/LrcUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget.lrc; 2 | 3 | import android.text.format.DateUtils; 4 | 5 | import java.util.Locale; 6 | 7 | /** 8 | * Created by hzwangchenyan on 2017/10/18. 9 | */ 10 | public class LrcUtils { 11 | 12 | public static String formatTime(long milli) { 13 | int m = (int) (milli / DateUtils.MINUTE_IN_MILLIS); 14 | int s = (int) ((milli / DateUtils.SECOND_IN_MILLIS) % 60); 15 | String mm = String.format(Locale.getDefault(), "%02d", m); 16 | String ss = String.format(Locale.getDefault(), "%02d", s); 17 | return mm + ":" + ss; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/sourcestorage/NoSourceInfoStorage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.sourcestorage; 2 | 3 | 4 | import com.yjl.funk.audiocache.SourceInfo; 5 | 6 | /** 7 | * {@link SourceInfoStorage} that does nothing. 8 | * 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public class NoSourceInfoStorage implements SourceInfoStorage { 12 | 13 | @Override 14 | public SourceInfo get(String url) { 15 | return null; 16 | } 17 | 18 | @Override 19 | public void put(String url, SourceInfo sourceInfo) { 20 | } 21 | 22 | @Override 23 | public void release() { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_artist_intro.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 放克音乐 3 | 设置 4 | 关于放克音乐 5 | 退出放克音乐 6 | Billboard 7 | 音乐排行 8 | 新碟上架 9 | 每\n日\n更\n新 10 | 正\n在\n播\n放 11 | 播放全部 12 | 多选 13 | 暂无歌词 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/InterruptedProxyCacheException.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | /** 4 | * Indicates interruption error in work of {@link ProxyCache} fired by user. 5 | * 6 | * @author Alexey Danilov 7 | */ 8 | public class InterruptedProxyCacheException extends ProxyCacheException { 9 | 10 | public InterruptedProxyCacheException(String message) { 11 | super(message); 12 | } 13 | 14 | public InterruptedProxyCacheException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | public InterruptedProxyCacheException(Throwable cause) { 19 | super(cause); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/PlayModeEnum.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | public enum PlayModeEnum { 4 | LOOP(0), 5 | SHUFFLE(1), 6 | SINGLE(2); 7 | 8 | private int value; 9 | 10 | PlayModeEnum(int value) { 11 | this.value = value; 12 | } 13 | 14 | public static PlayModeEnum valueOf(int value) { 15 | switch (value) { 16 | case 1: 17 | return SHUFFLE; 18 | case 2: 19 | return SINGLE; 20 | case 0: 21 | default: 22 | return LOOP; 23 | } 24 | } 25 | 26 | public int value() { 27 | return value; 28 | } 29 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/headers/HeaderInjector.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.headers; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Allows to add custom headers to server's requests. 7 | * 8 | * @author Lucas Nelaupe (https://github.com/lucas34). 9 | */ 10 | public interface HeaderInjector { 11 | 12 | /** 13 | * Adds headers to server's requests for corresponding url. 14 | * 15 | * @param url an url headers will be added for 16 | * @return a map with headers, where keys are header's names, and values are header's values. {@code null} is not acceptable! 17 | */ 18 | Map addHeaders(String url); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/AlbumInfo.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/8. 7 | */ 8 | 9 | public class AlbumInfo { 10 | private Album albumInfo; 11 | private List songlist; 12 | 13 | public Album getAlbumInfo() { 14 | return albumInfo; 15 | } 16 | 17 | public void setAlbumInfo(Album albumInfo) { 18 | this.albumInfo = albumInfo; 19 | } 20 | 21 | public List getSonglist() { 22 | return songlist; 23 | } 24 | 25 | public void setSonglist(List songlist) { 26 | this.songlist = songlist; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/OnlineSongList.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Administrator on 2017/11/6. 7 | */ 8 | 9 | public class OnlineSongList { 10 | private List song_list; 11 | private Billboard billboard; 12 | 13 | public List getSong_list() { 14 | return song_list; 15 | } 16 | 17 | public void setSong_list(List song_list) { 18 | this.song_list = song_list; 19 | } 20 | 21 | public Billboard getBillboard() { 22 | return billboard; 23 | } 24 | public void setBillboard(Billboard billboard) { 25 | this.billboard = billboard; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_artist_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 15 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/menu/navigation_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/yjl/funk/IFunkService.aidl: -------------------------------------------------------------------------------- 1 | // IFunkService.aidl 2 | package com.yjl.funk; 3 | 4 | import com.yjl.funk.model.MusicTrack; 5 | 6 | interface IFunkService { 7 | void play(int position); 8 | void setPlayListAndPlay(in List track,int position); 9 | MusicTrack getCurrentTrack(); 10 | List getPlayList(); 11 | void setPlayMode(int mode); 12 | int getPlayMode(); 13 | int getNowPlayingPosition(); 14 | boolean isPlaying(); 15 | boolean isPreparing(); 16 | boolean isPausing(); 17 | boolean isIdle(); 18 | int duration(); 19 | int position(); 20 | int secondPosition(); 21 | void playOrPause(); 22 | void next(); 23 | void prev(); 24 | void seekTo(int progress); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 100dp 4 | 34dp 5 | 8dp 6 | 12dp 7 | 50dp 8 | 5dp 9 | 60dp 10 | 1000 11 | 13sp 12 | 11sp 13 | 6dp 14 | 1dp 15 | 30dp 16 | 40dp 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/SourceInfo.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | /** 4 | * Stores source's info. 5 | * 6 | * @author Alexey Danilov (danikula@gmail.com). 7 | */ 8 | public class SourceInfo { 9 | 10 | public final String url; 11 | public final long length; 12 | public final String mime; 13 | 14 | public SourceInfo(String url, long length, String mime) { 15 | this.url = url; 16 | this.length = length; 17 | this.mime = mime; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "SourceInfo{" + 23 | "url='" + url + '\'' + 24 | ", length=" + length + 25 | ", mime='" + mime + '\'' + 26 | '}'; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/MusicFileNameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import com.yjl.funk.model.MusicTrack; 4 | import com.yjl.funk.utils.FileUtils; 5 | 6 | 7 | /** 8 | * Implementation of {@link FileNameGenerator} that uses MD5 of url as file name 9 | * 10 | * @author Alexey Danilov (danikula@gmail.com). 11 | */ 12 | public class MusicFileNameGenerator implements FileNameGenerator { 13 | 14 | private static final int MAX_EXTENSION_LENGTH = 4; 15 | 16 | @Override 17 | public String generate( MusicTrack track) { 18 | String name = ""; 19 | if(track!=null) { 20 | name = track.getAuthor()+"-"+track.getTitle()+ FileUtils.MP3; 21 | } 22 | return name; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /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/java/com/yjl/funk/audiocache/ProxyCacheException.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import android.support.design.BuildConfig; 4 | 5 | /** 6 | * Indicates any error in work of {@link ProxyCache}. 7 | * 8 | * @author Alexey Danilov 9 | */ 10 | public class ProxyCacheException extends Exception { 11 | 12 | private static final String LIBRARY_VERSION = ". Version: " + BuildConfig.VERSION_NAME; 13 | 14 | public ProxyCacheException(String message) { 15 | super(message + LIBRARY_VERSION); 16 | } 17 | 18 | public ProxyCacheException(String message, Throwable cause) { 19 | super(message + LIBRARY_VERSION, cause); 20 | } 21 | 22 | public ProxyCacheException(Throwable cause) { 23 | super("No explanation error" + LIBRARY_VERSION, cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/TotalSizeLruDiskUsage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * {@link DiskUsage} that uses LRU (Least Recently Used) strategy and trims cache size to max size if needed. 7 | * 8 | * @author Alexey Danilov (danikula@gmail.com). 9 | */ 10 | public class TotalSizeLruDiskUsage extends LruDiskUsage { 11 | 12 | private final long maxSize; 13 | 14 | public TotalSizeLruDiskUsage(long maxSize) { 15 | if (maxSize <= 0) { 16 | throw new IllegalArgumentException("Max size must be positive number!"); 17 | } 18 | this.maxSize = maxSize; 19 | } 20 | 21 | @Override 22 | protected boolean accept(File file, long totalSize, int totalCount) { 23 | return totalSize <= maxSize; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/TotalCountLruDiskUsage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * {@link DiskUsage} that uses LRU (Least Recently Used) strategy and trims cache size to max files count if needed. 7 | * 8 | * @author Alexey Danilov (danikula@gmail.com). 9 | */ 10 | public class TotalCountLruDiskUsage extends LruDiskUsage { 11 | 12 | private final int maxCount; 13 | 14 | public TotalCountLruDiskUsage(int maxCount) { 15 | if (maxCount <= 0) { 16 | throw new IllegalArgumentException("Max count must be positive number!"); 17 | } 18 | this.maxCount = maxCount; 19 | } 20 | 21 | @Override 22 | protected boolean accept(File file, long totalSize, int totalCount) { 23 | return totalCount <= maxCount; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/network/HttpInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.network; 2 | 3 | import android.os.Build; 4 | 5 | import java.io.IOException; 6 | 7 | import okhttp3.Interceptor; 8 | import okhttp3.Request; 9 | import okhttp3.Response; 10 | 11 | /** 12 | * Created by hzwangchenyan on 2017/3/30. 13 | */ 14 | public class HttpInterceptor implements Interceptor { 15 | public static final String UA = "User-Agent"; 16 | 17 | @Override 18 | public Response intercept(Chain chain) throws IOException { 19 | Request request = chain.request() 20 | .newBuilder() 21 | .addHeader(UA, makeUA()) 22 | .build(); 23 | return chain.proceed(request); 24 | } 25 | 26 | public static String makeUA() { 27 | return Build.BRAND + "/" + Build.MODEL + "/" + Build.VERSION.RELEASE; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/network/JsonCallback.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.network; 2 | 3 | 4 | 5 | import com.alibaba.fastjson.JSON; 6 | import com.zhy.http.okhttp.callback.Callback; 7 | 8 | import java.io.IOException; 9 | 10 | import okhttp3.Response; 11 | 12 | /** 13 | * Json封装 14 | * Created by wcy on 2015/12/20. 15 | */ 16 | public abstract class JsonCallback extends Callback { 17 | private Class mClass; 18 | 19 | 20 | public JsonCallback(Class clazz) { 21 | this.mClass = clazz; 22 | } 23 | 24 | @Override 25 | public T parseNetworkResponse(Response response, int id) throws IOException { 26 | try { 27 | String jsonString = response.body().string(); 28 | return JSON.parseObject(jsonString,mClass); 29 | } catch (Exception e) { 30 | e.printStackTrace(); 31 | } 32 | return null; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/Search.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | /** 4 | * Created by Administrator on 2017/11/10. 5 | */ 6 | 7 | public class Search { 8 | private OnlineSongList song_info; 9 | private AlbumList album_info; 10 | private ArtistList artist_info; 11 | 12 | public OnlineSongList getSong_info() { 13 | return song_info; 14 | } 15 | 16 | public void setSong_info(OnlineSongList song_info) { 17 | this.song_info = song_info; 18 | } 19 | 20 | public AlbumList getAlbum_info() { 21 | return album_info; 22 | } 23 | 24 | public void setAlbum_info(AlbumList album_info) { 25 | this.album_info = album_info; 26 | } 27 | 28 | public ArtistList getArtist_info() { 29 | return artist_info; 30 | } 31 | 32 | public void setArtist_info(ArtistList artist_info) { 33 | this.artist_info = artist_info; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/lrc/LrcFinder.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget.lrc; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by tonyy on 2017/11/18. 7 | */ 8 | 9 | public class LrcFinder { 10 | 11 | public static int findShowLine(List mLrcEntryList, long time) { 12 | int left = 0; 13 | int right = mLrcEntryList.size(); 14 | while (left <= right) { 15 | int middle = (left + right) / 2; 16 | long middleTime = mLrcEntryList.get(middle).getTime(); 17 | 18 | if (time < middleTime) { 19 | right = middle - 1; 20 | } else { 21 | if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) { 22 | return middle; 23 | } 24 | 25 | left = middle + 1; 26 | } 27 | } 28 | 29 | return 0; 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_album_circle_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 12 | 13 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #a000d4 4 | #1AC0AF 5 | #FF4081 6 | #50FFFFFF 7 | #EEEEFF 8 | #FFFFFF 9 | #50949292 10 | #2e2e2e 11 | #8c8c8c 12 | #eeeeee 13 | #80FFFFFF 14 | #FFFFFF 15 | #FF4081 16 | #FFFFFF 17 | #FFFFFF 18 | #FFFFFF 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/NetWorkErrorView.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.FrameLayout; 8 | 9 | import com.yjl.funk.R; 10 | 11 | /** 12 | * Created by Administrator on 2017/11/9. 13 | */ 14 | 15 | public class NetWorkErrorView extends FrameLayout { 16 | 17 | public NetWorkErrorView(Context context) { 18 | this(context,null); 19 | } 20 | 21 | public NetWorkErrorView(Context context, @Nullable AttributeSet attrs) { 22 | this(context, attrs,0); 23 | } 24 | 25 | public NetWorkErrorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 26 | super(context, attrs, defStyleAttr); 27 | init(context); 28 | } 29 | private void init(Context context){ 30 | View.inflate(context, R.layout.view_status_no_netwotk,this); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_status_empty.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_status_no_netwotk.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.base; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.support.v4.app.Fragment; 6 | 7 | import com.yjl.funk.widget.DataEmptyView; 8 | import com.yjl.funk.widget.NetWorkErrorView; 9 | 10 | 11 | public abstract class BaseFragment extends Fragment { 12 | protected Activity mActivity; 13 | public NetWorkErrorView netWorkErrorView; 14 | public DataEmptyView emptyView; 15 | 16 | public abstract void initViews(); 17 | 18 | /** 19 | * 监听设置 20 | */ 21 | public abstract void initListeners(); 22 | 23 | @Override 24 | public void onStart() { 25 | super.onStart(); 26 | 27 | } 28 | 29 | @Override 30 | public void onAttach(Context context) { 31 | super.onAttach(context); 32 | this.mActivity = (Activity)context; 33 | } 34 | 35 | @Override 36 | public void onDestroyView() { 37 | super.onDestroyView(); 38 | } 39 | } -------------------------------------------------------------------------------- /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 E:\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 | 19 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/DownloadInfo.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | 4 | 5 | /** 6 | * JavaBean 7 | * Created by wcy on 2015/12/27. 8 | */ 9 | public class DownloadInfo { 10 | private Bitrate bitrate; 11 | 12 | public Bitrate getBitrate() { 13 | return bitrate; 14 | } 15 | 16 | public void setBitrate(Bitrate bitrate) { 17 | this.bitrate = bitrate; 18 | } 19 | 20 | public static class Bitrate { 21 | 22 | private int file_duration; 23 | 24 | private String file_link; 25 | 26 | public int getFile_duration() { 27 | return file_duration; 28 | } 29 | 30 | public void setFile_duration(int file_duration) { 31 | this.file_duration = file_duration; 32 | } 33 | 34 | public String getFile_link() { 35 | return file_link; 36 | } 37 | 38 | public void setFile_link(String file_link) { 39 | this.file_link = file_link; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toast_layout.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 20 | 21 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | 15 | 16 | 17 | 18 | 22 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/RxBus.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | import rx.Observable; 4 | import rx.subjects.PublishSubject; 5 | import rx.subjects.SerializedSubject; 6 | import rx.subjects.Subject; 7 | 8 | public class RxBus { 9 | private static volatile RxBus defaultInstance; 10 | 11 | private final Subject bus; 12 | // PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者 13 | public RxBus() { 14 | bus = new SerializedSubject<>(PublishSubject.create()); 15 | } 16 | // 单例RxBus 17 | public static RxBus getDefault() { 18 | if (defaultInstance == null) { 19 | synchronized (RxBus.class) { 20 | if (defaultInstance == null) { 21 | defaultInstance = new RxBus(); 22 | } 23 | } 24 | } 25 | return defaultInstance ; 26 | } 27 | // 发送一个新的事件 28 | public void post (Object o) { 29 | bus.onNext(o); 30 | } 31 | public Observable toObservable (Class eventType) { 32 | return bus.ofType(eventType); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/ByteArraySource.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import java.io.ByteArrayInputStream; 4 | 5 | /** 6 | * Simple memory based {@link Source} implementation. 7 | * 8 | * @author Alexey Danilov (danikula@gmail.com). 9 | */ 10 | public class ByteArraySource implements Source { 11 | 12 | private final byte[] data; 13 | private ByteArrayInputStream arrayInputStream; 14 | 15 | public ByteArraySource(byte[] data) { 16 | this.data = data; 17 | } 18 | 19 | @Override 20 | public int read(byte[] buffer) throws ProxyCacheException { 21 | return arrayInputStream.read(buffer, 0, buffer.length); 22 | } 23 | 24 | @Override 25 | public long length() throws ProxyCacheException { 26 | return data.length; 27 | } 28 | 29 | @Override 30 | public void open(long offset) throws ProxyCacheException { 31 | arrayInputStream = new ByteArrayInputStream(data); 32 | arrayInputStream.skip(offset); 33 | } 34 | 35 | @Override 36 | public void close() throws ProxyCacheException { 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/style_progress_seek_bar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/adapter/PlayPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v4.view.PagerAdapter; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Created by Administrator on 2017/11/21. 12 | */ 13 | 14 | public class PlayPagerAdapter extends PagerAdapter { 15 | private List views; 16 | 17 | public PlayPagerAdapter(List views) { 18 | 19 | this.views = views; 20 | } 21 | 22 | @Override 23 | public int getCount() { 24 | return views.size(); 25 | } 26 | 27 | @Override 28 | public boolean isViewFromObject(View view, Object object) { 29 | return view==object; 30 | } 31 | 32 | @Override 33 | public Object instantiateItem(ViewGroup container, int position) { 34 | container.addView(views.get(position)); 35 | return views.get(position); 36 | } 37 | 38 | @Override 39 | public void destroyItem(ViewGroup container, int position, Object object) { 40 | container.removeView(views.get(position)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/DataEmptyView.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.Nullable; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.FrameLayout; 8 | import android.widget.TextView; 9 | 10 | import com.yjl.funk.R; 11 | 12 | /** 13 | * Created by Administrator on 2017/11/9. 14 | */ 15 | 16 | public class DataEmptyView extends FrameLayout { 17 | private TextView empty; 18 | public DataEmptyView(Context context) { 19 | this(context,null); 20 | } 21 | 22 | public DataEmptyView(Context context, @Nullable AttributeSet attrs) { 23 | this(context, attrs,0); 24 | } 25 | 26 | public DataEmptyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 27 | super(context, attrs, defStyleAttr); 28 | init(context); 29 | } 30 | private void init(Context context){ 31 | View.inflate(context, R.layout.view_status_empty,this); 32 | empty = (TextView) findViewById(R.id.tv_status_empty); 33 | } 34 | public void setText(String text){ 35 | empty.setText(text); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/Preconditions.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | public final class Preconditions { 4 | 5 | public static T checkNotNull(T reference) { 6 | if (reference == null) { 7 | throw new NullPointerException(); 8 | } 9 | return reference; 10 | } 11 | 12 | public static void checkAllNotNull(Object... references) { 13 | for (Object reference : references) { 14 | if (reference == null) { 15 | throw new NullPointerException(); 16 | } 17 | } 18 | } 19 | 20 | public static T checkNotNull(T reference, String errorMessage) { 21 | if (reference == null) { 22 | throw new NullPointerException(errorMessage); 23 | } 24 | return reference; 25 | } 26 | 27 | static void checkArgument(boolean expression) { 28 | if (!expression) { 29 | throw new IllegalArgumentException(); 30 | } 31 | } 32 | 33 | static void checkArgument(boolean expression, String errorMessage) { 34 | if (!expression) { 35 | throw new IllegalArgumentException(errorMessage); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_album_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 20 | 21 | 22 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_play_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 14 | 15 | 21 | 22 | 23 | 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/fragment/MyMusicFragment.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.yjl.funk.R; 10 | import com.yjl.funk.ui.base.BaseFragment; 11 | 12 | import butterknife.ButterKnife; 13 | import butterknife.Unbinder; 14 | 15 | /** 16 | * Created by Administrator on 2017/11/1. 17 | */ 18 | 19 | public class MyMusicFragment extends BaseFragment { 20 | private Unbinder unbinder; 21 | @Nullable 22 | @Override 23 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 24 | View view = inflater.inflate(R.layout.fragment_my_music, container, false); 25 | unbinder = ButterKnife.bind(this, view); 26 | initViews(); 27 | initListeners(); 28 | return view; 29 | } 30 | 31 | @Override 32 | public void initViews() { 33 | 34 | } 35 | 36 | @Override 37 | public void initListeners() { 38 | 39 | } 40 | @Override 41 | public void onDestroyView() { 42 | super.onDestroyView(); 43 | unbinder.unbind(); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/Config.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | 4 | import com.yjl.funk.audiocache.file.DiskUsage; 5 | import com.yjl.funk.audiocache.file.FileNameGenerator; 6 | import com.yjl.funk.audiocache.headers.HeaderInjector; 7 | import com.yjl.funk.audiocache.sourcestorage.SourceInfoStorage; 8 | import com.yjl.funk.model.MusicTrack; 9 | 10 | import java.io.File; 11 | 12 | /** 13 | * Configuration for proxy cache. 14 | * 15 | * @author Alexey Danilov (danikula@gmail.com). 16 | */ 17 | class Config { 18 | 19 | public final File cacheRoot; 20 | public final FileNameGenerator fileNameGenerator; 21 | public final DiskUsage diskUsage; 22 | public final SourceInfoStorage sourceInfoStorage; 23 | public final HeaderInjector headerInjector; 24 | 25 | Config(File cacheRoot, FileNameGenerator fileNameGenerator, DiskUsage diskUsage, SourceInfoStorage sourceInfoStorage, HeaderInjector headerInjector) { 26 | this.cacheRoot = cacheRoot; 27 | this.fileNameGenerator = fileNameGenerator; 28 | this.diskUsage = diskUsage; 29 | this.sourceInfoStorage = sourceInfoStorage; 30 | this.headerInjector = headerInjector; 31 | } 32 | 33 | File generateCacheFile(MusicTrack track) { 34 | String name = fileNameGenerator.generate(track); 35 | return new File(cacheRoot, name); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/Source.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | /** 4 | * Source for proxy. 5 | * 6 | * @author Alexey Danilov (danikula@gmail.com). 7 | */ 8 | public interface Source { 9 | 10 | /** 11 | * Opens source. Source should be open before using {@link #read(byte[])} 12 | * 13 | * @param offset offset in bytes for source. 14 | * @throws ProxyCacheException if error occur while opening source. 15 | */ 16 | void open(long offset) throws ProxyCacheException; 17 | 18 | /** 19 | * Returns length bytes or negative value if length is unknown. 20 | * 21 | * @return bytes length 22 | * @throws ProxyCacheException if error occur while fetching source data. 23 | */ 24 | long length() throws ProxyCacheException; 25 | 26 | /** 27 | * Read data to byte buffer from source with current offset. 28 | * 29 | * @param buffer a buffer to be used for reading data. 30 | * @return a count of read bytes 31 | * @throws ProxyCacheException if error occur while reading source. 32 | */ 33 | int read(byte[] buffer) throws ProxyCacheException; 34 | 35 | /** 36 | * Closes source and release resources. Every opened source should be closed. 37 | * 38 | * @throws ProxyCacheException if error occur while closing source. 39 | */ 40 | void close() throws ProxyCacheException; 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/processors/internal/Utils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.processors.internal; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.content.Context; 20 | import android.graphics.drawable.Drawable; 21 | import android.os.Build; 22 | 23 | public final class Utils { 24 | 25 | private Utils() { 26 | // Utility class. 27 | } 28 | 29 | public static Drawable getMaskDrawable(Context context, int maskId) { 30 | Drawable drawable; 31 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 32 | drawable = context.getDrawable(maskId); 33 | } else { 34 | drawable = context.getResources().getDrawable(maskId); 35 | } 36 | 37 | if (drawable == null) { 38 | throw new IllegalArgumentException("maskId is invalid"); 39 | } 40 | 41 | return drawable; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.neenbedankt.android-apt' 3 | 4 | android { 5 | compileSdkVersion 25 6 | buildToolsVersion "25.0.2" 7 | defaultConfig { 8 | applicationId "com.yjl.funk" 9 | minSdkVersion 21 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | } 22 | 23 | dependencies { 24 | compile fileTree(dir: 'libs', include: ['*.jar']) 25 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 26 | exclude group: 'com.android.support', module: 'support-annotations' 27 | }) 28 | compile 'com.android.support:appcompat-v7:25.3.1' 29 | compile "com.android.support:design:25.3.1" 30 | compile 'com.zhy:okhttputils:2.6.2' 31 | /*fastjson*/ 32 | compile 'com.alibaba:fastjson:1.2.31' 33 | /*butterknife*/ 34 | compile 'com.jakewharton:butterknife:8.5.1' 35 | apt 'com.jakewharton:butterknife-compiler:8.5.1' 36 | /*fresco*/ 37 | compile 'com.facebook.fresco:fresco:1.3.0' 38 | 39 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.19' 40 | compile 'com.android.support:cardview-v7:25.3.1' 41 | /*rxbinding*/ 42 | compile 'com.jakewharton.rxbinding:rxbinding:1.0.0' 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/fragment/ArtistIntroFragment.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.TextView; 9 | 10 | import com.yjl.funk.R; 11 | import com.yjl.funk.ui.base.BaseFragment; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import butterknife.Unbinder; 16 | 17 | /** 18 | * Created by Administrator on 2017/11/9. 19 | */ 20 | 21 | public class ArtistIntroFragment extends BaseFragment { 22 | @BindView(R.id.tv_intro) 23 | TextView tvIntro; 24 | private Unbinder unbinder; 25 | 26 | @Nullable 27 | @Override 28 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 29 | View view = inflater.inflate(R.layout.fragment_artist_intro, container, false); 30 | unbinder = ButterKnife.bind(this, view); 31 | initViews(); 32 | initListeners(); 33 | return view; 34 | } 35 | 36 | @Override 37 | public void initViews() { 38 | 39 | } 40 | 41 | @Override 42 | public void initListeners() { 43 | 44 | } 45 | 46 | @Override 47 | public void onDestroyView() { 48 | super.onDestroyView(); 49 | unbinder.unbind(); 50 | } 51 | 52 | public void setInfo(String intro) { 53 | tvIntro.setText(intro); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.os.Build; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.View; 9 | import android.view.WindowManager; 10 | 11 | /** 12 | * Created by Administrator on 2017/11/1. 13 | */ 14 | 15 | public class ScreenUtils { 16 | public static void setSystemBarTransparent(AppCompatActivity context) { 17 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 18 | // LOLLIPOP解决方案 19 | context.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); 20 | context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 21 | context.getWindow().setStatusBarColor(Color.TRANSPARENT); 22 | } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 23 | // KITKAT解决方案 24 | context.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 25 | } 26 | } 27 | public static int getStatusBarHeight(Context context) { 28 | int result = 0; 29 | int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); 30 | if (resourceId > 0) { 31 | result = context.getResources().getDimensionPixelSize(resourceId); 32 | } 33 | return result; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/network/HttpException.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.network; 2 | 3 | /** 4 | * 自定义错误信息,统一处理返回处理 5 | * Created by WZG on 2016/7/16. 6 | */ 7 | public class HttpException extends RuntimeException { 8 | 9 | public static final int NO_DATA = 0x2; 10 | private String msg; 11 | private int resultCode; 12 | 13 | public HttpException(int resultCode) { 14 | this(getApiExceptionMessage(resultCode)); 15 | } 16 | public HttpException(String detailMessage) { 17 | super(detailMessage); 18 | } 19 | public HttpException(Throwable throwable){super(throwable);} 20 | public HttpException(int resultCode, String msg){ 21 | super(msg); 22 | this.msg = msg; 23 | this.resultCode = resultCode; 24 | } 25 | public String getMsg() { 26 | return msg; 27 | } 28 | 29 | public void setMsg(String msg) { 30 | this.msg = msg; 31 | } 32 | 33 | public int getResultCode() { 34 | return resultCode; 35 | } 36 | 37 | public void setResultCode(int resultCode) { 38 | this.resultCode = resultCode; 39 | } 40 | /** 41 | * 转换错误数据 42 | * 43 | * @param code 44 | * @return 45 | */ 46 | private static String getApiExceptionMessage(int code) { 47 | String message = ""; 48 | switch (code) { 49 | case NO_DATA: 50 | message = "无数据"; 51 | break; 52 | default: 53 | message = "error"; 54 | break; 55 | 56 | } 57 | return message; 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/DensityUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | 4 | import android.app.Activity; 5 | import android.content.Context; 6 | import android.util.DisplayMetrics; 7 | 8 | public class DensityUtils { 9 | 10 | // 根据手机的分辨率将dp的单位转成px(像素) 11 | public static int dip2px(Context context, float dpValue) { 12 | final float scale = context.getResources().getDisplayMetrics().density; 13 | return (int) (dpValue * scale + 0.5f); 14 | } 15 | 16 | // 根据手机的分辨率将px(像素)的单位转成dp 17 | public static int px2dip(Context context, float pxValue) { 18 | final float scale = context.getResources().getDisplayMetrics().density; 19 | return (int) (pxValue / scale + 0.5f); 20 | } 21 | 22 | // 将px值转换为sp值 23 | public static int px2sp(Context context, float pxValue) { 24 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 25 | return (int) (pxValue / fontScale + 0.5f); 26 | } 27 | 28 | // 将sp值转换为px值 29 | public static int sp2px(Context context, float spValue) { 30 | final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; 31 | return (int) (spValue * fontScale + 0.5f); 32 | } 33 | 34 | // 屏幕宽度(像素) 35 | public static int getWindowWidth(Activity context){ 36 | DisplayMetrics metric = new DisplayMetrics(); 37 | context.getWindowManager().getDefaultDisplay().getMetrics(metric); 38 | return metric.widthPixels; 39 | } 40 | 41 | // 屏幕高度(像素) 42 | public static int getWindowHeight(Activity activity){ 43 | DisplayMetrics metric = new DisplayMetrics(); 44 | activity.getWindowManager().getDefaultDisplay().getMetrics(metric); 45 | return metric.heightPixels; 46 | } 47 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/include_music_toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 29 | 30 | 31 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_music_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 19 | 20 | 31 | 32 | 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/model/Billboard.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.model; 2 | 3 | public class Billboard { 4 | private String update_date; 5 | private String name; 6 | private String comment; 7 | private String pic_s640; 8 | private String pic_s444; 9 | private String pic_s260; 10 | private String pic_s210; 11 | 12 | public String getUpdate_date() { 13 | return update_date; 14 | } 15 | 16 | public void setUpdate_date(String update_date) { 17 | this.update_date = update_date; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public String getComment() { 29 | return comment; 30 | } 31 | 32 | public void setComment(String comment) { 33 | this.comment = comment; 34 | } 35 | 36 | public String getPic_s640() { 37 | return pic_s640; 38 | } 39 | 40 | public void setPic_s640(String pic_s640) { 41 | this.pic_s640 = pic_s640; 42 | } 43 | 44 | public String getPic_s444() { 45 | return pic_s444; 46 | } 47 | 48 | public void setPic_s444(String pic_s444) { 49 | this.pic_s444 = pic_s444; 50 | } 51 | 52 | public String getPic_s260() { 53 | return pic_s260; 54 | } 55 | 56 | public void setPic_s260(String pic_s260) { 57 | this.pic_s260 = pic_s260; 58 | } 59 | 60 | public String getPic_s210() { 61 | return pic_s210; 62 | } 63 | 64 | public void setPic_s210(String pic_s210) { 65 | this.pic_s210 = pic_s210; 66 | } 67 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/processors/GrayscalePostprocessor.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.processors; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.Canvas; 21 | import android.graphics.ColorMatrix; 22 | import android.graphics.ColorMatrixColorFilter; 23 | import android.graphics.Paint; 24 | 25 | import com.facebook.cache.common.CacheKey; 26 | import com.facebook.cache.common.SimpleCacheKey; 27 | import com.facebook.imagepipeline.request.BasePostprocessor; 28 | 29 | public class GrayscalePostprocessor extends BasePostprocessor { 30 | 31 | @Override public void process(Bitmap dest, Bitmap source) { 32 | super.process(dest, source); 33 | 34 | Canvas canvas = new Canvas(dest); 35 | ColorMatrix saturation = new ColorMatrix(); 36 | saturation.setSaturation(0f); 37 | Paint paint = new Paint(); 38 | paint.setColorFilter(new ColorMatrixColorFilter(saturation)); 39 | canvas.drawBitmap(source, 0, 0, paint); 40 | } 41 | 42 | @Override public String getName() { 43 | return getClass().getSimpleName(); 44 | } 45 | 46 | @Override public CacheKey getPostprocessorCacheKey() { 47 | return new SimpleCacheKey("gray"); 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/AlbumCircleView.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.animation.ObjectAnimator; 4 | import android.animation.ValueAnimator; 5 | import android.content.Context; 6 | import android.util.AttributeSet; 7 | import android.view.animation.LinearInterpolator; 8 | 9 | import com.facebook.drawee.generic.GenericDraweeHierarchy; 10 | import com.yjl.funk.imageloader.frescoview.FrescoImageView; 11 | 12 | /** 13 | * Created by tonyy on 2017/11/18. 14 | */ 15 | 16 | public class AlbumCircleView extends FrescoImageView { 17 | private boolean is_playing = false; 18 | private boolean is_Start = false; 19 | private ObjectAnimator animator = ObjectAnimator.ofFloat(this,"rotation",0f,360f); 20 | 21 | public AlbumCircleView(Context context, GenericDraweeHierarchy hierarchy) { 22 | super(context, hierarchy); 23 | } 24 | 25 | public AlbumCircleView(Context context) { 26 | super(context); 27 | } 28 | 29 | public AlbumCircleView(Context context, AttributeSet attrs) { 30 | super(context, attrs); 31 | } 32 | 33 | public AlbumCircleView(Context context, AttributeSet attrs, int defStyle) { 34 | super(context, attrs, defStyle); 35 | } 36 | 37 | 38 | public void startRotation(){ 39 | if(is_playing) 40 | return; 41 | animator.setDuration(60*1000); 42 | animator.setInterpolator(new LinearInterpolator()); 43 | animator.setRepeatCount(ValueAnimator.INFINITE); 44 | if(is_Start){ 45 | animator.resume(); 46 | }else { 47 | animator.start(); 48 | is_Start = true; 49 | } 50 | is_playing = true; 51 | } 52 | public void pauseRotation(){ 53 | if(is_playing) 54 | animator.pause(); 55 | is_playing = false; 56 | } 57 | 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/AppUtil.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | import android.app.ActivityManager; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.Matrix; 7 | import android.graphics.drawable.BitmapDrawable; 8 | import android.graphics.drawable.Drawable; 9 | import android.os.Build; 10 | import android.os.Environment; 11 | import android.support.annotation.NonNull; 12 | import android.support.design.widget.AppBarLayout; 13 | import android.support.design.widget.CoordinatorLayout; 14 | import android.support.v4.view.ViewCompat; 15 | import android.text.TextUtils; 16 | import android.util.Log; 17 | import android.view.ViewTreeObserver; 18 | 19 | 20 | 21 | import java.io.File; 22 | import java.io.FileNotFoundException; 23 | import java.io.FileOutputStream; 24 | import java.io.IOException; 25 | import java.io.RandomAccessFile; 26 | import java.nio.MappedByteBuffer; 27 | import java.nio.channels.FileChannel; 28 | import java.text.DecimalFormat; 29 | import java.util.List; 30 | 31 | import okhttp3.ResponseBody; 32 | 33 | /** 34 | * 方法工具类 35 | * Created by WZG on 2016/10/31. 36 | */ 37 | 38 | public class AppUtil { 39 | public static String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/kdb/"; 40 | //听取数量转化字符串 41 | public static String numToStr(String num){ 42 | if(TextUtils.isEmpty(num)){ 43 | return ""; 44 | }else { 45 | Long numlong = Long.valueOf(num); 46 | if (numlong > 10000) { 47 | return (new DecimalFormat("#.0").format(numlong / 10000f)) + "万"; 48 | } else { 49 | return num; 50 | } 51 | } 52 | } 53 | public static boolean checkSDCardAvailable(){ 54 | return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/ColorfulFontTextView.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.LinearGradient; 6 | import android.graphics.Paint; 7 | import android.graphics.Rect; 8 | import android.graphics.Shader; 9 | import android.support.v4.content.ContextCompat; 10 | import android.support.v7.widget.AppCompatTextView; 11 | import android.util.AttributeSet; 12 | import android.view.Gravity; 13 | 14 | import com.yjl.funk.R; 15 | 16 | public class ColorfulFontTextView extends AppCompatTextView { 17 | 18 | int TextViewWidth; //TextView的宽度 19 | private LinearGradient mLinearGradient; //渲染器 20 | private Paint paint; 21 | private Rect mTextBound = new Rect(); 22 | private boolean is_show = false; 23 | 24 | public ColorfulFontTextView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | } 27 | 28 | 29 | @Override 30 | protected void onDraw(Canvas canvas) { 31 | super.onDraw(canvas); 32 | if (is_show) { 33 | TextViewWidth = getMeasuredWidth(); 34 | paint = getPaint(); 35 | String mTipText = getText().toString(); 36 | paint.getTextBounds(mTipText, 0, mTipText.length(), mTextBound); 37 | //初始化线性渲染器 38 | mLinearGradient = new LinearGradient(0, 0, TextViewWidth, 0, 39 | new int[]{ContextCompat.getColor(getContext(), R.color.colorAccent), ContextCompat.getColor(getContext(), R.color.colorPrimary)}, new float[] 40 | {0.3f, 0.6f}, Shader.TileMode.REPEAT); 41 | paint.setShader(mLinearGradient); 42 | canvas.drawText(mTipText,0, getMeasuredHeight() / 2 + mTextBound.height() / 2, paint); 43 | } 44 | } 45 | 46 | public void setIsShow(boolean is_show) { 47 | this.is_show = is_show; 48 | } 49 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/processors/ColorFilterPostprocessor.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.processors; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.Canvas; 21 | import android.graphics.Paint; 22 | import android.graphics.PorterDuff; 23 | import android.graphics.PorterDuffColorFilter; 24 | 25 | import com.facebook.cache.common.CacheKey; 26 | import com.facebook.cache.common.SimpleCacheKey; 27 | import com.facebook.imagepipeline.request.BasePostprocessor; 28 | 29 | public class ColorFilterPostprocessor extends BasePostprocessor { 30 | 31 | private int color; 32 | 33 | public ColorFilterPostprocessor(int color) { 34 | this.color = color; 35 | } 36 | 37 | @Override public void process(Bitmap dest, Bitmap source) { 38 | super.process(dest, source); 39 | 40 | Canvas canvas = new Canvas(dest); 41 | Paint paint = new Paint(); 42 | paint.setAntiAlias(true); 43 | paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); 44 | canvas.drawBitmap(source, 0, 0, paint); 45 | } 46 | 47 | @Override public String getName() { 48 | return getClass().getSimpleName(); 49 | } 50 | 51 | @Override public CacheKey getPostprocessorCacheKey() { 52 | return new SimpleCacheKey("color=" + color); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/ByteArrayCache.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.util.Arrays; 5 | 6 | /** 7 | * Simple memory based {@link Cache} implementation. 8 | * 9 | * @author Alexey Danilov (danikula@gmail.com). 10 | */ 11 | public class ByteArrayCache implements Cache { 12 | 13 | private volatile byte[] data; 14 | private volatile boolean completed; 15 | 16 | public ByteArrayCache() { 17 | this(new byte[0]); 18 | } 19 | 20 | public ByteArrayCache(byte[] data) { 21 | this.data = Preconditions.checkNotNull(data); 22 | } 23 | 24 | @Override 25 | public int read(byte[] buffer, long offset, int length) throws ProxyCacheException { 26 | if (offset >= data.length) { 27 | return -1; 28 | } 29 | if (offset > Integer.MAX_VALUE) { 30 | throw new IllegalArgumentException("Too long offset for memory cache " + offset); 31 | } 32 | return new ByteArrayInputStream(data).read(buffer, (int) offset, length); 33 | } 34 | 35 | @Override 36 | public long available() throws ProxyCacheException { 37 | return data.length; 38 | } 39 | 40 | @Override 41 | public void append(byte[] newData, int length) throws ProxyCacheException { 42 | Preconditions.checkNotNull(data); 43 | Preconditions.checkArgument(length >= 0 && length <= newData.length); 44 | 45 | byte[] appendedData = Arrays.copyOf(data, data.length + length); 46 | System.arraycopy(newData, 0, appendedData, data.length, length); 47 | data = appendedData; 48 | } 49 | 50 | @Override 51 | public void close() throws ProxyCacheException { 52 | } 53 | 54 | @Override 55 | public void complete() { 56 | completed = true; 57 | } 58 | 59 | @Override 60 | public boolean isCompleted() { 61 | return completed; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/frescohelper/MyBitmapMemoryCacheParamsSupplier.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.frescohelper; 2 | 3 | import android.app.ActivityManager; 4 | import android.os.Build; 5 | 6 | import com.facebook.common.internal.Supplier; 7 | import com.facebook.common.util.ByteConstants; 8 | import com.facebook.imagepipeline.cache.MemoryCacheParams; 9 | 10 | public class MyBitmapMemoryCacheParamsSupplier implements Supplier { 11 | private static final int MAX_CACHE_ENTRIES = 56; 12 | private static final int MAX_CACHE_ASHM_ENTRIES = 128; 13 | private static final int MAX_CACHE_EVICTION_SIZE = 5; 14 | private static final int MAX_CACHE_EVICTION_ENTRIES = 5; 15 | private final ActivityManager mActivityManager; 16 | 17 | public MyBitmapMemoryCacheParamsSupplier(ActivityManager activityManager) { 18 | mActivityManager = activityManager; 19 | } 20 | 21 | @Override 22 | public MemoryCacheParams get() { 23 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 24 | return new MemoryCacheParams(getMaxCacheSize(), MAX_CACHE_ENTRIES, MAX_CACHE_EVICTION_SIZE, MAX_CACHE_EVICTION_ENTRIES, 1); 25 | } else { 26 | return new MemoryCacheParams( 27 | getMaxCacheSize(), 28 | MAX_CACHE_ASHM_ENTRIES, 29 | Integer.MAX_VALUE, 30 | Integer.MAX_VALUE, 31 | Integer.MAX_VALUE); 32 | } 33 | } 34 | 35 | private int getMaxCacheSize() { 36 | final int maxMemory = 37 | Math.min(mActivityManager.getMemoryClass() * ByteConstants.MB, Integer.MAX_VALUE); 38 | if (maxMemory < 32 * ByteConstants.MB) { 39 | return 4 * ByteConstants.MB; 40 | } else if (maxMemory < 64 * ByteConstants.MB) { 41 | return 6 * ByteConstants.MB; 42 | } else { 43 | return maxMemory / 5; 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/adapter/NewSpecialSongAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Point; 5 | import android.support.annotation.LayoutRes; 6 | 7 | import com.chad.library.adapter.base.BaseQuickAdapter; 8 | import com.chad.library.adapter.base.BaseViewHolder; 9 | import com.jakewharton.rxbinding.view.RxView; 10 | import com.yjl.funk.player.MusicClient; 11 | import com.yjl.funk.R; 12 | import com.yjl.funk.imageloader.frescohelper.FrescoHelper; 13 | import com.yjl.funk.imageloader.frescoview.FrescoImageView; 14 | import com.yjl.funk.model.MusicTrack; 15 | import com.yjl.funk.utils.AppUtil; 16 | import java.util.List; 17 | import java.util.Random; 18 | import java.util.concurrent.TimeUnit; 19 | 20 | import rx.functions.Action1; 21 | 22 | public class NewSpecialSongAdapter extends BaseQuickAdapter { 23 | private Context context; 24 | private List tracks; 25 | 26 | public NewSpecialSongAdapter(Context context, @LayoutRes int resId, List list) { 27 | super(resId, list); 28 | this.context = context; 29 | this.tracks = list; 30 | } 31 | 32 | 33 | @Override 34 | protected void convert(final BaseViewHolder helper, final MusicTrack item) { 35 | FrescoHelper.loadFrescoImage((FrescoImageView) helper.getView(R.id.iv_pic),item.getPic_big(),R.drawable.default_load_cover,false,new Point(300,250)); 36 | helper.setText(R.id.tv_name,item.getTitle()); 37 | helper.setText(R.id.tv_describe,item.getAuthor()); 38 | helper.setText(R.id.tv_listen_count, AppUtil.numToStr(String.valueOf(new Random().nextInt(3000000)%2990001+10000))); 39 | RxView.clicks(helper.itemView).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1() { 40 | @Override 41 | public void call(Void aVoid) { 42 | MusicClient.setPlayListAndPlayAt(tracks,helper.getLayoutPosition()); 43 | } 44 | }); 45 | } 46 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/processors/internal/RSBlur.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.processors.internal; 2 | 3 | import android.annotation.TargetApi; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.os.Build; 7 | import android.renderscript.Allocation; 8 | import android.renderscript.Element; 9 | import android.renderscript.RSRuntimeException; 10 | import android.renderscript.RenderScript; 11 | import android.renderscript.ScriptIntrinsicBlur; 12 | 13 | /** 14 | * Copyright (C) 2015 Wasabeef 15 | * 16 | * Licensed under the Apache License, Version 2.0 (the "License"); 17 | * you may not use this file except in compliance with the License. 18 | * You may obtain a copy of the License at 19 | * 20 | * http://www.apache.org/licenses/LICENSE-2.0 21 | * 22 | * Unless required by applicable law or agreed to in writing, software 23 | * distributed under the License is distributed on an "AS IS" BASIS, 24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | * See the License for the specific language governing permissions and 26 | * limitations under the License. 27 | */ 28 | 29 | public class RSBlur { 30 | 31 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) 32 | public static Bitmap blur(Context context, Bitmap bitmap, int radius) throws RSRuntimeException { 33 | RenderScript rs = null; 34 | try { 35 | rs = RenderScript.create(context); 36 | Allocation input = 37 | Allocation.createFromBitmap(rs, bitmap, Allocation.MipmapControl.MIPMAP_NONE, 38 | Allocation.USAGE_SCRIPT); 39 | Allocation output = Allocation.createTyped(rs, input.getType()); 40 | ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); 41 | 42 | blur.setInput(input); 43 | blur.setRadius(radius); 44 | blur.forEach(output); 45 | output.copyTo(bitmap); 46 | } finally { 47 | if (rs != null) { 48 | rs.destroy(); 49 | } 50 | } 51 | 52 | return bitmap; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/frescoview/BaseFrescoImageView.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.frescoview; 2 | 3 | import com.facebook.drawee.controller.ControllerListener; 4 | import com.facebook.drawee.generic.RoundingParams; 5 | import com.facebook.drawee.interfaces.DraweeController; 6 | import com.facebook.imagepipeline.request.ImageRequest; 7 | import com.facebook.imagepipeline.request.Postprocessor; 8 | 9 | /** 10 | * Created by Linhh on 16/3/2. 11 | */ 12 | public interface BaseFrescoImageView { 13 | 14 | /** 15 | * 获得当前监听 16 | * @return 17 | */ 18 | public ControllerListener getControllerListener(); 19 | 20 | /** 21 | * 获得当前使用的DraweeController 22 | * @return 23 | */ 24 | public DraweeController getDraweeController(); 25 | 26 | /** 27 | * 获得低级别ImageRequest 28 | * @return 29 | */ 30 | public ImageRequest getLowImageRequest(); 31 | 32 | /** 33 | * 获得当前使用的ImageRequest 34 | * @return 35 | */ 36 | public ImageRequest getImageRequest(); 37 | 38 | /** 39 | * 获得当前使用的RoundingParams 40 | */ 41 | public RoundingParams getRoundingParams(); 42 | 43 | /** 44 | * 是否开启动画 45 | * @return 46 | */ 47 | public boolean isAnim(); 48 | 49 | /** 50 | * 获得当前后处理 51 | * @return 52 | */ 53 | public Postprocessor getPostProcessor(); 54 | 55 | /** 56 | * 获得当前使用的默认图 57 | * @return 58 | */ 59 | public int getDefaultResID(); 60 | 61 | /** 62 | * 获得当前加载的图片 63 | * @return 64 | */ 65 | public String getThumbnailUrl(); 66 | 67 | /** 68 | * 获得当前低分辨率图片 69 | * @return 70 | */ 71 | public String getLowThumbnailUrl(); 72 | 73 | /** 74 | * 获得加载的本地图片 75 | * @return 76 | */ 77 | public String getThumbnailPath(); 78 | 79 | /** 80 | * 是否可以点击重试,默认false 81 | * @return 82 | */ 83 | public boolean getTapToRetryEnabled(); 84 | 85 | /** 86 | * 是否自动旋转 87 | * @return 88 | */ 89 | public boolean getAutoRotateEnabled(); 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/IgnoreHostProxySelector.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import java.io.IOException; 4 | import java.net.Proxy; 5 | import java.net.ProxySelector; 6 | import java.net.SocketAddress; 7 | import java.net.URI; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import static com.yjl.funk.audiocache.Preconditions.checkNotNull; 12 | 13 | /** 14 | * {@link ProxySelector} that ignore system default proxies for concrete host. 15 | *

16 | * It is important to ignore system proxy for localhost connection. 17 | * 18 | * @author Alexey Danilov (danikula@gmail.com). 19 | */ 20 | class IgnoreHostProxySelector extends ProxySelector { 21 | 22 | private static final List NO_PROXY_LIST = Arrays.asList(Proxy.NO_PROXY); 23 | 24 | private final ProxySelector defaultProxySelector; 25 | private final String hostToIgnore; 26 | private final int portToIgnore; 27 | 28 | IgnoreHostProxySelector(ProxySelector defaultProxySelector, String hostToIgnore, int portToIgnore) { 29 | this.defaultProxySelector = checkNotNull(defaultProxySelector); 30 | this.hostToIgnore = checkNotNull(hostToIgnore); 31 | this.portToIgnore = portToIgnore; 32 | } 33 | 34 | static void install(String hostToIgnore, int portToIgnore) { 35 | ProxySelector defaultProxySelector = ProxySelector.getDefault(); 36 | ProxySelector ignoreHostProxySelector = new IgnoreHostProxySelector(defaultProxySelector, hostToIgnore, portToIgnore); 37 | ProxySelector.setDefault(ignoreHostProxySelector); 38 | } 39 | 40 | @Override 41 | public List select(URI uri) { 42 | boolean ignored = hostToIgnore.equals(uri.getHost()) && portToIgnore == uri.getPort(); 43 | return ignored ? NO_PROXY_LIST : defaultProxySelector.select(uri); 44 | } 45 | 46 | @Override 47 | public void connectFailed(URI uri, SocketAddress address, IOException failure) { 48 | defaultProxySelector.connectFailed(uri, address, failure); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 一款基于Android 5.0以上MaterialDesign风格的音乐播放器——FunkMusicPlayer(Aidl) 2 | ==== 3 | 4 | 5 | ScreenShots 6 | ---- 7 | 8 | 9 | 10 | 11 | 12 | Thanks 13 | --- 14 | - [AndroidVideoCache](https://github.com/danikula/AndroidVideoCache) 15 | - [okhttp-utils](https://github.com/hongyangAndroid/okhttp-utils) 16 | - [Fresco](https://github.com/facebook/fresco) 17 | - [RxBinding](https://github.com/JakeWharton/RxBinding) 18 | - [BaseRecyclerViewAdapterHelper](https://github.com/CymChad/BaseRecyclerViewAdapterHelper) 19 | 20 | Features 21 | ----- 22 | MaterialDisgn风格 23 | 24 | 在线播放 25 | 26 | 搜索音乐 27 | 28 | 边播边缓存音乐(已缓存过的音乐可以离线收听) 29 | 30 | TODO 31 | ---- 32 | 下载 33 | 34 | 多选编辑 35 | 36 | 本地音乐扫描 37 | 38 | 项目ui完善 39 | 40 | 项目还未完成,仅供参考 41 | 42 | ApiCopyright 43 | ---- 44 | 百度音乐 45 | 46 | License 47 | ----- 48 | 49 |    Copyright 2017 TonyYam 50 | 51 | Licensed under the Apache License, Version 2.0 (the "License"); 52 | you may not use this file except in compliance with the License. 53 | You may obtain a copy of the License at 54 | 55 | http://www.apache.org/licenses/LICENSE-2.0 56 | 57 | Unless required by applicable law or agreed to in writing, software 58 | distributed under the License is distributed on an "AS IS" BASIS, 59 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 60 | See the License for the specific language governing permissions and 61 | limitations under the License. 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | 23 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 24 | 30 | 31 | 32 | 33 | 40 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/LoadingDialog.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.view.Gravity; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | 11 | import com.yjl.funk.R; 12 | import com.yjl.funk.utils.DensityUtils; 13 | 14 | 15 | /** 16 | * Created by Administrator on 2017/3/18. 17 | * 加载弹窗 18 | */ 19 | 20 | public class LoadingDialog extends Dialog { 21 | private Context context; 22 | private LoadingProgressView loadingProgressView; 23 | public LoadingDialog(Context context) { 24 | this(context, R.style.LoadingDialogStyle); 25 | 26 | } 27 | 28 | public LoadingDialog(Context context, int themeResId) { 29 | super(context, themeResId); 30 | this.context = context; 31 | initView(); 32 | } 33 | 34 | @Override 35 | public void onBackPressed() { 36 | super.onBackPressed(); 37 | this.dismiss(); 38 | } 39 | public void initView(){ 40 | View view = View.inflate(context,R.layout.loading_dialog,null); 41 | loadingProgressView = (LoadingProgressView) view.findViewById(R.id.load_view); 42 | Window dialogWindow = this.getWindow(); 43 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 44 | dialogWindow.setGravity(Gravity.CENTER); 45 | lp.width = DensityUtils.dip2px(context,75); // 宽度 46 | lp.height = DensityUtils.dip2px(context,75); // 高度 47 | this.addContentView(view,lp); 48 | this.setCancelable(false); 49 | } 50 | public void onShow(){ 51 | loadingProgressView.post(new Runnable() { 52 | @Override 53 | public void run() { 54 | loadingProgressView.startAnim(); 55 | } 56 | }); 57 | this.show(); 58 | } 59 | public void onDismiss() { 60 | if (loadingProgressView != null) 61 | loadingProgressView.post(new Runnable() { 62 | @Override 63 | public void run() { 64 | loadingProgressView.stopAnim(); 65 | } 66 | }); 67 | 68 | if (this.isShowing()) 69 | this.dismiss(); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/LruDiskUsage.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.util.List; 7 | import java.util.concurrent.Callable; 8 | import java.util.concurrent.ExecutorService; 9 | import java.util.concurrent.Executors; 10 | import java.util.logging.Logger; 11 | 12 | /** 13 | * {@link DiskUsage} that uses LRU (Least Recently Used) strategy to trim cache. 14 | * 15 | * @author Alexey Danilov (danikula@gmail.com). 16 | */ 17 | public abstract class LruDiskUsage implements DiskUsage { 18 | 19 | private final ExecutorService workerThread = Executors.newSingleThreadExecutor(); 20 | 21 | @Override 22 | public void touch(File file) throws IOException { 23 | workerThread.submit(new TouchCallable(file)); 24 | } 25 | 26 | private void touchInBackground(File file) throws IOException { 27 | Files.setLastModifiedNow(file); 28 | List files = Files.getLruListFiles(file.getParentFile()); 29 | trim(files); 30 | } 31 | 32 | protected abstract boolean accept(File file, long totalSize, int totalCount); 33 | 34 | private void trim(List files) { 35 | long totalSize = countTotalSize(files); 36 | int totalCount = files.size(); 37 | for (File file : files) { 38 | boolean accepted = accept(file, totalSize, totalCount); 39 | if (!accepted) { 40 | long fileSize = file.length(); 41 | boolean deleted = file.delete(); 42 | if (deleted) { 43 | totalCount--; 44 | totalSize -= fileSize; 45 | } else { 46 | } 47 | } 48 | } 49 | } 50 | 51 | private long countTotalSize(List files) { 52 | long totalSize = 0; 53 | for (File file : files) { 54 | totalSize += file.length(); 55 | } 56 | return totalSize; 57 | } 58 | 59 | private class TouchCallable implements Callable { 60 | 61 | private final File file; 62 | 63 | public TouchCallable(File file) { 64 | this.file = file; 65 | } 66 | 67 | @Override 68 | public Void call() throws Exception { 69 | touchInBackground(file); 70 | return null; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/Preferences.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.preference.PreferenceManager; 6 | import android.support.annotation.Nullable; 7 | 8 | import com.yjl.funk.R; 9 | 10 | public class Preferences { 11 | private static final String MUSIC_ID = "music_id"; 12 | private static final String PLAY_MODE = "play_mode"; 13 | 14 | private static Context sContext; 15 | 16 | public static void init(Context context) { 17 | sContext = context.getApplicationContext(); 18 | } 19 | 20 | public static long getCurrentSongId() { 21 | return getLong(MUSIC_ID, -1); 22 | } 23 | 24 | public static void saveCurrentSongId(long id) { 25 | saveLong(MUSIC_ID, id); 26 | } 27 | 28 | public static int getPlayMode() { 29 | return getInt(PLAY_MODE, 0); 30 | } 31 | 32 | public static void savePlayMode(int mode) { 33 | saveInt(PLAY_MODE, mode); 34 | } 35 | 36 | 37 | 38 | 39 | private static boolean getBoolean(String key, boolean defValue) { 40 | return getPreferences().getBoolean(key, defValue); 41 | } 42 | 43 | private static void saveBoolean(String key, boolean value) { 44 | getPreferences().edit().putBoolean(key, value).apply(); 45 | } 46 | 47 | private static int getInt(String key, int defValue) { 48 | return getPreferences().getInt(key, defValue); 49 | } 50 | 51 | private static void saveInt(String key, int value) { 52 | getPreferences().edit().putInt(key, value).apply(); 53 | } 54 | 55 | private static long getLong(String key, long defValue) { 56 | return getPreferences().getLong(key, defValue); 57 | } 58 | 59 | private static void saveLong(String key, long value) { 60 | getPreferences().edit().putLong(key, value).apply(); 61 | } 62 | 63 | private static String getString(String key, @Nullable String defValue) { 64 | return getPreferences().getString(key, defValue); 65 | } 66 | 67 | private static void saveString(String key, @Nullable String value) { 68 | getPreferences().edit().putString(key, value).apply(); 69 | } 70 | 71 | private static SharedPreferences getPreferences() { 72 | return PreferenceManager.getDefaultSharedPreferences(sContext); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/ToastyUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.content.Context; 4 | import android.graphics.PorterDuff; 5 | import android.graphics.drawable.Drawable; 6 | import android.graphics.drawable.NinePatchDrawable; 7 | import android.os.Build; 8 | import android.support.annotation.ColorInt; 9 | import android.support.annotation.DrawableRes; 10 | import android.support.annotation.NonNull; 11 | import android.view.View; 12 | import com.yjl.funk.R; 13 | 14 | 15 | /** 16 | * This file is part of Toasty. 17 | *

18 | * Toasty is free software: you can redistribute it and/or modify 19 | * it under the terms of the GNU General Public License as published by 20 | * the Free Software Foundation, either version 3 of the License, or 21 | * (at your option) any later version. 22 | *

23 | * Toasty is distributed in the hope that it will be useful, 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | * GNU General Public License for more details. 27 | *

28 | * You should have received a copy of the GNU General Public License 29 | * along with Toasty. If not, see . 30 | */ 31 | 32 | final class ToastyUtils { 33 | private ToastyUtils() { 34 | } 35 | 36 | static Drawable tintIcon(@NonNull Drawable drawable, @ColorInt int tintColor) { 37 | drawable.setColorFilter(tintColor, PorterDuff.Mode.SRC_IN); 38 | return drawable; 39 | } 40 | 41 | static Drawable tint9PatchDrawableFrame(@NonNull Context context, @ColorInt int tintColor) { 42 | final NinePatchDrawable toastDrawable = (NinePatchDrawable) getDrawable(context, R.drawable.toast_frame); 43 | return tintIcon(toastDrawable, tintColor); 44 | } 45 | 46 | static void setBackground(@NonNull View view, Drawable drawable) { 47 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) 48 | view.setBackground(drawable); 49 | else 50 | view.setBackgroundDrawable(drawable); 51 | } 52 | 53 | static Drawable getDrawable(@NonNull Context context, @DrawableRes int id) { 54 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) 55 | return context.getDrawable(id); 56 | else 57 | return context.getResources().getDrawable(id); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/player/Constants.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.player; 2 | 3 | /** 4 | * Created by tonyy on 2017/11/12. 5 | */ 6 | 7 | public class Constants { 8 | public static final String PLAYSTATE_CHANGED = "com.yjl.funk.playstatechanged"; 9 | public static final String MUSIC_CHANGED = "com.yjl.funk.musicchanged"; 10 | public static final String PLAYLIST_CHANGED = "com.yjl.funk.playlistchanged"; 11 | public static final String LRC_ERROR = "com.yjl.funk.lrcerror"; 12 | public static final String LRC_DOWNLOADED = "com.yjl.funk.lrcdownloaded"; 13 | public static final String TRACK_ERROR = "com.yjl.funk.trackerror"; 14 | public static final String SERVICECMD = "com.yjl.funk.musicservicecommand"; 15 | public static final String TOGGLEPAUSE_ACTION = "com.yjl.funk.togglepause"; 16 | public static final String PAUSE_ACTION = "com.yjl.funk.pause"; 17 | public static final String STOP_ACTION = "com.yjl.funk.stop"; 18 | public static final String PREVIOUS_ACTION = "com.yjl.funk.previous"; 19 | public static final String NEXT_ACTION = "com.yjl.funk.next"; 20 | public static final String REPEAT_ACTION = "com.yjl.funk.repeat"; 21 | public static final String SHUFFLE_ACTION = "com.yjl.funk.shuffle"; 22 | public static final String CMDNAME = "command"; 23 | public static final String CMDTOGGLEPAUSE = "togglepause"; 24 | public static final String CMDSTOP = "stop"; 25 | public static final String CMDPAUSE = "pause"; 26 | public static final String CMDPLAY = "play"; 27 | public static final String CMDPREVIOUS = "previous"; 28 | public static final String CMDNEXT = "next"; 29 | public static final String EXTRA_NOTIFICATION = "FROM_FUNK_MUSIC_NOTIFICATION"; 30 | //随机 31 | public static final int SHUFFLE= 201; 32 | //单曲循环 33 | public static final int REPEAT_CURRENT = 202; 34 | //列表循环 35 | public static final int REPEAT_ALL = 203; 36 | public static final String TAG = "MusicPlaybackService"; 37 | //关闭当前服务 38 | public static final String SHUTDOWN = "com.yjl.funk.shutdown"; 39 | //播放器焦点变化 40 | public static final int FOCUSCHANGE = 5; 41 | //音量递减 42 | public static final int FADEDOWN = 6; 43 | //音量递增 44 | public static final int FADEUP = 7; 45 | //关闭当前服务延时 46 | public static final int IDLE_DELAY = 5 * 60 * 1000; 47 | //歌曲名称 48 | public static final String TRACK_ERROR_INFO = "trackerrorinfo"; 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_special_album.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 20 | 21 | 28 | 29 | 40 | 41 | 51 | 52 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/base/BaseMusicActivity.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.base; 2 | 3 | 4 | import android.content.ComponentName; 5 | import android.content.ServiceConnection; 6 | import android.media.AudioManager; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.support.v7.app.AppCompatActivity; 10 | 11 | import com.yjl.funk.IFunkService; 12 | import com.yjl.funk.player.MusicClient; 13 | import com.yjl.funk.utils.ScreenUtils; 14 | 15 | import butterknife.ButterKnife; 16 | 17 | 18 | /** 19 | * Created by Administrator on 2017/3/2. 20 | */ 21 | 22 | public abstract class BaseMusicActivity extends AppCompatActivity implements ServiceConnection { 23 | private MusicClient.ServiceToken mToken; 24 | @Override 25 | protected void onCreate( Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(OnLayoutInit()); 28 | ButterKnife.bind(this); 29 | initToolBar(); 30 | initViews(); 31 | initListeners(); 32 | ScreenUtils.setSystemBarTransparent(this); 33 | 34 | mToken = MusicClient.bindToService(this, this); 35 | setVolumeControlStream(AudioManager.STREAM_MUSIC); 36 | } 37 | 38 | 39 | public abstract int OnLayoutInit(); 40 | /** 41 | * 初始化控件 42 | * 43 | */ 44 | public abstract void initViews(); 45 | 46 | /** 47 | * 监听设置 48 | */ 49 | public abstract void initListeners(); 50 | /** 51 | * 初始化工具栏*/ 52 | public abstract void initToolBar(); 53 | /** 54 | * app字体不随系统字体的大小改变而改变 55 | */ 56 | 57 | @Override 58 | public void onServiceConnected(final ComponentName name, final IBinder service) { 59 | MusicClient.mService = IFunkService.Stub.asInterface(service); 60 | 61 | } 62 | 63 | 64 | @Override 65 | public void onServiceDisconnected(final ComponentName name) { 66 | MusicClient.mService = null; 67 | } 68 | @Override 69 | protected void onResume() { 70 | super.onResume(); 71 | } 72 | 73 | 74 | @Override 75 | protected void onPause() { 76 | super.onPause(); 77 | 78 | } 79 | @Override 80 | protected void onStart(){ 81 | super.onStart(); 82 | } 83 | @Override 84 | protected void onDestroy() { 85 | super.onDestroy(); 86 | //解注eventbus 87 | if (mToken != null) { 88 | MusicClient.unbindFromService(mToken); 89 | mToken = null; 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/receiver/MediaButtonIntentReceiver.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.yjl.funk.receiver; 4 | 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.media.AudioManager; 9 | import android.view.KeyEvent; 10 | import com.yjl.funk.player.Constants; 11 | import com.yjl.funk.service.FunkMusicService; 12 | 13 | /** 14 | * 耳机线控 15 | */ 16 | public class MediaButtonIntentReceiver extends BroadcastReceiver { 17 | 18 | private static void sendBroadCast(Context context, String command) { 19 | final Intent i = new Intent(context, FunkMusicService.class); 20 | i.setAction(Constants.SERVICECMD); 21 | i.putExtra(Constants.CMDNAME, command); 22 | context.startService(i); 23 | } 24 | @Override 25 | public void onReceive(final Context context, final Intent intent) { 26 | final String intentAction = intent.getAction(); 27 | //拔耳机 28 | if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intentAction)) { 29 | sendBroadCast(context, Constants.CMDPAUSE); 30 | } else if (Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) { 31 | final KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT); 32 | if (event == null) { 33 | return; 34 | } 35 | final int keycode = event.getKeyCode(); 36 | 37 | String command = null; 38 | switch (keycode) { 39 | case KeyEvent.KEYCODE_MEDIA_STOP: 40 | command = Constants.CMDSTOP; 41 | break; 42 | case KeyEvent.KEYCODE_MEDIA_NEXT: 43 | command = Constants.CMDNEXT; 44 | break; 45 | case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 46 | command = Constants.CMDPREVIOUS; 47 | break; 48 | case KeyEvent.KEYCODE_MEDIA_PAUSE: 49 | command = Constants.CMDPAUSE; 50 | break; 51 | case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 52 | case KeyEvent.KEYCODE_HEADSETHOOK: 53 | command = Constants.CMDTOGGLEPAUSE; 54 | break; 55 | case KeyEvent.KEYCODE_MEDIA_PLAY: 56 | command = Constants.CMDPLAY; 57 | break; 58 | } 59 | abortBroadcast(); 60 | sendBroadCast(context, command); 61 | 62 | } 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.utils; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | 7 | import com.yjl.funk.network.HttpCallback; 8 | import com.yjl.funk.network.HttpClient; 9 | import com.yjl.funk.network.HttpException; 10 | 11 | import java.io.BufferedWriter; 12 | import java.io.File; 13 | import java.io.FileWriter; 14 | import java.io.IOException; 15 | 16 | public class FileUtils { 17 | public static final String MP3 = ".mp3"; 18 | public static final String LRC = ".lrc"; 19 | public static final String COVER = "cover_"; 20 | public static String getAppDir() { 21 | return Environment.getExternalStorageDirectory().getAbsolutePath() + "/FunkMusic"; 22 | } 23 | 24 | public static String getMusicDir() { 25 | String dir = getAppDir() + "/music/"; 26 | return mkdirs(dir); 27 | } 28 | public static File getCacheDirFile() { 29 | String dir = getAppDir() + "/cache/"; 30 | return new File(dir); 31 | } 32 | public static String getLrcDir() { 33 | String dir = getAppDir() + "/lyric/"; 34 | return mkdirs(dir); 35 | } 36 | 37 | public static String getAlbumDir() { 38 | String dir = getAppDir() + "/album/"; 39 | return mkdirs(dir); 40 | } 41 | 42 | 43 | private static String mkdirs(String dir) { 44 | File file = new File(dir); 45 | if (!file.exists()) { 46 | file.mkdirs(); 47 | } 48 | return dir; 49 | } 50 | public static boolean exists(String path) { 51 | File file = new File(path); 52 | return file.exists(); 53 | } 54 | //下载专辑封面 55 | public static void downloadAlbumCover(String picUrl, String fileName) { 56 | HttpClient.downloadFile(picUrl, FileUtils.getAlbumDir(), fileName, new HttpCallback() { 57 | @Override 58 | public void onSuccess(File file) { 59 | } 60 | 61 | @Override 62 | public void onFail(HttpException e) { 63 | } 64 | 65 | @Override 66 | public void onFinish() { 67 | 68 | } 69 | }); 70 | } 71 | public static void saveLrcFile(String path, String content) { 72 | try { 73 | BufferedWriter bw = new BufferedWriter(new FileWriter(path)); 74 | bw.write(content); 75 | bw.flush(); 76 | bw.close(); 77 | } catch (IOException e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/GetRequest.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import android.text.TextUtils; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | 12 | import static com.yjl.funk.audiocache.Preconditions.checkNotNull; 13 | 14 | /** 15 | * Model for Http GET request. 16 | * 17 | * @author Alexey Danilov (danikula@gmail.com). 18 | */ 19 | class GetRequest { 20 | 21 | private static final Pattern RANGE_HEADER_PATTERN = Pattern.compile("[R,r]ange:[ ]?bytes=(\\d*)-"); 22 | private static final Pattern URL_PATTERN = Pattern.compile("GET /(.*) HTTP"); 23 | 24 | public final String uri; 25 | public final long rangeOffset; 26 | public final boolean partial; 27 | 28 | public GetRequest(String request) { 29 | checkNotNull(request); 30 | long offset = findRangeOffset(request); 31 | this.rangeOffset = Math.max(0, offset); 32 | this.partial = offset >= 0; 33 | this.uri = findUri(request); 34 | } 35 | 36 | public static GetRequest read(InputStream inputStream) throws IOException { 37 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8")); 38 | StringBuilder stringRequest = new StringBuilder(); 39 | String line; 40 | while (!TextUtils.isEmpty(line = reader.readLine())) { // until new line (headers ending) 41 | stringRequest.append(line).append('\n'); 42 | } 43 | return new GetRequest(stringRequest.toString()); 44 | } 45 | 46 | private long findRangeOffset(String request) { 47 | Matcher matcher = RANGE_HEADER_PATTERN.matcher(request); 48 | if (matcher.find()) { 49 | String rangeValue = matcher.group(1); 50 | return Long.parseLong(rangeValue); 51 | } 52 | return -1; 53 | } 54 | 55 | private String findUri(String request) { 56 | Matcher matcher = URL_PATTERN.matcher(request); 57 | if (matcher.find()) { 58 | return matcher.group(1); 59 | } 60 | throw new IllegalArgumentException("Invalid request `" + request + "`: url not found!"); 61 | } 62 | 63 | @Override 64 | public String toString() { 65 | return "GetRequest{" + 66 | "rangeOffset=" + rangeOffset + 67 | ", partial=" + partial + 68 | ", uri='" + uri + '\'' + 69 | '}'; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/adapter/NewAlbumListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.graphics.Point; 6 | import android.support.annotation.LayoutRes; 7 | import android.text.TextUtils; 8 | import android.view.View; 9 | import android.widget.TextView; 10 | 11 | import com.chad.library.adapter.base.BaseQuickAdapter; 12 | import com.chad.library.adapter.base.BaseViewHolder; 13 | import com.jakewharton.rxbinding.view.RxView; 14 | import com.yjl.funk.R; 15 | import com.yjl.funk.imageloader.frescohelper.FrescoHelper; 16 | import com.yjl.funk.imageloader.frescoview.FrescoImageView; 17 | import com.yjl.funk.model.Album; 18 | import com.yjl.funk.ui.activity.MainActivity; 19 | import com.yjl.funk.utils.NetworkUtil; 20 | import com.yjl.funk.widget.Toasty; 21 | 22 | import java.util.List; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import rx.functions.Action1; 26 | 27 | /** 28 | * Created by Administrator on 2017/11/6. 29 | */ 30 | 31 | public class NewAlbumListAdapter extends BaseQuickAdapter { 32 | private Context context; 33 | private boolean is_time; 34 | public NewAlbumListAdapter(Context context, @LayoutRes int resId, List list,boolean is_time) { 35 | super(resId, list); 36 | this.context = context; 37 | this.is_time = is_time; 38 | } 39 | 40 | 41 | @Override 42 | protected void convert(BaseViewHolder helper, final Album item) { 43 | if (item != null) { 44 | FrescoHelper.loadFrescoImage((FrescoImageView) helper.getView(R.id.iv_pic), item.getPic_big() + "@s_1,w_450,h_450", R.drawable.default_load_cover, false, new Point(400, 500)); 45 | helper.setText(R.id.tv_name, item.getTitle()); 46 | helper.setText(R.id.tv_describe, item.getAuthor()); 47 | TextView publish = helper.getView(R.id.tv_publish_time); 48 | if(is_time) 49 | publish.setText("发布时间 " + item.getPublishtime()); 50 | else publish.setVisibility(View.GONE); 51 | RxView.clicks(helper.itemView).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1() { 52 | @Override 53 | public void call(Void aVoid) { 54 | if (NetworkUtil.isNetConnect(context)) { 55 | MainActivity.getInstance().switchAlbumInfoFragment(item.getAlbum_id()); 56 | } else { 57 | Toasty.error(context, "网络无连接,请检查您的网络设置").show(); 58 | } 59 | } 60 | }); 61 | 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /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/fragment_artist_hot_song.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 19 | 20 | 29 | 30 | 39 | 40 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/processors/MaskPostprocessor.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.processors; 2 | 3 | /** 4 | * Copyright (C) 2015 Wasabeef 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | 19 | import android.content.Context; 20 | import android.graphics.Bitmap; 21 | import android.graphics.Canvas; 22 | import android.graphics.Paint; 23 | import android.graphics.PorterDuff; 24 | import android.graphics.PorterDuffXfermode; 25 | import android.graphics.drawable.Drawable; 26 | 27 | import com.facebook.cache.common.CacheKey; 28 | import com.facebook.cache.common.SimpleCacheKey; 29 | import com.facebook.imagepipeline.request.BasePostprocessor; 30 | import com.yjl.funk.imageloader.processors.internal.Utils; 31 | 32 | 33 | public class MaskPostprocessor extends BasePostprocessor { 34 | 35 | private static Paint paint = new Paint(); 36 | private Context context; 37 | private int maskId; 38 | 39 | static { 40 | paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); 41 | } 42 | 43 | /** 44 | * @param maskId If you change the mask file, please also rename the mask file, or Glide will get 45 | * the cache with the old mask. Because getId() return the same values if using the 46 | * same make file name. If you have a good idea please tell us, thanks. 47 | */ 48 | public MaskPostprocessor(Context context, int maskId) { 49 | this.context = context.getApplicationContext(); 50 | this.maskId = maskId; 51 | } 52 | 53 | @Override public void process(Bitmap dest, Bitmap source) { 54 | 55 | Bitmap result = 56 | Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888); 57 | 58 | Drawable mask = Utils.getMaskDrawable(context, maskId); 59 | 60 | Canvas canvas = new Canvas(result); 61 | mask.setBounds(0, 0, source.getWidth(), source.getHeight()); 62 | mask.draw(canvas); 63 | canvas.drawBitmap(source, 0, 0, paint); 64 | 65 | super.process(dest, result); 66 | } 67 | 68 | @Override public String getName() { 69 | return getClass().getSimpleName(); 70 | } 71 | 72 | @Override public CacheKey getPostprocessorCacheKey() { 73 | return new SimpleCacheKey("mask=" + context.getResources().getResourceEntryName(maskId)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_album_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 16 | 17 | 18 | 23 | 24 | 30 | 31 | 36 | 37 | 47 | 48 | 54 | 55 | 62 | 63 | 64 | 65 | 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk; 2 | 3 | import android.app.ActivityManager; 4 | import android.app.Application; 5 | import android.content.Context; 6 | 7 | import com.facebook.drawee.backends.pipeline.Fresco; 8 | import com.facebook.imagepipeline.core.ImagePipelineConfig; 9 | import com.yjl.funk.audiocache.HttpProxyCacheServer; 10 | import com.yjl.funk.imageloader.frescohelper.FrescoHelper; 11 | import com.yjl.funk.imageloader.frescohelper.MyBitmapMemoryCacheParamsSupplier; 12 | import com.yjl.funk.network.HttpInterceptor; 13 | import com.yjl.funk.utils.FileUtils; 14 | import com.zhy.http.okhttp.OkHttpUtils; 15 | 16 | import java.util.concurrent.TimeUnit; 17 | 18 | import okhttp3.OkHttpClient; 19 | 20 | 21 | /** 22 | * project:KDB—seller 23 | * Created on 2017/5/2 0002. 24 | * author :yanjinlong 25 | */ 26 | 27 | public class MyApplication extends Application { 28 | 29 | private static MyApplication instance; 30 | private HttpProxyCacheServer proxy; 31 | 32 | public static HttpProxyCacheServer getProxy(Context context) { 33 | MyApplication app = (MyApplication) context.getApplicationContext(); 34 | return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy; 35 | } 36 | 37 | private HttpProxyCacheServer newProxy() { 38 | return new HttpProxyCacheServer.Builder(this) 39 | .maxCacheFilesCount(10) 40 | .cacheDirectory(FileUtils.getCacheDirFile()) 41 | .build(); 42 | } 43 | 44 | @Override 45 | public void onCreate() { 46 | super.onCreate(); 47 | if (instance == null) { 48 | synchronized (MyApplication.class) { 49 | if (instance == null) { 50 | instance= this; 51 | } 52 | } 53 | } 54 | initOkHttpUtils(); 55 | ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this) 56 | .setDownsampleEnabled(true) 57 | .setBitmapMemoryCacheParamsSupplier(new MyBitmapMemoryCacheParamsSupplier((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE))) 58 | .build(); 59 | Fresco.initialize(this,config); 60 | 61 | } 62 | public static MyApplication getInstance() { 63 | return instance; 64 | } 65 | @Override 66 | public void onTrimMemory(int level) { 67 | super.onTrimMemory(level); 68 | FrescoHelper.trimMemory(level); 69 | } 70 | 71 | 72 | @Override 73 | public void onLowMemory() { 74 | super.onLowMemory(); 75 | FrescoHelper.clearMemory(); 76 | } 77 | private void initOkHttpUtils() { 78 | OkHttpClient okHttpClient = new OkHttpClient.Builder() 79 | .connectTimeout(10, TimeUnit.SECONDS) 80 | .readTimeout(10, TimeUnit.SECONDS) 81 | .writeTimeout(10, TimeUnit.SECONDS) 82 | .addInterceptor(new HttpInterceptor()) 83 | .build(); 84 | OkHttpUtils.initClient(okHttpClient); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 17 | 27 | 31 | 35 | 45 | 51 | 55 | 59 | 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/widget/AlbumIntroDialog.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.widget; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.graphics.Point; 6 | import android.text.TextUtils; 7 | import android.view.Gravity; 8 | import android.view.View; 9 | import android.view.Window; 10 | import android.view.WindowManager; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import com.jakewharton.rxbinding.view.RxView; 15 | import com.yjl.funk.R; 16 | import com.yjl.funk.imageloader.frescohelper.FrescoHelper; 17 | import com.yjl.funk.imageloader.frescoview.FrescoImageView; 18 | import com.yjl.funk.imageloader.processors.BlurPostprocessor; 19 | import com.yjl.funk.model.AlbumInfo; 20 | 21 | import java.util.concurrent.TimeUnit; 22 | 23 | import butterknife.ButterKnife; 24 | import rx.functions.Action1; 25 | 26 | 27 | /** 28 | * Created by Administrator on 2017/11/8. 29 | */ 30 | 31 | public class AlbumIntroDialog extends Dialog { 32 | private Context context; 33 | private AlbumInfo info; 34 | private FrescoImageView ivBg,ivAlbum; 35 | private ImageView ivCLose; 36 | private TextView tv_name,tv_describe; 37 | public AlbumIntroDialog(Context context, AlbumInfo info) { 38 | this(context, R.style.Dialog_Fullscreen); 39 | this.context = context; 40 | this.info = info; 41 | initView(); 42 | } 43 | 44 | public AlbumIntroDialog(Context context, int themeResId) { 45 | super(context, themeResId); 46 | } 47 | 48 | @Override 49 | public void onBackPressed() { 50 | super.onBackPressed(); 51 | this.dismiss(); 52 | } 53 | public void initView(){ 54 | View view = View.inflate(context,R.layout.dialog_album_info,null); 55 | ivAlbum = ButterKnife.findById(view,R.id.iv_album_img); 56 | ivBg = ButterKnife.findById(view,R.id.iv_album_bg); 57 | tv_name = ButterKnife.findById(view,R.id.tv_album_name); 58 | tv_describe = ButterKnife.findById(view,R.id.tv_album_describe); 59 | ivCLose = ButterKnife.findById(view,R.id.iv_close); 60 | if(info!=null) { 61 | FrescoHelper.loadFrescoImageCircle(ivAlbum, info.getAlbumInfo().getPic_s500(), 0, false); 62 | FrescoHelper.loadFrescoImage(ivBg, info.getAlbumInfo().getPic_s500(), 0, false, new Point(720, 480), new BlurPostprocessor(context, 15)); 63 | tv_name.setText(info.getAlbumInfo().getTitle()); 64 | if(TextUtils.isEmpty(info.getAlbumInfo().getInfo())) 65 | tv_describe.setText("暂无简介"); 66 | else 67 | tv_describe.setText(info.getAlbumInfo().getInfo()); 68 | } 69 | RxView.clicks(ivCLose).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1() { 70 | @Override 71 | public void call(Void aVoid) { 72 | AlbumIntroDialog.this.dismiss(); 73 | } 74 | }); 75 | Window dialogWindow = this.getWindow(); 76 | WindowManager.LayoutParams lp = dialogWindow.getAttributes(); 77 | dialogWindow.setGravity(Gravity.CENTER); 78 | this.addContentView(view,lp); 79 | } 80 | 81 | 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/ui/adapter/OnlineMusicListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.LayoutRes; 5 | import android.support.v4.content.ContextCompat; 6 | import android.text.TextUtils; 7 | import android.view.View; 8 | import android.widget.TextView; 9 | 10 | import com.chad.library.adapter.base.BaseQuickAdapter; 11 | import com.chad.library.adapter.base.BaseViewHolder; 12 | import com.jakewharton.rxbinding.view.RxView; 13 | import com.yjl.funk.player.MusicClient; 14 | import com.yjl.funk.R; 15 | import com.yjl.funk.imageloader.frescohelper.FrescoHelper; 16 | import com.yjl.funk.imageloader.frescoview.FrescoImageView; 17 | import com.yjl.funk.model.MusicTrack; 18 | import com.yjl.funk.utils.DensityUtils; 19 | 20 | import java.util.List; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | import rx.functions.Action1; 24 | 25 | /** 26 | * Created by Administrator on 2017/11/7. 27 | */ 28 | 29 | public class OnlineMusicListAdapter extends BaseQuickAdapter { 30 | private Context context; 31 | private boolean is_rank, is_img;//是否显示排名 是否显示图片 32 | private List list; 33 | 34 | public OnlineMusicListAdapter(Context context, @LayoutRes int resId, List list, boolean is_rank, boolean is_img) { 35 | super(resId, list); 36 | this.context = context; 37 | this.is_rank = is_rank; 38 | this.is_img = is_img; 39 | this.list = list; 40 | } 41 | 42 | @Override 43 | protected void convert(final BaseViewHolder helper, MusicTrack item) { 44 | TextView rank = helper.getView(R.id.tv_rank); 45 | if (is_rank) { 46 | if (helper.getLayoutPosition() < 3) { 47 | rank.setTextColor(ContextCompat.getColor(context, R.color.colorAccent)); 48 | } else { 49 | rank.setTextColor(ContextCompat.getColor(context, R.color.text_gray)); 50 | } 51 | rank.setText(String.valueOf(helper.getLayoutPosition() + 1)); 52 | } else { 53 | rank.setVisibility(View.GONE); 54 | } 55 | helper.setText(R.id.tv_name, item.getTitle()); 56 | helper.setText(R.id.tv_describe, item.getAuthor() + " · " + item.getAlbum_title()); 57 | if (is_img) { 58 | String cover = ""; 59 | if(TextUtils.isEmpty(item.getPic_big())){ 60 | if(!TextUtils.isEmpty(item.getPic_small())) 61 | cover = item.getPic_small().split("\\@")[0]+"@s_1,w_500,h_500"; 62 | 63 | }else { 64 | cover = item.getPic_big(); 65 | } 66 | FrescoHelper.loadFrescoImage((FrescoImageView) helper.getView(R.id.iv_song),cover, R.drawable.default_load_cover_small, DensityUtils.dip2px(context, 2), false); 67 | }else 68 | helper.setVisible(R.id.iv_song, false); 69 | 70 | RxView.clicks(helper.itemView).throttleFirst(1, TimeUnit.SECONDS).subscribe(new Action1() { 71 | @Override 72 | public void call(Void aVoid) { 73 | MusicClient.setPlayListAndPlayAt(list, helper.getLayoutPosition()); 74 | } 75 | }); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/res/layout/layout_notification.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 26 | 27 | 36 | 37 | 46 | 47 | 48 | 52 | 53 | 61 | 62 | 70 | 71 | 79 | 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/file/Files.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache.file; 2 | 3 | 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | import java.util.Arrays; 8 | import java.util.Collections; 9 | import java.util.Comparator; 10 | import java.util.Date; 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | 14 | /** 15 | * Utils for work with files. 16 | * 17 | * @author Alexey Danilov (danikula@gmail.com). 18 | */ 19 | class Files { 20 | 21 | 22 | static void makeDir(File directory) throws IOException { 23 | if (directory.exists()) { 24 | if (!directory.isDirectory()) { 25 | throw new IOException("File " + directory + " is not directory!"); 26 | } 27 | } else { 28 | boolean isCreated = directory.mkdirs(); 29 | if (!isCreated) { 30 | throw new IOException(String.format("Directory %s can't be created", directory.getAbsolutePath())); 31 | } 32 | } 33 | } 34 | 35 | static List getLruListFiles(File directory) { 36 | List result = new LinkedList<>(); 37 | File[] files = directory.listFiles(); 38 | if (files != null) { 39 | result = Arrays.asList(files); 40 | Collections.sort(result, new LastModifiedComparator()); 41 | } 42 | return result; 43 | } 44 | 45 | static void setLastModifiedNow(File file) throws IOException { 46 | if (file.exists()) { 47 | long now = System.currentTimeMillis(); 48 | boolean modified = file.setLastModified(now); // on some devices (e.g. Nexus 5) doesn't work 49 | if (!modified) { 50 | modify(file); 51 | if (file.lastModified() < now) { 52 | // NOTE: apparently this is a known issue (see: http://stackoverflow.com/questions/6633748/file-lastmodified-is-never-what-was-set-with-file-setlastmodified) 53 | } 54 | } 55 | } 56 | } 57 | 58 | static void modify(File file) throws IOException { 59 | long size = file.length(); 60 | if (size == 0) { 61 | recreateZeroSizeFile(file); 62 | return; 63 | } 64 | 65 | RandomAccessFile accessFile = new RandomAccessFile(file, "rwd"); 66 | accessFile.seek(size - 1); 67 | byte lastByte = accessFile.readByte(); 68 | accessFile.seek(size - 1); 69 | accessFile.write(lastByte); 70 | accessFile.close(); 71 | } 72 | 73 | private static void recreateZeroSizeFile(File file) throws IOException { 74 | if (!file.delete() || !file.createNewFile()) { 75 | throw new IOException("Error recreate zero-size file " + file); 76 | } 77 | } 78 | 79 | private static final class LastModifiedComparator implements Comparator { 80 | 81 | @Override 82 | public int compare(File lhs, File rhs) { 83 | return compareLong(lhs.lastModified(), rhs.lastModified()); 84 | } 85 | 86 | private int compareLong(long first, long second) { 87 | return (first < second) ? -1 : ((first == second) ? 0 : 1); 88 | } 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/StorageUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import android.content.Context; 4 | import android.os.Environment; 5 | 6 | 7 | import java.io.File; 8 | 9 | import static android.os.Environment.MEDIA_MOUNTED; 10 | 11 | /** 12 | * Provides application storage paths 13 | *

14 | * See https://github.com/nostra13/Android-Universal-Image-Loader 15 | * 16 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com) 17 | * @since 1.0.0 18 | */ 19 | final class StorageUtils { 20 | 21 | private static final String INDIVIDUAL_DIR_NAME = "video-cache"; 22 | 23 | /** 24 | * Returns individual application cache directory (for only video caching from Proxy). Cache directory will be 25 | * created on SD card ("/Android/data/[app_package_name]/cache/video-cache") if card is mounted . 26 | * Else - Android defines cache directory on device's file system. 27 | * 28 | * @param context Application context 29 | * @return Cache {@link File directory} 30 | */ 31 | public static File getIndividualCacheDirectory(Context context) { 32 | File cacheDir = getCacheDirectory(context, true); 33 | return new File(cacheDir, INDIVIDUAL_DIR_NAME); 34 | } 35 | 36 | /** 37 | * Returns application cache directory. Cache directory will be created on SD card 38 | * ("/Android/data/[app_package_name]/cache") (if card is mounted and app has appropriate permission) or 39 | * on device's file system depending incoming parameters. 40 | * 41 | * @param context Application context 42 | * @param preferExternal Whether prefer external location for cache 43 | * @return Cache {@link File directory}.
44 | * NOTE: Can be null in some unpredictable cases (if SD card is unmounted and 45 | * {@link Context#getCacheDir() Context.getCacheDir()} returns null). 46 | */ 47 | private static File getCacheDirectory(Context context, boolean preferExternal) { 48 | File appCacheDir = null; 49 | String externalStorageState; 50 | try { 51 | externalStorageState = Environment.getExternalStorageState(); 52 | } catch (NullPointerException e) { // (sh)it happens 53 | externalStorageState = ""; 54 | } 55 | if (preferExternal && MEDIA_MOUNTED.equals(externalStorageState)) { 56 | appCacheDir = getExternalCacheDir(context); 57 | } 58 | if (appCacheDir == null) { 59 | appCacheDir = context.getCacheDir(); 60 | } 61 | if (appCacheDir == null) { 62 | String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/"; 63 | appCacheDir = new File(cacheDirPath); 64 | } 65 | return appCacheDir; 66 | } 67 | 68 | private static File getExternalCacheDir(Context context) { 69 | File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data"); 70 | File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache"); 71 | if (!appCacheDir.exists()) { 72 | if (!appCacheDir.mkdirs()) { 73 | 74 | return null; 75 | } 76 | } 77 | return appCacheDir; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/service/ServiceStub.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.service; 2 | 3 | import android.os.RemoteException; 4 | 5 | import com.yjl.funk.IFunkService; 6 | import com.yjl.funk.model.MusicTrack; 7 | 8 | import java.lang.ref.WeakReference; 9 | import java.util.List; 10 | 11 | public class ServiceStub extends IFunkService.Stub { 12 | 13 | private final WeakReference mService; 14 | 15 | public ServiceStub(final FunkMusicService service) { 16 | mService = new WeakReference(service); 17 | } 18 | 19 | 20 | @Override 21 | public void play(int position) throws RemoteException { 22 | mService.get().play(position); 23 | } 24 | 25 | @Override 26 | public void setPlayListAndPlay(List tracks, int position) throws RemoteException { 27 | mService.get().setPlayListAndPlayAt(tracks,position); 28 | } 29 | 30 | @Override 31 | public MusicTrack getCurrentTrack() throws RemoteException { 32 | return mService.get().getCurrentMusicTrack(); 33 | } 34 | 35 | @Override 36 | public List getPlayList() throws RemoteException { 37 | return mService.get().getPlayList(); 38 | } 39 | 40 | @Override 41 | public void setPlayMode(int mode) throws RemoteException { 42 | mService.get().setPlayMode(mode); 43 | } 44 | 45 | @Override 46 | public int getPlayMode() throws RemoteException { 47 | return mService.get().getPlayMode(); 48 | } 49 | 50 | @Override 51 | public int getNowPlayingPosition() throws RemoteException { 52 | return mService.get().getCurrentPlayListPosition(); 53 | } 54 | 55 | @Override 56 | public boolean isPlaying() throws RemoteException { 57 | return mService.get().isPlaying(); 58 | } 59 | 60 | @Override 61 | public boolean isPreparing() throws RemoteException { 62 | return mService.get().isPreparing(); 63 | } 64 | 65 | @Override 66 | public boolean isPausing() throws RemoteException { 67 | return mService.get().isPausing(); 68 | } 69 | 70 | @Override 71 | public boolean isIdle() throws RemoteException { 72 | return mService.get().isIDLE(); 73 | } 74 | 75 | @Override 76 | public int duration() throws RemoteException { 77 | return mService.get().duration(); 78 | } 79 | 80 | @Override 81 | public int position() throws RemoteException { 82 | return mService.get().position(); 83 | } 84 | 85 | @Override 86 | public int secondPosition() throws RemoteException { 87 | return mService.get().secondPosition(); 88 | } 89 | 90 | @Override 91 | public void playOrPause() throws RemoteException { 92 | mService.get().playOrPause(); 93 | } 94 | 95 | @Override 96 | public void next() throws RemoteException { 97 | mService.get().next(); 98 | } 99 | 100 | @Override 101 | public void prev() throws RemoteException { 102 | mService.get().prev(); 103 | } 104 | 105 | @Override 106 | public void seekTo(int progress) throws RemoteException { 107 | mService.get().seek(progress); 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_special_music.xml: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 19 | 20 | 24 | 25 | 30 | 31 | 49 | 50 | 51 | 65 | 66 | 78 | 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/imageloader/frescoview/FrescoController.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.imageloader.frescoview; 2 | 3 | import com.facebook.drawee.controller.ControllerListener; 4 | import com.facebook.drawee.drawable.ScalingUtils; 5 | import com.facebook.drawee.generic.RoundingParams; 6 | import com.facebook.imagepipeline.request.Postprocessor; 7 | 8 | /** 9 | * Created by Linhh on 16/3/2. 10 | */ 11 | public interface FrescoController { 12 | 13 | public final static String HTTP_PERFIX = "http://"; 14 | public final static String HTTPS_PERFIX = "https://"; 15 | public final static String FILE_PERFIX = "file://"; 16 | 17 | /** 18 | * 加载网络图片 19 | * @param lowUrl 低分辨率图片 20 | * @param url 网络图片 21 | * @param defaultResID 默认图 22 | */ 23 | public void loadView(String lowUrl, String url, int defaultResID); 24 | 25 | /** 26 | * 加载网络图片 27 | * @param url 网络图片 28 | * @param defaultResID 默认图 29 | */ 30 | public void loadView(String url, int defaultResID); 31 | 32 | /** 33 | * 加载本地图片 34 | * @param path 图片路劲 35 | * @param defaultRes 默认图 36 | */ 37 | public void loadLocalImage(String path, int defaultRes); 38 | 39 | /** 40 | * 将该Fresco处理为圆形 41 | */ 42 | public void asCircle(); 43 | 44 | /** 45 | * 用一种颜色来遮挡View以实现圆形,在一些内存较低的机器上推荐使用 46 | * @param overlay_color 47 | */ 48 | public void setCircle(int overlay_color); 49 | 50 | /** 51 | * 设置圆角 52 | * @param radius 53 | */ 54 | public void setCornerRadius(float radius); 55 | 56 | /** 57 | * 用一种颜色来遮挡View以实现圆角,在一些内存较低的机器上推荐使用 58 | * @param radius 59 | * @param overlay_color 60 | */ 61 | public void setCornerRadius(float radius, int overlay_color); 62 | 63 | /** 64 | * 设置边框 65 | * @param color 66 | * @param width 67 | */ 68 | public void setBorder(int color, float width); 69 | 70 | /** 71 | * 清除所使用的RoundingParams 72 | */ 73 | public void clearRoundingParams(); 74 | 75 | /** 76 | * 设置RoundingParams 77 | * @param roundingParmas 78 | */ 79 | public void setRoundingParmas(RoundingParams roundingParmas); 80 | 81 | /** 82 | * 设置下载监听器 83 | * @param controllerListener 84 | */ 85 | public void setControllerListener(ControllerListener controllerListener); 86 | 87 | 88 | /** 89 | * 设置后处理 90 | * @param postProcessor 91 | */ 92 | public void setPostProcessor(Postprocessor postProcessor); 93 | 94 | 95 | /** 96 | * 是否开启动画 97 | * @param anim 98 | */ 99 | public void setAnim(boolean anim); 100 | 101 | /** 102 | * 是否可以点击重试 103 | * @param tapToRetryEnabled 104 | */ 105 | public void setTapToRetryEnabled(boolean tapToRetryEnabled); 106 | 107 | /** 108 | * 是否自动旋转 109 | * @param autoRotateEnabled 110 | */ 111 | public void setAutoRotateEnabled(boolean autoRotateEnabled); 112 | 113 | /** 114 | * 设置图片缩放type 115 | * @param scaleType 116 | */ 117 | public void setActualImageScaleType(ScalingUtils.ScaleType scaleType); 118 | 119 | /** 120 | * 设置图片切换动时间 121 | * @param time 122 | * */ 123 | public void setFadeTime(int time); 124 | 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/audiocache/ProxyCacheUtils.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.audiocache; 2 | 3 | import android.text.TextUtils; 4 | import android.webkit.MimeTypeMap; 5 | 6 | import java.io.Closeable; 7 | import java.io.IOException; 8 | import java.io.UnsupportedEncodingException; 9 | import java.net.URLDecoder; 10 | import java.net.URLEncoder; 11 | import java.security.MessageDigest; 12 | import java.security.NoSuchAlgorithmException; 13 | import java.util.Arrays; 14 | 15 | import static com.yjl.funk.audiocache.Preconditions.checkArgument; 16 | import static com.yjl.funk.audiocache.Preconditions.checkNotNull; 17 | 18 | 19 | /** 20 | * Just simple utils. 21 | * 22 | * @author Alexey Danilov (danikula@gmail.com). 23 | */ 24 | public class ProxyCacheUtils { 25 | 26 | static final int DEFAULT_BUFFER_SIZE = 8 * 1024; 27 | static final int MAX_ARRAY_PREVIEW = 16; 28 | 29 | static String getSupposablyMime(String url) { 30 | MimeTypeMap mimes = MimeTypeMap.getSingleton(); 31 | String extension = MimeTypeMap.getFileExtensionFromUrl(url); 32 | return TextUtils.isEmpty(extension) ? null : mimes.getMimeTypeFromExtension(extension); 33 | } 34 | 35 | static void assertBuffer(byte[] buffer, long offset, int length) { 36 | checkNotNull(buffer, "Buffer must be not null!"); 37 | checkArgument(offset >= 0, "Data offset must be positive!"); 38 | checkArgument(length >= 0 && length <= buffer.length, "Length must be in range [0..buffer.length]"); 39 | } 40 | 41 | static String preview(byte[] data, int length) { 42 | int previewLength = Math.min(MAX_ARRAY_PREVIEW, Math.max(length, 0)); 43 | byte[] dataRange = Arrays.copyOfRange(data, 0, previewLength); 44 | String preview = Arrays.toString(dataRange); 45 | if (previewLength < length) { 46 | preview = preview.substring(0, preview.length() - 1) + ", ...]"; 47 | } 48 | return preview; 49 | } 50 | 51 | static String encode(String url) { 52 | try { 53 | return URLEncoder.encode(url, "utf-8"); 54 | } catch (UnsupportedEncodingException e) { 55 | throw new RuntimeException("Error encoding url", e); 56 | } 57 | } 58 | 59 | static String decode(String url) { 60 | try { 61 | return URLDecoder.decode(url, "utf-8"); 62 | } catch (UnsupportedEncodingException e) { 63 | throw new RuntimeException("Error decoding url", e); 64 | } 65 | } 66 | 67 | static void close(Closeable closeable) { 68 | if (closeable != null) { 69 | try { 70 | closeable.close(); 71 | } catch (IOException e) { 72 | } 73 | } 74 | } 75 | 76 | public static String computeMD5(String string) { 77 | try { 78 | MessageDigest messageDigest = MessageDigest.getInstance("MD5"); 79 | byte[] digestBytes = messageDigest.digest(string.getBytes()); 80 | return bytesToHexString(digestBytes); 81 | } catch (NoSuchAlgorithmException e) { 82 | throw new IllegalStateException(e); 83 | } 84 | } 85 | 86 | private static String bytesToHexString(byte[] bytes) { 87 | StringBuffer sb = new StringBuffer(); 88 | for (byte b : bytes) { 89 | sb.append(String.format("%02x", b)); 90 | } 91 | return sb.toString(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/com/yjl/funk/handler/MusicPlayerHandler.java: -------------------------------------------------------------------------------- 1 | package com.yjl.funk.handler; 2 | 3 | import android.media.AudioManager; 4 | import android.media.MediaPlayer; 5 | import android.os.Handler; 6 | import android.os.Looper; 7 | import android.os.Message; 8 | 9 | import com.yjl.funk.service.FunkMusicService; 10 | 11 | import java.lang.ref.WeakReference; 12 | 13 | import static com.yjl.funk.player.Constants.FADEDOWN; 14 | import static com.yjl.funk.player.Constants.FADEUP; 15 | import static com.yjl.funk.player.Constants.FOCUSCHANGE; 16 | 17 | /** 18 | * MediaPLayer 控制Handler 19 | **/ 20 | public class MusicPlayerHandler extends Handler { 21 | private final WeakReference mService; 22 | private float mCurrentVolume = 1.0f; 23 | private MediaPlayer mPlayer; 24 | 25 | public MusicPlayerHandler(final FunkMusicService service, MediaPlayer player, final Looper looper) { 26 | super(looper); 27 | mService = new WeakReference(service); 28 | this.mPlayer = player; 29 | } 30 | 31 | 32 | @Override 33 | public void handleMessage(final Message msg) { 34 | final FunkMusicService service = mService.get(); 35 | if (service == null) { 36 | return; 37 | } 38 | synchronized (service) { 39 | switch (msg.what) { 40 | case FADEDOWN: 41 | mCurrentVolume -= .05f; 42 | if (mCurrentVolume > .2f) { 43 | sendEmptyMessageDelayed(FADEDOWN, 10); 44 | } else { 45 | mCurrentVolume = .2f; 46 | } 47 | mPlayer.setVolume(mCurrentVolume,mCurrentVolume); 48 | break; 49 | case FADEUP: 50 | mCurrentVolume += .01f; 51 | if (mCurrentVolume < 1.0f) { 52 | sendEmptyMessageDelayed(FADEUP, 10); 53 | } else { 54 | mCurrentVolume = 1.0f; 55 | } 56 | mPlayer.setVolume(mCurrentVolume,mCurrentVolume); 57 | break; 58 | case FOCUSCHANGE: 59 | switch (msg.arg1) { 60 | case AudioManager.AUDIOFOCUS_LOSS: 61 | case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 62 | service.pause(); 63 | break; 64 | case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 65 | removeMessages(FADEUP); 66 | sendEmptyMessage(FADEDOWN); 67 | break; 68 | case AudioManager.AUDIOFOCUS_GAIN: 69 | if (!service.isPlaying()) { 70 | mCurrentVolume = 0f; 71 | service.mPlayer.setVolume(mCurrentVolume,mCurrentVolume); 72 | service.start(); 73 | } else { 74 | removeMessages(FADEDOWN); 75 | sendEmptyMessage(FADEUP); 76 | } 77 | break; 78 | } 79 | break; 80 | default: 81 | break; 82 | } 83 | } 84 | } 85 | } --------------------------------------------------------------------------------