Full Code of naman14/Timber for AI

master b53a7d54682e cached
320 files
1.3 MB
301.2k tokens
1896 symbols
1 requests
Download .txt
Showing preview only (1,433K chars total). Download the full file or copy to clipboard to get everything.
Repository: naman14/Timber
Branch: master
Commit: b53a7d54682e
Files: 320
Total size: 1.3 MB

Directory structure:
gitextract_5h1zqhrq/

├── .gitignore
├── .travis.yml
├── Changelog.md
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── naman14/
│       │               └── timber/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── aidl/
│           │   └── com/
│           │       └── naman14/
│           │           └── timber/
│           │               ├── ITimberService.aidl
│           │               └── helpers/
│           │                   └── MusicPlaybackTrack.aidl
│           ├── java/
│           │   └── com/
│           │       └── naman14/
│           │           └── timber/
│           │               ├── MusicPlayer.java
│           │               ├── MusicService.java
│           │               ├── TimberApp.java
│           │               ├── WearBrowserService.java
│           │               ├── activities/
│           │               │   ├── BaseActivity.java
│           │               │   ├── BaseThemedActivity.java
│           │               │   ├── DonateActivity.java
│           │               │   ├── MainActivity.java
│           │               │   ├── NowPlayingActivity.java
│           │               │   ├── PlaylistDetailActivity.java
│           │               │   ├── SearchActivity.java
│           │               │   └── SettingsActivity.java
│           │               ├── adapters/
│           │               │   ├── AlbumAdapter.java
│           │               │   ├── AlbumSongsAdapter.java
│           │               │   ├── ArtistAdapter.java
│           │               │   ├── ArtistAlbumAdapter.java
│           │               │   ├── ArtistSongAdapter.java
│           │               │   ├── BaseQueueAdapter.java
│           │               │   ├── BaseSongAdapter.java
│           │               │   ├── FolderAdapter.java
│           │               │   ├── PlayingQueueAdapter.java
│           │               │   ├── PlaylistAdapter.java
│           │               │   ├── SearchAdapter.java
│           │               │   ├── SlidingQueueAdapter.java
│           │               │   └── SongsListAdapter.java
│           │               ├── cast/
│           │               │   ├── CastOptionsProvider.java
│           │               │   ├── ExpandedControlsActivity.java
│           │               │   ├── SimpleSessionManagerListener.java
│           │               │   ├── TimberCastHelper.java
│           │               │   └── WebServer.java
│           │               ├── dataloaders/
│           │               │   ├── AlbumLoader.java
│           │               │   ├── AlbumSongLoader.java
│           │               │   ├── ArtistAlbumLoader.java
│           │               │   ├── ArtistLoader.java
│           │               │   ├── ArtistSongLoader.java
│           │               │   ├── FolderLoader.java
│           │               │   ├── LastAddedLoader.java
│           │               │   ├── NowPlayingCursor.java
│           │               │   ├── PlaylistLoader.java
│           │               │   ├── PlaylistSongLoader.java
│           │               │   ├── QueueLoader.java
│           │               │   ├── SongLoader.java
│           │               │   ├── SortedCursor.java
│           │               │   └── TopTracksLoader.java
│           │               ├── dialogs/
│           │               │   ├── AddPlaylistDialog.java
│           │               │   ├── CreatePlaylistDialog.java
│           │               │   ├── LastFmLoginDialog.java
│           │               │   └── StorageSelectDialog.java
│           │               ├── fragments/
│           │               │   ├── AlbumDetailFragment.java
│           │               │   ├── AlbumFragment.java
│           │               │   ├── ArtistBioFragment.java
│           │               │   ├── ArtistDetailFragment.java
│           │               │   ├── ArtistFragment.java
│           │               │   ├── ArtistMusicFragment.java
│           │               │   ├── FoldersFragment.java
│           │               │   ├── MainFragment.java
│           │               │   ├── PlaylistFragment.java
│           │               │   ├── QueueFragment.java
│           │               │   ├── SettingsFragment.java
│           │               │   ├── SimilarArtistFragment.java
│           │               │   └── SongsFragment.java
│           │               ├── helpers/
│           │               │   ├── MediaButtonIntentReceiver.java
│           │               │   └── MusicPlaybackTrack.java
│           │               ├── lastfmapi/
│           │               │   ├── LastFmClient.java
│           │               │   ├── LastFmRestService.java
│           │               │   ├── LastFmUserRestService.java
│           │               │   ├── RestServiceFactory.java
│           │               │   ├── callbacks/
│           │               │   │   ├── AlbumInfoListener.java
│           │               │   │   ├── ArtistInfoListener.java
│           │               │   │   └── UserListener.java
│           │               │   └── models/
│           │               │       ├── AlbumBio.java
│           │               │       ├── AlbumInfo.java
│           │               │       ├── AlbumQuery.java
│           │               │       ├── AlbumTracks.java
│           │               │       ├── ArtistBio.java
│           │               │       ├── ArtistInfo.java
│           │               │       ├── ArtistQuery.java
│           │               │       ├── ArtistTag.java
│           │               │       ├── Artwork.java
│           │               │       ├── LastfmAlbum.java
│           │               │       ├── LastfmArtist.java
│           │               │       ├── LastfmUserSession.java
│           │               │       ├── ScrobbleInfo.java
│           │               │       ├── ScrobbleQuery.java
│           │               │       ├── UserLoginInfo.java
│           │               │       └── UserLoginQuery.java
│           │               ├── listeners/
│           │               │   ├── MusicStateListener.java
│           │               │   └── SimplelTransitionListener.java
│           │               ├── models/
│           │               │   ├── Album.java
│           │               │   ├── Artist.java
│           │               │   ├── Playlist.java
│           │               │   └── Song.java
│           │               ├── nowplaying/
│           │               │   ├── BaseNowplayingFragment.java
│           │               │   ├── Timber1.java
│           │               │   ├── Timber2.java
│           │               │   ├── Timber3.java
│           │               │   ├── Timber4.java
│           │               │   ├── Timber5.java
│           │               │   └── Timber6.java
│           │               ├── permissions/
│           │               │   ├── Nammu.java
│           │               │   ├── PermissionCallback.java
│           │               │   ├── PermissionListener.java
│           │               │   └── PermissionRequest.java
│           │               ├── provider/
│           │               │   ├── MusicDB.java
│           │               │   ├── MusicPlaybackState.java
│           │               │   ├── RecentStore.java
│           │               │   ├── SearchHistory.java
│           │               │   └── SongPlayCount.java
│           │               ├── slidinguppanel/
│           │               │   ├── SlidingUpPanelLayout.java
│           │               │   └── ViewDragHelper.java
│           │               ├── subfragments/
│           │               │   ├── ArtistTagFragment.java
│           │               │   ├── LyricsFragment.java
│           │               │   ├── PlaylistPagerFragment.java
│           │               │   ├── QuickControlsFragment.java
│           │               │   ├── StyleSelectorFragment.java
│           │               │   └── SubStyleSelectorFragment.java
│           │               ├── timely/
│           │               │   ├── TimelyView.java
│           │               │   ├── animation/
│           │               │   │   └── TimelyEvaluator.java
│           │               │   └── model/
│           │               │       ├── NumberUtils.java
│           │               │       ├── core/
│           │               │       │   └── Figure.java
│           │               │       └── number/
│           │               │           ├── Eight.java
│           │               │           ├── Five.java
│           │               │           ├── Four.java
│           │               │           ├── Nine.java
│           │               │           ├── Null.java
│           │               │           ├── One.java
│           │               │           ├── Seven.java
│           │               │           ├── Six.java
│           │               │           ├── Three.java
│           │               │           ├── Two.java
│           │               │           └── Zero.java
│           │               ├── transition/
│           │               │   └── PlayTransition.java
│           │               ├── utils/
│           │               │   ├── ATEUtils.java
│           │               │   ├── Constants.java
│           │               │   ├── FabAnimationUtils.java
│           │               │   ├── Helpers.java
│           │               │   ├── ImageUtils.java
│           │               │   ├── LyricsExtractor.java
│           │               │   ├── LyricsLoader.java
│           │               │   ├── NavigationUtils.java
│           │               │   ├── PreferencesUtility.java
│           │               │   ├── SlideTrackSwitcher.java
│           │               │   ├── SortOrder.java
│           │               │   └── TimberUtils.java
│           │               └── widgets/
│           │                   ├── BaseRecyclerView.java
│           │                   ├── BubbleTextGetter.java
│           │                   ├── CircleImageView.java
│           │                   ├── CircularSeekBar.java
│           │                   ├── DividerItemDecoration.java
│           │                   ├── DragSortRecycler.java
│           │                   ├── FastScroller.java
│           │                   ├── MultiViewPager.java
│           │                   ├── MusicVisualizer.java
│           │                   ├── PlayPauseButton.java
│           │                   ├── PlayPauseDrawable.java
│           │                   ├── PopupImageView.java
│           │                   ├── SquareImageView.java
│           │                   ├── TextDrawable.java
│           │                   ├── ThemedPreferenceCategory.java
│           │                   └── desktop/
│           │                       ├── BaseWidget.java
│           │                       ├── SmallWidget.java
│           │                       ├── StandardWidget.java
│           │                       └── WhiteWidget.java
│           └── res/
│               ├── anim/
│               │   ├── activity_fade_in.xml
│               │   ├── activity_fade_out.xml
│               │   ├── design_fab_out.xml
│               │   ├── scale.xml
│               │   ├── slide_in_from_bottom.xml
│               │   ├── slide_in_from_left.xml
│               │   ├── slide_in_from_right.xml
│               │   ├── slide_out_to_bottom.xml
│               │   ├── slide_out_to_left.xml
│               │   └── slide_out_to_right.xml
│               ├── color/
│               │   ├── state_selector_black.xml
│               │   ├── state_selector_dark.xml
│               │   └── state_selector_light.xml
│               ├── drawable/
│               │   ├── bg_gradient.xml
│               │   ├── ic_file_music_dark.xml
│               │   ├── ic_folder_open_black_24dp.xml
│               │   ├── ic_folder_open_white_24dp.xml
│               │   ├── ic_folder_parent_dark.xml
│               │   ├── ic_menu.xml
│               │   ├── ic_timer_wait.xml
│               │   ├── item_divider_black.xml
│               │   ├── item_divider_white.xml
│               │   ├── progress_drawable.xml
│               │   ├── progress_drawable_black.xml
│               │   ├── progress_drawable_dark.xml
│               │   ├── progress_drawable_withbackground.xml
│               │   ├── progress_drawable_withbackground_black.xml
│               │   ├── progress_drawable_withbackground_dark.xml
│               │   ├── recyclerview_fastscroller_bubble.xml
│               │   ├── recyclerview_fastscroller_handle.xml
│               │   └── selectable_item_background.xml
│               ├── drawable-xhdpi/
│               │   ├── above_shadow.xml
│               │   └── below_shadow.xml
│               ├── layout/
│               │   ├── activity_donate.xml
│               │   ├── activity_main.xml
│               │   ├── activity_nowplaying.xml
│               │   ├── activity_playlist_detail.xml
│               │   ├── activity_search.xml
│               │   ├── activity_settings.xml
│               │   ├── artist_detail_albums_header.xml
│               │   ├── bottom_nowplaying_card.xml
│               │   ├── dialog_lastfm_login.xml
│               │   ├── empty_view.xml
│               │   ├── fragment_album_detail.xml
│               │   ├── fragment_artist_bio.xml
│               │   ├── fragment_artist_detail.xml
│               │   ├── fragment_artist_music.xml
│               │   ├── fragment_cast_mini_controller.xml
│               │   ├── fragment_folders.xml
│               │   ├── fragment_lyrics.xml
│               │   ├── fragment_main.xml
│               │   ├── fragment_playback_controls.xml
│               │   ├── fragment_playlist.xml
│               │   ├── fragment_playlist_pager.xml
│               │   ├── fragment_queue.xml
│               │   ├── fragment_recyclerview.xml
│               │   ├── fragment_similar_artists.xml
│               │   ├── fragment_style_selector.xml
│               │   ├── fragment_style_selector_pager.xml
│               │   ├── fragment_timber1.xml
│               │   ├── fragment_timber2.xml
│               │   ├── fragment_timber3.xml
│               │   ├── fragment_timber4.xml
│               │   ├── fragment_timber5.xml
│               │   ├── fragment_timber6.xml
│               │   ├── include_list_viewpager.xml
│               │   ├── item_album_grid.xml
│               │   ├── item_album_list.xml
│               │   ├── item_album_search.xml
│               │   ├── item_album_song.xml
│               │   ├── item_artist.xml
│               │   ├── item_artist_album.xml
│               │   ├── item_artist_grid.xml
│               │   ├── item_artist_song.xml
│               │   ├── item_donate_product.xml
│               │   ├── item_folder_list.xml
│               │   ├── item_playing_queue.xml
│               │   ├── item_song.xml
│               │   ├── item_song_playlist.xml
│               │   ├── item_song_sliding_queue.xml
│               │   ├── item_song_timber1.xml
│               │   ├── layout_artist_tag.xml
│               │   ├── layout_dummy_header_artist.xml
│               │   ├── nav_header.xml
│               │   ├── recyclerview_fastscroller.xml
│               │   ├── search_section_header.xml
│               │   ├── song_elapsedtime.xml
│               │   ├── widget_small.xml
│               │   ├── widget_standard.xml
│               │   └── widget_white.xml
│               ├── menu/
│               │   ├── album_detail.xml
│               │   ├── album_sort_by.xml
│               │   ├── artist_detail.xml
│               │   ├── artist_sort_by.xml
│               │   ├── drawer_view.xml
│               │   ├── menu_cast.xml
│               │   ├── menu_expanded_controller.xml
│               │   ├── menu_folders.xml
│               │   ├── menu_main.xml
│               │   ├── menu_playlist.xml
│               │   ├── menu_playlist_detail.xml
│               │   ├── menu_search.xml
│               │   ├── menu_show_as.xml
│               │   ├── now_playing.xml
│               │   ├── popup_playing_queue.xml
│               │   ├── popup_song.xml
│               │   └── song_sort_by.xml
│               ├── transition/
│               │   ├── image_transform.xml
│               │   └── play_transition.xml
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── plurals.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-da/
│               │   └── strings.xml
│               ├── values-de/
│               │   └── strings.xml
│               ├── values-es/
│               │   └── strings.xml
│               ├── values-fr/
│               │   └── strings.xml
│               ├── values-id/
│               │   └── strings.xml
│               ├── values-it/
│               │   └── strings.xml
│               ├── values-ko/
│               │   └── strings.xml
│               ├── values-nb-rNO/
│               │   └── strings.xml
│               ├── values-pt/
│               │   └── strings.xml
│               ├── values-ru/
│               │   └── strings.xml
│               ├── values-tr/
│               │   └── strings.xml
│               ├── values-v19/
│               │   └── styles.xml
│               ├── values-v21/
│               │   ├── dimens.xml
│               │   └── styles.xml
│               ├── values-w820dp/
│               │   └── dimens.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   ├── preferences.xml
│                   ├── widget_small.xml
│                   ├── widget_standard.xml
│                   └── widget_white.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── mock/
│   ├── mock-google-services.json
│   └── mock-secret.xml
├── mock.gradle
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
.gradle
/local.properties
.idea
.DS_Store
/build
/captures
/*.iml

/app/app-release.apk
app/app.iml
app/manifest-merger-release-report.txt

secret.xml
google-services.json


================================================
FILE: .travis.yml
================================================
language: android
jdk: oraclejdk8

branches:
  only:
    - master

script: "./gradlew clean assembleDebug"

android:
  components:
      - platform-tools
      - tools
      - build-tools-28.0.3
      - android-28
      - extra-android-m2repository


================================================
FILE: Changelog.md
================================================
#Changelog

v0.21b-

* Add Homescreen widget
* View playlists in list, grid and default
* Delete playlists, clear auto playlists and hide auto playlists
* Remove songs from playlists, reorder playlists
* Delete songs from device

v0.14b-

* Added Theme engine
* Performance improvements
* Many bugs fixed

v0.13b-

* Create playlists and add songs to playlists
* Go to artist, album, add to queue, play next in song popup menu
* Pause music playback when headphones removed
* Fixed equalizer not working
* Fixed track numbers being wrong
* Bluetooth controls
* Show song duration in Timber3 now playing style
* Added Chinese,French,German and Italian translation
* Bug fixes and improvements

v0.122b-
* Fix crash in search activity
* Fix one time crash in marshmallow after allowing permission
* Added albums view options(list,grid)

v0.12b-
* Fix crash in artist detail and search
* Add intent for equalizer
* Ability to sort songs, albums and artists according to year,duration,track,number of songs, a-z, z-a etc


v0.11b-
* Fix crash on asynctask onpostexecute
* Fix crash on onTouchEvent in NavigationView
* Updated more material launcher and notification icon
* Reduced Apk size, enabled Proguard
* Added option to choose default start page
* Added option to remember the last page opened
* Fixed blurred albumart not changing if albumart not available

v0.1b
* Initial Release


================================================
FILE: README.md
================================================
# Timber
[![Build Status](https://travis-ci.org/naman14/Timber.svg?branch=master)](https://travis-ci.org/naman14/Timber)

Material Design Music Player

This project is no longer in active development. Please refer to [TimberX](https://github.com/naman14/TimberX) instead

<a href='https://play.google.com/store/apps/details?id=naman14.timber&pcampaignid=MKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png' height=90px/></a>

<a href='https://f-droid.org/repository/browse/?fdid=naman14.timber'><img alt='Get it on F-Droid' src='https://guardianproject.info/wp-content/uploads/2014/07/logo-fdroid.png' height=60px/></a>

## Screenshots

<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen2.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen3.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen7.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen8.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen9.jpg" width="330" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen10.jpg" width="330" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen1.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen5.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen12.jpg" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen4.png" width="360" height="640">
<img src="https://raw.githubusercontent.com/naman14/Timber/master/graphics/screen6.png" width="360" height="640">

## Features
- Material design
- Browse Songs, Albums, Artists
- Create and edit playlists
- 6 different now playing styles
- Homescreen widgets
- Browse device folders
- Dark theme and UI customisability
- Gestures for track switching
- LastFM scrobble
- Android Wear and Android Auto support
- Playing queue in notification (Xposed)
- Lyrics support
- Chromecast support

## Changelog

Changelog is available [here](https://github.com/naman14/Timber/blob/master/Changelog.md)

## Credits

* CyanogenMod's [Eleven Music Player](https://github.com/CyanogenMod/android_packages_apps_Eleven)
* [TimelyTextView](https://github.com/adnan-SM/TimelyTextView)
* [MultiViewPager](https://github.com/Pixplicity/MultiViewPager)
* [PlayPauseButton](https://github.com/recruit-lifestyle/PlayPauseButton)
* [CircularSeekBar](https://github.com/devadvance/circularseekbar)
* [Nammu](https://github.com/tajchert/Nammu)

# Donate
Paypal donation email-
namandwivedi14@gmail.com


## License

>(c) 2015 Naman Dwivedi 

>This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 

>This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 

>You should have received a copy of the GNU General Public License along with this app. If not, see <https://www.gnu.org/licenses/>.


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'

android {
    compileSdkVersion rootProject.compileSdkVersion

    defaultConfig {
        applicationId "naman14.timber"
        minSdkVersion rootProject.minSdkVersion
        targetSdkVersion rootProject.targetSdkVersion
        versionCode 22
        versionName "1.8"
        //renderscript support mode is not supported for 21+ with gradle version 2.0
        renderscriptTargetApi 16
        renderscriptSupportModeEnabled false
        multiDexEnabled true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
        debug {
            versionNameSuffix "-debug"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    lintOptions {
        disable 'MissingTranslation'
        disable 'ExtraTranslation'
    }

}

repositories {
    jcenter()
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "androidx.appcompat:appcompat:1.0.2"
    implementation "com.google.android.material:material:1.0.0"
    implementation "androidx.cardview:cardview:1.0.0"
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    implementation "androidx.palette:palette:1.0.0"
    implementation "androidx.percentlayout:percentlayout:1.0.0"
    implementation 'androidx.multidex:multidex:2.0.1'

    implementation "androidx.mediarouter:mediarouter:1.1.0"
    implementation 'com.google.android.gms:play-services-cast-framework:16.1.2'

    implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
    implementation 'net.steamcrafted:materialiconlib:1.1.4'
    implementation 'com.squareup.retrofit:retrofit:1.9.0'
    implementation 'com.squareup.okhttp:okhttp-urlconnection:2.3.0'
    implementation 'com.squareup.okhttp:okhttp:2.3.0'
    implementation 'com.google.code.gson:gson:2.3'
    implementation 'de.Maxr1998:track-selector-lib:1.2'

    implementation 'com.afollestad.material-dialogs:core:0.9.0.2'
    implementation 'com.afollestad.material-dialogs:commons:0.9.0.2'

    implementation('com.github.naman14:app-theme-engine:0.5.2@aar') {
        transitive = true
    }
    implementation 'com.google.firebase:firebase-crashlytics:17.2.2'

    implementation 'com.anjlab.android.iab.v3:library:1.0.+'
    implementation 'org.nanohttpd:nanohttpd:2.3.1'
}

apply from: '../mock.gradle'


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/naman/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}

# retrofit
-keep class com.squareup.okhttp.** { *; }
-keep class retrofit.** { *; }
-keep interface com.squareup.okhttp.** { *; }
-keep class com.naman14.timber.lastfmapi.models.** { *; }

-keep class android.support.v4.app.** { *; }
-keep interface android.support.v4.app.** { *; }
-keep class android.support.v7.app.** { *; }
-keep interface android.support.v7.app.** { *; }

-dontwarn com.squareup.okhttp.**
-dontwarn okio.**
-dontwarn retrofit.**
-dontwarn rx.**

-keepclasseswithmembers class * {
    @retrofit.http.* <methods>;
}

-keepattributes Exceptions
-keepattributes Signature
-keepattributes *Annotation*

#renderscript
-keep class android.support.v8.renderscript.** { *; }

#searchview
-keep class android.support.v7.widget.SearchView { *; }


================================================
FILE: app/src/androidTest/java/com/naman14/timber/ApplicationTest.java
================================================
package com.naman14.timber;

import android.app.Application;
import android.test.ApplicationTestCase;

/**
 * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
 */
public class ApplicationTest extends ApplicationTestCase<Application> {
    public ApplicationTest() {
        super(Application.class);
    }
}

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.naman14.timber">

    <uses-sdk tools:overrideLibrary="de.Maxr1998.trackselectorlib" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    <uses-permission android:name="com.android.vending.BILLING" />


    <application
        android:name=".TimberApp"
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="Timber"
        android:theme="@style/AppTheme.FullScreen.Light"
        tools:replace="android:allowBackup, android:label">

        <activity
            android:name=".activities.MainActivity"
            android:label="Timber"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.CATEGORY_APP_MUSIC" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />

                <data android:scheme="file" />
                <data android:mimeType="audio/*" />
                <data android:mimeType="application/ogg" />
                <data android:mimeType="application/x-ogg" />
                <data android:mimeType="application/itunes" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="http" />
                <data android:mimeType="audio/*" />
                <data android:mimeType="application/ogg" />
                <data android:mimeType="application/x-ogg" />
                <data android:mimeType="application/itunes" />
            </intent-filter>
            <intent-filter android:priority="-1">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="content" />
                <data android:mimeType="audio/*" />
                <data android:mimeType="application/ogg" />
                <data android:mimeType="application/x-ogg" />
                <data android:mimeType="application/itunes" />
            </intent-filter>
        </activity>

        <activity
            android:name=".activities.SettingsActivity"
            android:theme="@style/AppThemeNormalLight" />

        <activity
            android:name=".activities.PlaylistDetailActivity"
            android:theme="@style/AppTheme.FullScreen.Light" />

        <activity
            android:name=".activities.SearchActivity"
            android:theme="@style/AppThemeNormalLight" />

        <activity
            android:name=".activities.NowPlayingActivity"
            android:theme="@style/AppTheme.FullScreen.Light" />

        <activity android:name=".activities.DonateActivity"/>

        <activity
            android:name=".cast.ExpandedControlsActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.ExpandedCastController"
            android:screenOrientation="portrait">

        </activity>

        <receiver android:name=".helpers.MediaButtonIntentReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
                <action android:name="android.media.AUDIO_BECOMING_NOISY" />
            </intent-filter>
        </receiver>
        <!-- Music service -->
        <service
            android:name=".MusicService"
            android:label="@string/app_name"
            android:process=":main" />

        <service
            android:name=".WearBrowserService"
            android:exported="true">
            <intent-filter>
                <action android:name="android.media.browse.MediaBrowserService" />
            </intent-filter>
        </service>


        <meta-data
            android:name=
                "com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
            android:value="com.naman14.timber.cast.CastOptionsProvider" />

        <receiver android:name=".widgets.desktop.StandardWidget" android:label="@string/widget_standard">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.naman14.timber.metachanged" />
                <action android:name="com.naman14.timber.playstatechanged" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_standard" />
        </receiver>

        <receiver android:name=".widgets.desktop.WhiteWidget" android:label="@string/widget_white">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.naman14.timber.metachanged" />
                <action android:name="com.naman14.timber.playstatechanged" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_white" />
        </receiver>

        <receiver android:name=".widgets.desktop.SmallWidget" android:label="@string/widget_small">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="com.naman14.timber.metachanged" />
                <action android:name="com.naman14.timber.playstatechanged" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                android:resource="@xml/widget_small" />
        </receiver>

    </application>

</manifest>


================================================
FILE: app/src/main/aidl/com/naman14/timber/ITimberService.aidl
================================================
package com.naman14.timber;

import com.naman14.timber.helpers.MusicPlaybackTrack;

interface ITimberService
{
    void openFile(String path);
    void open(in long [] list, int position, long sourceId, int sourceType);
    void stop();
    void pause();
    void play();
    void prev(boolean forcePrevious);
    void next();
    void enqueue(in long [] list, int action, long sourceId, int sourceType);
    void setQueuePosition(int index);
    void setShuffleMode(int shufflemode);
    void setRepeatMode(int repeatmode);
    void moveQueueItem(int from, int to);
    void refresh();
    void playlistChanged();
    boolean isPlaying();
    long [] getQueue();
    long getQueueItemAtPosition(int position);
    int getQueueSize();
    int getQueuePosition();
    int getQueueHistoryPosition(int position);
    int getQueueHistorySize();
    int[] getQueueHistoryList();
    long duration();
    long position();
    long seek(long pos);
    void seekRelative(long deltaInMs);
    long getAudioId();
    MusicPlaybackTrack getCurrentTrack();
    MusicPlaybackTrack getTrack(int index);
    long getNextAudioId();
    long getPreviousAudioId();
    long getArtistId();
    long getAlbumId();
    String getArtistName();
    String getTrackName();
    String getAlbumName();
    String getPath();
    int getShuffleMode();
    int removeTracks(int first, int last);
    int removeTrack(long id);
    boolean removeTrackAtPosition(long id, int position);
    int getRepeatMode();
    int getMediaMountedCount();
    int getAudioSessionId();
}



================================================
FILE: app/src/main/aidl/com/naman14/timber/helpers/MusicPlaybackTrack.aidl
================================================
package com.naman14.timber.helpers;

parcelable MusicPlaybackTrack;

================================================
FILE: app/src/main/java/com/naman14/timber/MusicPlayer.java
================================================
/*
 * Copyright (C) 2012 Andrew Neal
 * Copyright (C) 2014 The CyanogenMod Project
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.naman14.timber;

import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.widget.Toast;

import com.naman14.timber.dataloaders.SongLoader;
import com.naman14.timber.helpers.MusicPlaybackTrack;
import com.naman14.timber.utils.TimberUtils.IdType;

import java.util.Arrays;
import java.util.WeakHashMap;

public class MusicPlayer {

    private static final WeakHashMap<Context, ServiceBinder> mConnectionMap;
    private static final long[] sEmptyList;
    public static ITimberService mService = null;
    private static ContentValues[] mContentValuesCache = null;

    static {
        mConnectionMap = new WeakHashMap<Context, ServiceBinder>();
        sEmptyList = new long[0];
    }

    public static final ServiceToken bindToService(final Context context,
                                                   final ServiceConnection callback) {

        Activity realActivity = ((Activity) context).getParent();
        if (realActivity == null) {
            realActivity = (Activity) context;
        }
        final ContextWrapper contextWrapper = new ContextWrapper(realActivity);
        contextWrapper.startService(new Intent(contextWrapper, MusicService.class));
        final ServiceBinder binder = new ServiceBinder(callback,
                contextWrapper.getApplicationContext());
        if (contextWrapper.bindService(
                new Intent().setClass(contextWrapper, MusicService.class), binder, 0)) {
            mConnectionMap.put(contextWrapper, binder);
            return new ServiceToken(contextWrapper);
        }
        return null;
    }

    public static void unbindFromService(final ServiceToken token) {
        if (token == null) {
            return;
        }
        final ContextWrapper mContextWrapper = token.mWrappedContext;
        final ServiceBinder mBinder = mConnectionMap.remove(mContextWrapper);
        if (mBinder == null) {
            return;
        }
        mContextWrapper.unbindService(mBinder);
        if (mConnectionMap.isEmpty()) {
            mService = null;
        }
    }

    public static final boolean isPlaybackServiceConnected() {
        return mService != null;
    }

    public static void next() {
        try {
            if (mService != null) {
                mService.next();
            }
        } catch (final RemoteException ignored) {
        }
    }

    public static void initPlaybackServiceWithSettings(final Context context) {

    }

    public static void asyncNext(final Context context) {
        final Intent previous = new Intent(context, MusicService.class);
        previous.setAction(MusicService.NEXT_ACTION);
        context.startService(previous);
    }

    public static void previous(final Context context, final boolean force) {
        final Intent previous = new Intent(context, MusicService.class);
        if (force) {
            previous.setAction(MusicService.PREVIOUS_FORCE_ACTION);
        } else {
            previous.setAction(MusicService.PREVIOUS_ACTION);
        }
        context.startService(previous);
    }

    public static void playOrPause() {
        try {
            if (mService != null) {
                if (mService.isPlaying()) {
                    mService.pause();
                } else {
                    mService.play();
                }
            }
        } catch (final Exception ignored) {
        }
    }

    public static void cycleRepeat() {
        try {
            if (mService != null) {
                switch (mService.getRepeatMode()) {
                    case MusicService.REPEAT_NONE:
                        mService.setRepeatMode(MusicService.REPEAT_ALL);
                        break;
                    case MusicService.REPEAT_ALL:
                        mService.setRepeatMode(MusicService.REPEAT_CURRENT);
                        if (mService.getShuffleMode() != MusicService.SHUFFLE_NONE) {
                            mService.setShuffleMode(MusicService.SHUFFLE_NONE);
                        }
                        break;
                    default:
                        mService.setRepeatMode(MusicService.REPEAT_NONE);
                        break;
                }
            }
        } catch (final RemoteException ignored) {
        }
    }

    public static void cycleShuffle() {
        try {
            if (mService != null) {
                switch (mService.getShuffleMode()) {
                    case MusicService.SHUFFLE_NONE:
                        mService.setShuffleMode(MusicService.SHUFFLE_NORMAL);
                        if (mService.getRepeatMode() == MusicService.REPEAT_CURRENT) {
                            mService.setRepeatMode(MusicService.REPEAT_ALL);
                        }
                        break;
                    case MusicService.SHUFFLE_NORMAL:
                        mService.setShuffleMode(MusicService.SHUFFLE_NONE);
                        break;
                    case MusicService.SHUFFLE_AUTO:
                        mService.setShuffleMode(MusicService.SHUFFLE_NONE);
                        break;
                    default:
                        break;
                }
            }
        } catch (final RemoteException ignored) {
        }
    }

    public static final boolean isPlaying() {
        if (mService != null) {
            try {
                return mService.isPlaying();
            } catch (final RemoteException ignored) {
            }
        }
        return false;
    }

    public static final int getShuffleMode() {
        if (mService != null) {
            try {
                return mService.getShuffleMode();
            } catch (final RemoteException ignored) {
            }
        }
        return 0;
    }

    public static void setShuffleMode(int mode) {
        try {
            if (mService != null) {
                mService.setShuffleMode(mode);
            }
        } catch (RemoteException ignored) {

        }
    }

    public static final int getRepeatMode() {
        if (mService != null) {
            try {
                return mService.getRepeatMode();
            } catch (final RemoteException ignored) {
            }
        }
        return 0;
    }

    public static final String getTrackName() {
        if (mService != null) {
            try {
                return mService.getTrackName();
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final String getArtistName() {
        if (mService != null) {
            try {
                return mService.getArtistName();
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final String getAlbumName() {
        if (mService != null) {
            try {
                return mService.getAlbumName();
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final long getCurrentAlbumId() {
        if (mService != null) {
            try {
                return mService.getAlbumId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final long getCurrentAudioId() {
        if (mService != null) {
            try {
                return mService.getAudioId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final MusicPlaybackTrack getCurrentTrack() {
        if (mService != null) {
            try {
                return mService.getCurrentTrack();
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final MusicPlaybackTrack getTrack(int index) {
        if (mService != null) {
            try {
                return mService.getTrack(index);
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final long getNextAudioId() {
        if (mService != null) {
            try {
                return mService.getNextAudioId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final long getPreviousAudioId() {
        if (mService != null) {
            try {
                return mService.getPreviousAudioId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final long getCurrentArtistId() {
        if (mService != null) {
            try {
                return mService.getArtistId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final int getAudioSessionId() {
        if (mService != null) {
            try {
                return mService.getAudioSessionId();
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final long[] getQueue() {
        try {
            if (mService != null) {
                return mService.getQueue();
            } else {
            }
        } catch (final RemoteException ignored) {
        }
        return sEmptyList;
    }

    public static final long getQueueItemAtPosition(int position) {
        try {
            if (mService != null) {
                return mService.getQueueItemAtPosition(position);
            } else {
            }
        } catch (final RemoteException ignored) {
        }
        return -1;
    }

    public static final int getQueueSize() {
        try {
            if (mService != null) {
                return mService.getQueueSize();
            } else {
            }
        } catch (final RemoteException ignored) {
        }
        return 0;
    }

    public static final int getQueuePosition() {
        try {
            if (mService != null) {
                return mService.getQueuePosition();
            }
        } catch (final RemoteException ignored) {
        }
        return 0;
    }

    public static void setQueuePosition(final int position) {
        if (mService != null) {
            try {
                mService.setQueuePosition(position);
            } catch (final RemoteException ignored) {
            }
        }
    }

    public static void refresh() {
        try {
            if (mService != null) {
                mService.refresh();
            }
        } catch (final RemoteException ignored) {
        }
    }

    public static final int getQueueHistorySize() {
        if (mService != null) {
            try {
                return mService.getQueueHistorySize();
            } catch (final RemoteException ignored) {
            }
        }
        return 0;
    }

    public static final int getQueueHistoryPosition(int position) {
        if (mService != null) {
            try {
                return mService.getQueueHistoryPosition(position);
            } catch (final RemoteException ignored) {
            }
        }
        return -1;
    }

    public static final int[] getQueueHistoryList() {
        if (mService != null) {
            try {
                return mService.getQueueHistoryList();
            } catch (final RemoteException ignored) {
            }
        }
        return null;
    }

    public static final int removeTrack(final long id) {
        try {
            if (mService != null) {
                return mService.removeTrack(id);
            }
        } catch (final RemoteException ingored) {
        }
        return 0;
    }

    public static final boolean removeTrackAtPosition(final long id, final int position) {
        try {
            if (mService != null) {
                return mService.removeTrackAtPosition(id, position);
            }
        } catch (final RemoteException ingored) {
        }
        return false;
    }

    public static void moveQueueItem(final int from, final int to) {
        try {
            if (mService != null) {
                mService.moveQueueItem(from, to);
            } else {
            }
        } catch (final RemoteException ignored) {
        }
    }

    public static void playArtist(final Context context, final long artistId, int position, boolean shuffle) {
        final long[] artistList = getSongListForArtist(context, artistId);
        if (artistList != null) {
            playAll(context, artistList, position, artistId, IdType.Artist, shuffle);
        }
    }

    public static void playAlbum(final Context context, final long albumId, int position, boolean shuffle) {
        final long[] albumList = getSongListForAlbum(context, albumId);
        if (albumList != null) {
            playAll(context, albumList, position, albumId, IdType.Album, shuffle);
        }
    }

    public static void playAll(final Context context, final long[] list, int position,
                               final long sourceId, final IdType sourceType,
                               final boolean forceShuffle) {
        if (list == null || list.length == 0 || mService == null) {
            return;
        }
        try {
            if (forceShuffle) {
                mService.setShuffleMode(MusicService.SHUFFLE_NORMAL);
            }
            final long currentId = mService.getAudioId();
            final int currentQueuePosition = getQueuePosition();
            if (position != -1 && currentQueuePosition == position && currentId == list[position]) {
                final long[] playlist = getQueue();
                if (Arrays.equals(list, playlist)) {
                    mService.play();
                    return;
                }
            }
            if (position < 0) {
                position = 0;
            }
            mService.open(list, forceShuffle ? -1 : position, sourceId, sourceType.mId);
            mService.play();
        } catch (final RemoteException ignored) {
        } catch (IllegalStateException e) {
            e.printStackTrace();
        }
    }

    public static void playNext(Context context, final long[] list, final long sourceId, final IdType sourceType) {
        if (mService == null) {
            return;
        }
        try {
            mService.enqueue(list, MusicService.NEXT, sourceId, sourceType.mId);
            final String message = makeLabel(context, R.plurals.NNNtrackstoqueue, list.length);
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        } catch (final RemoteException ignored) {
        }
    }

    public static void shuffleAll(final Context context) {
        Cursor cursor = SongLoader.makeSongCursor(context, null, null);
        final long[] trackList = SongLoader.getSongListForCursor(cursor);
        if (trackList.length == 0 || mService == null) {
            return;
        }
        try {
            mService.setShuffleMode(MusicService.SHUFFLE_NORMAL);
            if (getQueuePosition() == 0 && mService.getAudioId() == trackList[0] && Arrays.equals(trackList, getQueue())) {
                    mService.play();
                    return;
            }
            mService.open(trackList, -1, -1, IdType.NA.mId);
            mService.play();
            cursor.close();
        } catch (final RemoteException ignored) {
        }
    }

    public static final long[] getSongListForArtist(final Context context, final long id) {
        final String[] projection = new String[]{
                BaseColumns._ID
        };
        final String selection = MediaStore.Audio.AudioColumns.ARTIST_ID + "=" + id + " AND "
                + MediaStore.Audio.AudioColumns.IS_MUSIC + "=1";
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null,
                MediaStore.Audio.AudioColumns.ALBUM_KEY + "," + MediaStore.Audio.AudioColumns.TRACK);
        if (cursor != null) {
            final long[] mList = SongLoader.getSongListForCursor(cursor);
            cursor.close();
            cursor = null;
            return mList;
        }
        return sEmptyList;
    }

    public static final long[] getSongListForAlbum(final Context context, final long id) {
        final String[] projection = new String[]{
                BaseColumns._ID
        };
        final String selection = MediaStore.Audio.AudioColumns.ALBUM_ID + "=" + id + " AND " + MediaStore.Audio.AudioColumns.IS_MUSIC
                + "=1";
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, selection, null,
                MediaStore.Audio.AudioColumns.TRACK + ", " + MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
        if (cursor != null) {
            final long[] mList = SongLoader.getSongListForCursor(cursor);
            cursor.close();
            cursor = null;
            return mList;
        }
        return sEmptyList;
    }

    public static final int getSongCountForAlbumInt(final Context context, final long id) {
        int songCount = 0;
        if (id == -1) {
            return songCount;
        }

        Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, id);
        Cursor cursor = context.getContentResolver().query(uri,
                new String[]{MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS}, null, null, null);
        if (cursor != null) {
            cursor.moveToFirst();
            if (!cursor.isAfterLast()) {
                if (!cursor.isNull(0)) {
                    songCount = cursor.getInt(0);
                }
            }
            cursor.close();
            cursor = null;
        }

        return songCount;
    }

    public static final String getReleaseDateForAlbum(final Context context, final long id) {
        if (id == -1) {
            return null;
        }
        Uri uri = ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, id);
        Cursor cursor = context.getContentResolver().query(uri, new String[]{
                MediaStore.Audio.AlbumColumns.FIRST_YEAR
        }, null, null, null);
        String releaseDate = null;
        if (cursor != null) {
            cursor.moveToFirst();
            if (!cursor.isAfterLast()) {
                releaseDate = cursor.getString(0);
            }
            cursor.close();
            cursor = null;
        }
        return releaseDate;
    }

    public static void seek(final long position) {
        if (mService != null) {
            try {
                mService.seek(position);
            } catch (final RemoteException ignored) {
            } catch (IllegalStateException ignored) {

            }
        }
    }

    public static void seekRelative(final long deltaInMs) {
        if (mService != null) {
            try {
                mService.seekRelative(deltaInMs);
            } catch (final RemoteException ignored) {
            } catch (final IllegalStateException ignored) {

            }
        }
    }

    public static final long position() {
        if (mService != null) {
            try {
                return mService.position();
            } catch (final RemoteException ignored) {
            } catch (final IllegalStateException ex) {

            }
        }
        return 0;
    }

    public static final long duration() {
        if (mService != null) {
            try {
                return mService.duration();
            } catch (final RemoteException ignored) {
            } catch (final IllegalStateException ignored) {

            }
        }
        return 0;
    }

    public static void clearQueue() {
        if (mService!=null) {
            try {
                mService.removeTracks(0, Integer.MAX_VALUE);
            } catch (final RemoteException ignored) {
            }
        }
    }

    public static void addToQueue(final Context context, final long[] list, long sourceId,
                                  IdType sourceType) {
        if (mService == null) {
            return;
        }
        try {
            mService.enqueue(list, MusicService.LAST, sourceId, sourceType.mId);
            final String message = makeLabel(context, R.plurals.NNNtrackstoqueue, list.length);
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
        } catch (final RemoteException ignored) {
        }
    }

    public static final String makeLabel(final Context context, final int pluralInt,
                                         final int number) {
        return context.getResources().getQuantityString(pluralInt, number, number);
    }

    public static void addToPlaylist(final Context context, final long[] ids, final long playlistid) {
        final int size = ids.length;
        final ContentResolver resolver = context.getContentResolver();
        final String[] projection = new String[]{
                "max(" + "play_order" + ")",
        };
        final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistid);
        Cursor cursor = null;
        int base = 0;

        try {
            cursor = resolver.query(uri, projection, null, null, null);

            if (cursor != null && cursor.moveToFirst()) {
                base = cursor.getInt(0) + 1;
            }
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }

        int numinserted = 0;
        for (int offSet = 0; offSet < size; offSet += 1000) {
            makeInsertItems(ids, offSet, 1000, base);
            numinserted += resolver.bulkInsert(uri, mContentValuesCache);
        }
        final String message = context.getResources().getQuantityString(
                R.plurals.NNNtrackstoplaylist, numinserted, numinserted);
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }

    public static void makeInsertItems(final long[] ids, final int offset, int len, final int base) {
        if (offset + len > ids.length) {
            len = ids.length - offset;
        }

        if (mContentValuesCache == null || mContentValuesCache.length != len) {
            mContentValuesCache = new ContentValues[len];
        }
        for (int i = 0; i < len; i++) {
            if (mContentValuesCache[i] == null) {
                mContentValuesCache[i] = new ContentValues();
            }
            mContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i);
            mContentValuesCache[i].put(MediaStore.Audio.Playlists.Members.AUDIO_ID, ids[offset + i]);
        }
    }

    public static final long createPlaylist(final Context context, final String name) {
        if (name != null && name.length() > 0) {
            final ContentResolver resolver = context.getContentResolver();
            final String[] projection = new String[]{
                    MediaStore.Audio.PlaylistsColumns.NAME
            };
            final String selection = MediaStore.Audio.PlaylistsColumns.NAME + " = '" + name + "'";
            Cursor cursor = resolver.query(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
                    projection, selection, null, null);
            if (cursor.getCount() <= 0) {
                final ContentValues values = new ContentValues(1);
                values.put(MediaStore.Audio.PlaylistsColumns.NAME, name);
                final Uri uri = resolver.insert(MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI,
                        values);
                return Long.parseLong(uri.getLastPathSegment());
            }
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
            return -1;
        }
        return -1;
    }

    public static final void openFile(final String path) {
        if (mService != null) {
            try {
                mService.openFile(path);
            } catch (final RemoteException ignored) {
            }
        }
    }

    public static final class ServiceBinder implements ServiceConnection {
        private final ServiceConnection mCallback;
        private final Context mContext;


        public ServiceBinder(final ServiceConnection callback, final Context context) {
            mCallback = callback;
            mContext = context;
        }

        @Override
        public void onServiceConnected(final ComponentName className, final IBinder service) {
            mService = ITimberService.Stub.asInterface(service);
            if (mCallback != null) {
                mCallback.onServiceConnected(className, service);
            }
            initPlaybackServiceWithSettings(mContext);
        }

        @Override
        public void onServiceDisconnected(final ComponentName className) {
            if (mCallback != null) {
                mCallback.onServiceDisconnected(className);
            }
            mService = null;
        }
    }

    public static final class ServiceToken {
        public ContextWrapper mWrappedContext;

        public ServiceToken(final ContextWrapper context) {
            mWrappedContext = context;
        }
    }
}


================================================
FILE: app/src/main/java/com/naman14/timber/MusicService.java
================================================
/*
 * Copyright (C) 2012 Andrew Neal
 * Copyright (C) 2014 The CyanogenMod Project
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.naman14.timber;

import android.Manifest;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.media.AudioManager;
import android.media.AudioManager.OnAudioFocusChangeListener;
import android.media.MediaMetadataEditor;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.media.RemoteControlClient;
import android.media.audiofx.AudioEffect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.MediaStore;
import android.provider.MediaStore.Audio.AlbumColumns;
import android.provider.MediaStore.Audio.AudioColumns;
import androidx.core.app.NotificationManagerCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;

import androidx.media.app.NotificationCompat;
import androidx.palette.graphics.Palette;
import android.text.TextUtils;
import android.util.Log;

import com.naman14.timber.helpers.MediaButtonIntentReceiver;
import com.naman14.timber.helpers.MusicPlaybackTrack;
import com.naman14.timber.lastfmapi.LastFmClient;
import com.naman14.timber.lastfmapi.models.LastfmUserSession;
import com.naman14.timber.lastfmapi.models.ScrobbleQuery;
import com.naman14.timber.permissions.Nammu;
import com.naman14.timber.provider.MusicPlaybackState;
import com.naman14.timber.provider.RecentStore;
import com.naman14.timber.provider.SongPlayCount;
import com.naman14.timber.utils.NavigationUtils;
import com.naman14.timber.utils.PreferencesUtility;
import com.naman14.timber.utils.TimberUtils;
import com.naman14.timber.utils.TimberUtils.IdType;
import com.nostra13.universalimageloader.core.ImageLoader;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Random;
import java.util.TreeSet;

import de.Maxr1998.trackselectorlib.ModNotInstalledException;
import de.Maxr1998.trackselectorlib.NotificationHelper;
import de.Maxr1998.trackselectorlib.TrackItem;

@SuppressLint("NewApi")
public class MusicService extends Service {
    public static final String PLAYSTATE_CHANGED = "com.naman14.timber.playstatechanged";
    public static final String POSITION_CHANGED = "com.naman14.timber.positionchanged";
    public static final String META_CHANGED = "com.naman14.timber.metachanged";
    public static final String QUEUE_CHANGED = "com.naman14.timber.queuechanged";
    public static final String PLAYLIST_CHANGED = "com.naman14.timber.playlistchanged";
    public static final String REPEATMODE_CHANGED = "com.naman14.timber.repeatmodechanged";
    public static final String SHUFFLEMODE_CHANGED = "com.naman14.timber.shufflemodechanged";
    public static final String TRACK_ERROR = "com.naman14.timber.trackerror";
    public static final String TIMBER_PACKAGE_NAME = "com.naman14.timber";
    public static final String MUSIC_PACKAGE_NAME = "com.android.music";
    public static final String SERVICECMD = "com.naman14.timber.musicservicecommand";
    public static final String TOGGLEPAUSE_ACTION = "com.naman14.timber.togglepause";
    public static final String PAUSE_ACTION = "com.naman14.timber.pause";
    public static final String STOP_ACTION = "com.naman14.timber.stop";
    public static final String PREVIOUS_ACTION = "com.naman14.timber.previous";
    public static final String PREVIOUS_FORCE_ACTION = "com.naman14.timber.previous.force";
    public static final String NEXT_ACTION = "fcom.naman14.timber.next";
    public static final String REPEAT_ACTION = "com.naman14.timber.repeat";
    public static final String SHUFFLE_ACTION = "com.naman14.timber.shuffle";
    public static final String FROM_MEDIA_BUTTON = "frommediabutton";
    public static final String REFRESH = "com.naman14.timber.refresh";
    public static final String UPDATE_LOCKSCREEN = "com.naman14.timber.updatelockscreen";
    public static final String CMDNAME = "command";
    public static final String CMDTOGGLEPAUSE = "togglepause";
    public static final String CMDSTOP = "stop";
    public static final String CMDPAUSE = "pause";
    public static final String CMDPLAY = "play";
    public static final String CMDPREVIOUS = "previous";
    public static final String CMDNEXT = "next";
    public static final String CMDNOTIF = "buttonId";
    public static final String UPDATE_PREFERENCES = "updatepreferences";
    public static final String CHANNEL_ID = "timber_channel_01";
    public static final int NEXT = 2;
    public static final int LAST = 3;
    public static final int SHUFFLE_NONE = 0;
    public static final int SHUFFLE_NORMAL = 1;
    public static final int SHUFFLE_AUTO = 2;
    public static final int REPEAT_NONE = 0;
    public static final int REPEAT_CURRENT = 1;
    public static final int REPEAT_ALL = 2;
    public static final int MAX_HISTORY_SIZE = 1000;
    private static final String TAG = "MusicPlaybackService";
    private static final boolean D = false;
    private static final String SHUTDOWN = "com.naman14.timber.shutdown";
    private static final int IDCOLIDX = 0;
    private static final int TRACK_ENDED = 1;
    private static final int TRACK_WENT_TO_NEXT = 2;
    private static final int RELEASE_WAKELOCK = 3;
    private static final int SERVER_DIED = 4;
    private static final int FOCUSCHANGE = 5;
    private static final int FADEDOWN = 6;
    private static final int FADEUP = 7;
    private static final int IDLE_DELAY = 5 * 60 * 1000;
    private static final long REWIND_INSTEAD_PREVIOUS_THRESHOLD = 3000;
    private static final String[] PROJECTION = new String[]{
            "audio._id AS _id", MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM,
            MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
            MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID,
            MediaStore.Audio.Media.ARTIST_ID
    };
    private static final String[] ALBUM_PROJECTION = new String[]{
            MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST,
            MediaStore.Audio.Albums.LAST_YEAR
    };
    private static final String[] NOTIFICATION_PROJECTION = new String[]{
            "audio._id AS _id", AudioColumns.ALBUM_ID, AudioColumns.TITLE,
            AudioColumns.ARTIST, AudioColumns.DURATION
    };
    private static final Shuffler mShuffler = new Shuffler();
    private static final int NOTIFY_MODE_NONE = 0;
    private static final int NOTIFY_MODE_FOREGROUND = 1;
    private static final int NOTIFY_MODE_BACKGROUND = 2;
    private static final String[] PROJECTION_MATRIX = new String[]{
            "_id", MediaStore.Audio.Media.ARTIST, MediaStore.Audio.Media.ALBUM,
            MediaStore.Audio.Media.TITLE, MediaStore.Audio.Media.DATA,
            MediaStore.Audio.Media.MIME_TYPE, MediaStore.Audio.Media.ALBUM_ID,
            MediaStore.Audio.Media.ARTIST_ID
    };
    private static LinkedList<Integer> mHistory = new LinkedList<>();
    private final IBinder mBinder = new ServiceStub(this);
    private MultiPlayer mPlayer;
    private String mFileToPlay;
    private WakeLock mWakeLock;
    private AlarmManager mAlarmManager;
    private PendingIntent mShutdownIntent;
    private boolean mShutdownScheduled;
    private NotificationManagerCompat mNotificationManager;
    private Cursor mCursor;
    private Cursor mAlbumCursor;
    private AudioManager mAudioManager;
    private SharedPreferences mPreferences;
    private boolean mServiceInUse = false;
    private boolean mIsSupposedToBePlaying = false;
    private long mLastPlayedTime;
    private int mNotifyMode = NOTIFY_MODE_NONE;
    private long mNotificationPostTime = 0;
    private boolean mQueueIsSaveable = true;
    private boolean mPausedByTransientLossOfFocus = false;

    private MediaSessionCompat mSession;
    @SuppressWarnings("deprecation")
    private RemoteControlClient mRemoteControlClient;

    private ComponentName mMediaButtonReceiverComponent;

    private int mCardId;

    private int mPlayPos = -1;

    private int mNextPlayPos = -1;

    private int mOpenFailedCounter = 0;

    private int mMediaMountedCount = 0;

    private int mShuffleMode = SHUFFLE_NONE;

    private int mRepeatMode = REPEAT_NONE;

    private int mServiceStartId = -1;

    private ArrayList<MusicPlaybackTrack> mPlaylist = new ArrayList<MusicPlaybackTrack>(100);

    private long[] mAutoShuffleList = null;

    private MusicPlayerHandler mPlayerHandler;
    private final OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {

        @Override
        public void onAudioFocusChange(final int focusChange) {
            mPlayerHandler.obtainMessage(FOCUSCHANGE, focusChange, 0).sendToTarget();
        }
    };
    private HandlerThread mHandlerThread;
    private BroadcastReceiver mUnmountReceiver = null;
    private MusicPlaybackState mPlaybackStateStore;
    private boolean mShowAlbumArtOnLockscreen;
    private boolean mActivateXTrackSelector;
    private SongPlayCount mSongPlayCount;
    private RecentStore mRecentStore;
    private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String command = intent.getStringExtra(CMDNAME);


            handleCommandIntent(intent);

        }
    };
    private ContentObserver mMediaStoreObserver;

    @Override
    public IBinder onBind(final Intent intent) {
        if (D) Log.d(TAG, "Service bound, intent = " + intent);
        cancelShutdown();
        mServiceInUse = true;
        return mBinder;
    }

    @Override
    public boolean onUnbind(final Intent intent) {
        if (D) Log.d(TAG, "Service unbound");
        mServiceInUse = false;
        saveQueue(true);

        if (mIsSupposedToBePlaying || mPausedByTransientLossOfFocus) {

            return true;

        } else if (mPlaylist.size() > 0 || mPlayerHandler.hasMessages(TRACK_ENDED)) {
            scheduleDelayedShutdown();
            return true;
        }
        stopSelf(mServiceStartId);

        return true;
    }

    @Override
    public void onRebind(final Intent intent) {
        cancelShutdown();
        mServiceInUse = true;
    }

    @Override
    public void onCreate() {
        if (D) Log.d(TAG, "Creating service");
        super.onCreate();

        mNotificationManager = NotificationManagerCompat.from(this);
        createNotificationChannel();

        // gets a pointer to the playback state store
        mPlaybackStateStore = MusicPlaybackState.getInstance(this);
        mSongPlayCount = SongPlayCount.getInstance(this);
        mRecentStore = RecentStore.getInstance(this);


        mHandlerThread = new HandlerThread("MusicPlayerHandler",
                android.os.Process.THREAD_PRIORITY_BACKGROUND);
        mHandlerThread.start();


        mPlayerHandler = new MusicPlayerHandler(this, mHandlerThread.getLooper());


        mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        mMediaButtonReceiverComponent = new ComponentName(getPackageName(),
                MediaButtonIntentReceiver.class.getName());
        mAudioManager.registerMediaButtonEventReceiver(mMediaButtonReceiverComponent);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            setUpMediaSession();
        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            setUpRemoteControlClient();

        mPreferences = getSharedPreferences("Service", 0);
        mCardId = getCardId();

        registerExternalStorageListener();

        mPlayer = new MultiPlayer(this);
        mPlayer.setHandler(mPlayerHandler);

        // Initialize the intent filter and each action
        final IntentFilter filter = new IntentFilter();
        filter.addAction(SERVICECMD);
        filter.addAction(TOGGLEPAUSE_ACTION);
        filter.addAction(PAUSE_ACTION);
        filter.addAction(STOP_ACTION);
        filter.addAction(NEXT_ACTION);
        filter.addAction(PREVIOUS_ACTION);
        filter.addAction(PREVIOUS_FORCE_ACTION);
        filter.addAction(REPEAT_ACTION);
        filter.addAction(SHUFFLE_ACTION);
        filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        filter.addAction(Intent.ACTION_SCREEN_ON);
        // Attach the broadcast listener
        registerReceiver(mIntentReceiver, filter);

        mMediaStoreObserver = new MediaStoreObserver(mPlayerHandler);
        getContentResolver().registerContentObserver(
                MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, mMediaStoreObserver);
        getContentResolver().registerContentObserver(
                MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, mMediaStoreObserver);

        // Initialize the wake lock
        final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
        mWakeLock.setReferenceCounted(false);


        final Intent shutdownIntent = new Intent(this, MusicService.class);
        shutdownIntent.setAction(SHUTDOWN);

        mAlarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        mShutdownIntent = PendingIntent.getService(this, 0, shutdownIntent, 0);

        scheduleDelayedShutdown();

        reloadQueueAfterPermissionCheck();
        notifyChange(QUEUE_CHANGED);
        notifyChange(META_CHANGED);
        //Try to push LastFMCache
        if (LastfmUserSession.getSession(this) != null) {
            LastFmClient.getInstance(this).Scrobble(null);
        }
        PreferencesUtility pref = PreferencesUtility.getInstance(this);
        mShowAlbumArtOnLockscreen = pref.getSetAlbumartLockscreen();
        mActivateXTrackSelector = pref.getXPosedTrackselectorEnabled();
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void setUpRemoteControlClient() {
        //Legacy for ICS
        if (mRemoteControlClient == null) {
            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
            mediaButtonIntent.setComponent(mMediaButtonReceiverComponent);
            PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0);

            // create and register the remote control client
            mRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
            mAudioManager.registerRemoteControlClient(mRemoteControlClient);
        }

        mRemoteControlClient.setTransportControlFlags(
                RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
                        RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
                        RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
                        RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
                        RemoteControlClient.FLAG_KEY_MEDIA_STOP);
    }

    private void setUpMediaSession() {
        mSession = new MediaSessionCompat(this, "Timber");
        mSession.setCallback(new MediaSessionCompat.Callback() {
            @Override
            public void onPause() {
                pause();
                mPausedByTransientLossOfFocus = false;
            }

            @Override
            public void onPlay() {
                play();
            }

            @Override
            public void onSeekTo(long pos) {
                seek(pos);
            }

            @Override
            public void onSkipToNext() {
                gotoNext(true);
            }

            @Override
            public void onSkipToPrevious() {
                prev(false);
            }

            @Override
            public void onStop() {
                pause();
                mPausedByTransientLossOfFocus = false;
                seek(0);
                releaseServiceUiAndStop();
            }
        });
        mSession.setFlags(MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS
                          | MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
    }

    @Override
    public void onDestroy() {
        if (D) Log.d(TAG, "Destroying service");
        super.onDestroy();
        //Try to push LastFMCache
        if (LastfmUserSession.getSession(this).isLogedin()) {
            LastFmClient.getInstance(this).Scrobble(null);
        }
        // Remove any sound effects
        final Intent audioEffectsIntent = new Intent(
                AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
        audioEffectsIntent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
        audioEffectsIntent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
        sendBroadcast(audioEffectsIntent);


        mAlarmManager.cancel(mShutdownIntent);

        mPlayerHandler.removeCallbacksAndMessages(null);

        if (TimberUtils.isJellyBeanMR2())
            mHandlerThread.quitSafely();
        else mHandlerThread.quit();

        mPlayer.release();
        mPlayer = null;

        mAudioManager.abandonAudioFocus(mAudioFocusListener);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            mSession.release();

        getContentResolver().unregisterContentObserver(mMediaStoreObserver);

        closeCursor();

        unregisterReceiver(mIntentReceiver);
        if (mUnmountReceiver != null) {
            unregisterReceiver(mUnmountReceiver);
            mUnmountReceiver = null;
        }

        mWakeLock.release();
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        if (D) Log.d(TAG, "Got new intent " + intent + ", startId = " + startId);
        mServiceStartId = startId;

        if (intent != null) {
            final String action = intent.getAction();

            if (SHUTDOWN.equals(action)) {
                mShutdownScheduled = false;
                releaseServiceUiAndStop();
                return START_NOT_STICKY;
            }

            handleCommandIntent(intent);
        }

        scheduleDelayedShutdown();

        if (intent != null && intent.getBooleanExtra(FROM_MEDIA_BUTTON, false)) {
            MediaButtonIntentReceiver.completeWakefulIntent(intent);
        }

        return START_NOT_STICKY; //no sense to use START_STICKY with using startForeground
    }

    void scrobble() {
        if (LastfmUserSession.getSession(this).isLogedin()) {
            Log.d("Scrobble", "to LastFM");
            String trackname = getTrackName();
            if (trackname != null)
                LastFmClient.getInstance(this).Scrobble(new ScrobbleQuery(getArtistName(), trackname, System.currentTimeMillis() / 1000));
        }
    }

    private void releaseServiceUiAndStop() {
        if (isPlaying()
                || mPausedByTransientLossOfFocus
                || mPlayerHandler.hasMessages(TRACK_ENDED)) {
            return;
        }

        if (D) Log.d(TAG, "Nothing is playing anymore, releasing notification");
        cancelNotification();
        mAudioManager.abandonAudioFocus(mAudioFocusListener);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            mSession.setActive(false);

        if (!mServiceInUse) {
            saveQueue(true);
            stopSelf(mServiceStartId);
        }
    }

    private void handleCommandIntent(Intent intent) {
        final String action = intent.getAction();
        final String command = SERVICECMD.equals(action) ? intent.getStringExtra(CMDNAME) : null;

        if (D) Log.d(TAG, "handleCommandIntent: action = " + action + ", command = " + command);

        if (NotificationHelper.checkIntent(intent)) {
            goToPosition(mPlayPos + NotificationHelper.getPosition(intent));
            return;
        }

        if (CMDNEXT.equals(command) || NEXT_ACTION.equals(action)) {
            gotoNext(true);
        } else if (CMDPREVIOUS.equals(command) || PREVIOUS_ACTION.equals(action)
                || PREVIOUS_FORCE_ACTION.equals(action)) {
            prev(PREVIOUS_FORCE_ACTION.equals(action));
        } else if (CMDTOGGLEPAUSE.equals(command) || TOGGLEPAUSE_ACTION.equals(action)) {
            if (isPlaying()) {
                pause();
                mPausedByTransientLossOfFocus = false;
            } else {
                play();
            }
        } else if (CMDPAUSE.equals(command) || PAUSE_ACTION.equals(action)) {
            pause();
            mPausedByTransientLossOfFocus = false;
        } else if (CMDPLAY.equals(command)) {
            play();
        } else if (CMDSTOP.equals(command) || STOP_ACTION.equals(action)) {
            pause();
            mPausedByTransientLossOfFocus = false;
            seek(0);
            releaseServiceUiAndStop();
        } else if (REPEAT_ACTION.equals(action)) {
            cycleRepeat();
        } else if (SHUFFLE_ACTION.equals(action)) {
            cycleShuffle();
        } else if (UPDATE_PREFERENCES.equals(action)) {
            onPreferencesUpdate(intent.getExtras());
        }
        else if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) {
            if (PreferencesUtility.getInstance(getApplicationContext()).pauseEnabledOnDetach()) {
                pause();
            }
        }
    }

    private void onPreferencesUpdate(Bundle extras) {
        mShowAlbumArtOnLockscreen = extras.getBoolean("lockscreen", mShowAlbumArtOnLockscreen);
        mActivateXTrackSelector = extras.getBoolean("xtrack",mActivateXTrackSelector);
        LastfmUserSession session = LastfmUserSession.getSession(this);
        session.mToken = extras.getString("lf_token", session.mToken);
        session.mUsername = extras.getString("lf_user", session.mUsername);
        if ("logout".equals(session.mToken)) {
            session.mToken = null;
            session.mUsername = null;
        }
        notifyChange(META_CHANGED);

    }

    private void updateNotification() {
        final int newNotifyMode;
        if (isPlaying()) {
            newNotifyMode = NOTIFY_MODE_FOREGROUND;
        } else if (recentlyPlayed()) {
            newNotifyMode = NOTIFY_MODE_BACKGROUND;
        } else {
            newNotifyMode = NOTIFY_MODE_NONE;
        }

        int notificationId = hashCode();
        if (mNotifyMode != newNotifyMode) {
            if (mNotifyMode == NOTIFY_MODE_FOREGROUND) {
                if (TimberUtils.isLollipop())
                    stopForeground(newNotifyMode == NOTIFY_MODE_NONE);
                else
                    stopForeground(newNotifyMode == NOTIFY_MODE_NONE || newNotifyMode == NOTIFY_MODE_BACKGROUND);
            } else if (newNotifyMode == NOTIFY_MODE_NONE) {
                mNotificationManager.cancel(notificationId);
                mNotificationPostTime = 0;
            }
        }

        if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
            startForeground(notificationId, buildNotification());
        } else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
            mNotificationManager.notify(notificationId, buildNotification());
        }

        mNotifyMode = newNotifyMode;
    }

    private void cancelNotification() {
        stopForeground(true);
        mNotificationManager.cancel(hashCode());
        mNotificationPostTime = 0;
        mNotifyMode = NOTIFY_MODE_NONE;
    }

    private int getCardId() {
        if (TimberUtils.isMarshmallow()) {
            if (Nammu.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
                return getmCardId();
            } else return 0;
        } else {
            return getmCardId();
        }
    }

    private int getmCardId() {
        final ContentResolver resolver = getContentResolver();
        Cursor cursor = resolver.query(Uri.parse("content://media/external/fs_id"), null, null,
                null, null);
        int mCardId = -1;
        if (cursor != null && cursor.moveToFirst()) {
            mCardId = cursor.getInt(0);
            cursor.close();
            cursor = null;
        }
        return mCardId;
    }

    public void closeExternalStorageFiles(final String storagePath) {
        stop(true);
        notifyChange(QUEUE_CHANGED);
        notifyChange(META_CHANGED);
    }

    public void registerExternalStorageListener() {
        if (mUnmountReceiver == null) {
            mUnmountReceiver = new BroadcastReceiver() {


                @Override
                public void onReceive(final Context context, final Intent intent) {
                    final String action = intent.getAction();
                    if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
                        saveQueue(true);
                        mQueueIsSaveable = false;
                        closeExternalStorageFiles(intent.getData().getPath());
                    } else if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
                        mMediaMountedCount++;
                        mCardId = getCardId();
                        reloadQueueAfterPermissionCheck();
                        mQueueIsSaveable = true;
                        notifyChange(QUEUE_CHANGED);
                        notifyChange(META_CHANGED);
                    }
                }
            };
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_MEDIA_EJECT);
            filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
            filter.addDataScheme("file");
            registerReceiver(mUnmountReceiver, filter);
        }
    }

    private void scheduleDelayedShutdown() {
        if (D) Log.v(TAG, "Scheduling shutdown in " + IDLE_DELAY + " ms");
        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
                SystemClock.elapsedRealtime() + IDLE_DELAY, mShutdownIntent);
        mShutdownScheduled = true;
    }

    private void cancelShutdown() {
        if (D) Log.d(TAG, "Cancelling delayed shutdown, scheduled = " + mShutdownScheduled);
        if (mShutdownScheduled) {
            mAlarmManager.cancel(mShutdownIntent);
            mShutdownScheduled = false;
        }
    }

    private void stop(final boolean goToIdle) {
        if (D) Log.d(TAG, "Stopping playback, goToIdle = " + goToIdle);
        long duration = this.duration();
        long position = this.position();
        if (duration > 30000 && (position >= duration / 2) || position > 240000) {
            scrobble();
        }

        if (mPlayer.isInitialized()) {
            mPlayer.stop();
        }
        mFileToPlay = null;
        closeCursor();
        if (goToIdle) {
            setIsSupposedToBePlaying(false, false);
        } else {
            if (TimberUtils.isLollipop())
                stopForeground(false);
            else stopForeground(true);
        }
    }

    private int removeTracksInternal(int first, int last) {
        synchronized (this) {
            if (last < first) {
                return 0;
            } else if (first < 0) {
                first = 0;
            } else if (last >= mPlaylist.size()) {
                last = mPlaylist.size() - 1;
            }

            boolean gotonext = false;
            if (first <= mPlayPos && mPlayPos <= last) {
                mPlayPos = first;
                gotonext = true;
            } else if (mPlayPos > last) {
                mPlayPos -= last - first + 1;
            }
            final int numToRemove = last - first + 1;

            if (first == 0 && last == mPlaylist.size() - 1) {
                mPlayPos = -1;
                mNextPlayPos = -1;
                mPlaylist.clear();
                mHistory.clear();
            } else {
                for (int i = 0; i < numToRemove; i++) {
                    mPlaylist.remove(first);
                }

                ListIterator<Integer> positionIterator = mHistory.listIterator();
                while (positionIterator.hasNext()) {
                    int pos = positionIterator.next();
                    if (pos >= first && pos <= last) {
                        positionIterator.remove();
                    } else if (pos > last) {
                        positionIterator.set(pos - numToRemove);
                    }
                }
            }
            if (gotonext) {
                if (mPlaylist.size() == 0) {
                    stop(true);
                    mPlayPos = -1;
                    closeCursor();
                } else {
                    if (mShuffleMode != SHUFFLE_NONE) {
                        mPlayPos = getNextPosition(true);
                    } else if (mPlayPos >= mPlaylist.size()) {
                        mPlayPos = 0;
                    }
                    final boolean wasPlaying = isPlaying();
                    stop(false);
                    openCurrentAndNext();
                    if (wasPlaying) {
                        play();
                    }
                }
                notifyChange(META_CHANGED);
            }
            return last - first + 1;
        }
    }

    private void addToPlayList(final long[] list, int position, long sourceId, TimberUtils.IdType sourceType) {
        final int addlen = list.length;
        if (position < 0) {
            mPlaylist.clear();
            position = 0;
        }

        mPlaylist.ensureCapacity(mPlaylist.size() + addlen);
        if (position > mPlaylist.size()) {
            position = mPlaylist.size();
        }

        final ArrayList<MusicPlaybackTrack> arrayList = new ArrayList<MusicPlaybackTrack>(addlen);
        for (int i = 0; i < list.length; i++) {
            arrayList.add(new MusicPlaybackTrack(list[i], sourceId, sourceType, i));
        }

        mPlaylist.addAll(position, arrayList);

        if (mPlaylist.size() == 0) {
            closeCursor();
            notifyChange(META_CHANGED);
        }
    }

    private void updateCursor(final long trackId) {
        updateCursor("_id=" + trackId, null);
    }

    private void updateCursor(final String selection, final String[] selectionArgs) {
        synchronized (this) {
            closeCursor();
            mCursor = openCursorAndGoToFirst(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    PROJECTION, selection, selectionArgs);
        }
        updateAlbumCursor();
    }

    private void updateCursor(final Uri uri) {
        synchronized (this) {
            closeCursor();
            mCursor = openCursorAndGoToFirst(uri, PROJECTION, null, null);
        }
        updateAlbumCursor();
    }

    private void updateAlbumCursor() {
        long albumId = getAlbumId();
        if (albumId >= 0) {
            mAlbumCursor = openCursorAndGoToFirst(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
                    ALBUM_PROJECTION, "_id=" + albumId, null);
        } else {
            mAlbumCursor = null;
        }
    }

    private Cursor openCursorAndGoToFirst(Uri uri, String[] projection,
                                          String selection, String[] selectionArgs) {
        Cursor c = getContentResolver().query(uri, projection,
                selection, selectionArgs, null);
        if (c == null) {
            return null;
        }
        if (!c.moveToFirst()) {
            c.close();
            return null;
        }
        return c;
    }

    private synchronized void closeCursor() {
        if (mCursor != null) {
            mCursor.close();
            mCursor = null;
        }
        if (mAlbumCursor != null) {
            mAlbumCursor.close();
            mAlbumCursor = null;
        }
    }

    private void openCurrentAndNext() {
        openCurrentAndMaybeNext(true);
    }

    private void openCurrentAndMaybeNext(final boolean openNext) {
        synchronized (this) {
            closeCursor();

            if (mPlaylist.size() == 0) {
                return;
            }
            stop(false);

            boolean shutdown = false;

            updateCursor(mPlaylist.get(mPlayPos).mId);
            while (true) {
                if (mCursor != null
                        && openFile(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/"
                        + mCursor.getLong(IDCOLIDX))) {
                    break;
                }

                closeCursor();
                if (mOpenFailedCounter++ < 10 && mPlaylist.size() > 1) {
                    final int pos = getNextPosition(false);
                    if (pos < 0) {
                        shutdown = true;
                        break;
                    }
                    mPlayPos = pos;
                    stop(false);
                    mPlayPos = pos;
                    updateCursor(mPlaylist.get(mPlayPos).mId);
                } else {
                    mOpenFailedCounter = 0;
                    Log.w(TAG, "Failed to open file for playback");
                    shutdown = true;
                    break;
                }
            }

            if (shutdown) {
                scheduleDelayedShutdown();
                if (mIsSupposedToBePlaying) {
                    mIsSupposedToBePlaying = false;
                    notifyChange(PLAYSTATE_CHANGED);
                }
            } else if (openNext) {
                setNextTrack();
            }
        }
    }

    private void sendErrorMessage(final String trackName) {
        final Intent i = new Intent(TRACK_ERROR);
        i.putExtra(TrackErrorExtra.TRACK_NAME, trackName);
        sendBroadcast(i);
    }

    private int getNextPosition(final boolean force) {
        if (mPlaylist == null || mPlaylist.isEmpty()) {
            return -1;
        }
        if (!force && mRepeatMode == REPEAT_CURRENT) {
            if (mPlayPos < 0) {
                return 0;
            }
            return mPlayPos;
        } else if (mShuffleMode == SHUFFLE_NORMAL) {
            final int numTracks = mPlaylist.size();


            final int[] trackNumPlays = new int[numTracks];
            for (int i = 0; i < numTracks; i++) {
                trackNumPlays[i] = 0;
            }


            final int numHistory = mHistory.size();
            for (int i = 0; i < numHistory; i++) {
                final int idx = mHistory.get(i).intValue();
                if (idx >= 0 && idx < numTracks) {
                    trackNumPlays[idx]++;
                }
            }

            if (mPlayPos >= 0 && mPlayPos < numTracks) {
                trackNumPlays[mPlayPos]++;
            }

            int minNumPlays = Integer.MAX_VALUE;
            int numTracksWithMinNumPlays = 0;
            for (int i = 0; i < trackNumPlays.length; i++) {
                if (trackNumPlays[i] < minNumPlays) {
                    minNumPlays = trackNumPlays[i];
                    numTracksWithMinNumPlays = 1;
                } else if (trackNumPlays[i] == minNumPlays) {
                    numTracksWithMinNumPlays++;
                }
            }


            if (minNumPlays > 0 && numTracksWithMinNumPlays == numTracks
                    && mRepeatMode != REPEAT_ALL && !force) {
                return -1;
            }


            int skip = mShuffler.nextInt(numTracksWithMinNumPlays);
            for (int i = 0; i < trackNumPlays.length; i++) {
                if (trackNumPlays[i] == minNumPlays) {
                    if (skip == 0) {
                        return i;
                    } else {
                        skip--;
                    }
                }
            }

            if (D)
                Log.e(TAG, "Getting the next position resulted did not get a result when it should have");
            return -1;
        } else if (mShuffleMode == SHUFFLE_AUTO) {
            doAutoShuffleUpdate();
            return mPlayPos + 1;
        } else {
            if (mPlayPos >= mPlaylist.size() - 1) {
                if (mRepeatMode == REPEAT_NONE && !force) {
                    return -1;
                } else if (mRepeatMode == REPEAT_ALL || force) {
                    return 0;
                }
                return -1;
            } else {
                return mPlayPos + 1;
            }
        }
    }

    private void setNextTrack() {
        setNextTrack(getNextPosition(false));
    }

    private void setNextTrack(int position) {
        mNextPlayPos = position;
        if (D) Log.d(TAG, "setNextTrack: next play position = " + mNextPlayPos);
        if (mNextPlayPos >= 0 && mPlaylist != null && mNextPlayPos < mPlaylist.size()) {
            final long id = mPlaylist.get(mNextPlayPos).mId;
            mPlayer.setNextDataSource(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "/" + id);
        } else {
            mPlayer.setNextDataSource(null);
        }
    }

    private boolean makeAutoShuffleList() {
        Cursor cursor = null;
        try {
            cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
                    new String[]{
                            MediaStore.Audio.Media._ID
                    }, MediaStore.Audio.Media.IS_MUSIC + "=1", null, null);
            if (cursor == null || cursor.getCount() == 0) {
                return false;
            }
            final int len = cursor.getCount();
            final long[] list = new long[len];
            for (int i = 0; i < len; i++) {
                cursor.moveToNext();
                list[i] = cursor.getLong(0);
            }
            mAutoShuffleList = list;
            return true;
        } catch (final RuntimeException e) {
        } finally {
            if (cursor != null) {
                cursor.close();
                cursor = null;
            }
        }
        return false;
    }

    private void doAutoShuffleUpdate() {
        boolean notify = false;
        if (mPlayPos > 10) {
            removeTracks(0, mPlayPos - 9);
            notify = true;
        }
        final int toAdd = 7 - (mPlaylist.size() - (mPlayPos < 0 ? -1 : mPlayPos));
        for (int i = 0; i < toAdd; i++) {
            int lookback = mHistory.size();
            int idx = -1;
            while (true) {
                idx = mShuffler.nextInt(mAutoShuffleList.length);
                if (!wasRecentlyUsed(idx, lookback)) {
                    break;
                }
                lookback /= 2;
            }
            mHistory.add(idx);
            if (mHistory.size() > MAX_HISTORY_SIZE) {
                mHistory.remove(0);
            }
            mPlaylist.add(new MusicPlaybackTrack(mAutoShuffleList[idx], -1, TimberUtils.IdType.NA, -1));
            notify = true;
        }
        if (notify) {
            notifyChange(QUEUE_CHANGED);
        }
    }

    private boolean wasRecentlyUsed(final int idx, int lookbacksize) {
        if (lookbacksize == 0) {
            return false;
        }
        final int histsize = mHistory.size();
        if (histsize < lookbacksize) {
            lookbacksize = histsize;
        }
        final int maxidx = histsize - 1;
        for (int i = 0; i < lookbacksize; i++) {
            final long entry = mHistory.get(maxidx - i);
            if (entry == idx) {
                return true;
            }
        }
        return false;
    }

    private void notifyChange(final String what) {
        if (D) Log.d(TAG, "notifyChange: what = " + what);

        // Update the lockscreen controls
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            updateMediaSession(what);
        else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
            updateRemoteControlClient(what);

        if (what.equals(POSITION_CHANGED)) {
            return;
        }

        final Intent intent = new Intent(what);
        intent.putExtra("id", getAudioId());
        intent.putExtra("artist", getArtistName());
        intent.putExtra("album", getAlbumName());
        intent.putExtra("albumid", getAlbumId());
        intent.putExtra("track", getTrackName());
        intent.putExtra("playing", isPlaying());

        sendStickyBroadcast(intent);

        final Intent musicIntent = new Intent(intent);
        musicIntent.setAction(what.replace(TIMBER_PACKAGE_NAME, MUSIC_PACKAGE_NAME));
        sendStickyBroadcast(musicIntent);

        if (what.equals(META_CHANGED)) {

            mRecentStore.addSongId(getAudioId());
            mSongPlayCount.bumpSongCount(getAudioId());

        } else if (what.equals(QUEUE_CHANGED)) {
            saveQueue(true);
            if (isPlaying()) {

                if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size()
                        && getShuffleMode() != SHUFFLE_NONE) {
                    setNextTrack(mNextPlayPos);
                } else {
                    setNextTrack();
                }
            }
        } else {
            saveQueue(false);
        }

        if (what.equals(PLAYSTATE_CHANGED)) {
            updateNotification();
        }

    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void updateRemoteControlClient(final String what) {
        //Legacy for ICS
        if (mRemoteControlClient != null) {
            int playState = mIsSupposedToBePlaying
                    ? RemoteControlClient.PLAYSTATE_PLAYING
                    : RemoteControlClient.PLAYSTATE_PAUSED;
            if (what.equals(META_CHANGED) || what.equals(QUEUE_CHANGED)) {
                Bitmap albumArt = null;
                if (mShowAlbumArtOnLockscreen) {
                    albumArt = ImageLoader.getInstance().loadImageSync(TimberUtils.getAlbumArtUri(getAlbumId()).toString());
                    if (albumArt != null) {

                        Bitmap.Config config = albumArt.getConfig();
                        if (config == null) {
                            config = Bitmap.Config.ARGB_8888;
                        }
                        albumArt = albumArt.copy(config, false);
                    }
                }

                RemoteControlClient.MetadataEditor editor = mRemoteControlClient.editMetadata(true);
                editor.putString(MediaMetadataRetriever.METADATA_KEY_ALBUM, getAlbumName());
                editor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, getArtistName());
                editor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, getTrackName());
                editor.putLong(MediaMetadataRetriever.METADATA_KEY_DURATION, duration());
                editor.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, albumArt);
                editor.apply();

            }
            mRemoteControlClient.setPlaybackState(playState);
        }
    }


    private void updateMediaSession(final String what) {
        int playState = mIsSupposedToBePlaying
                ? PlaybackStateCompat.STATE_PLAYING
                : PlaybackStateCompat.STATE_PAUSED;

        if (what.equals(PLAYSTATE_CHANGED) || what.equals(POSITION_CHANGED)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mSession.setPlaybackState(new PlaybackStateCompat.Builder()
                        .setState(playState, position(), 1.0f)
                        .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE |
                                PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
                        .build());
            }
        } else if (what.equals(META_CHANGED) || what.equals(QUEUE_CHANGED)) {
            Bitmap albumArt = null;
            if (mShowAlbumArtOnLockscreen) {
                albumArt = ImageLoader.getInstance().loadImageSync(TimberUtils.getAlbumArtUri(getAlbumId()).toString());
                if (albumArt != null) {

                    Bitmap.Config config = albumArt.getConfig();
                    if (config == null) {
                        config = Bitmap.Config.ARGB_8888;
                    }
                    albumArt = albumArt.copy(config, false);
                }
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                mSession.setMetadata(new MediaMetadataCompat.Builder()
                        .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, getArtistName())
                        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, getAlbumArtistName())
                        .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, getAlbumName())
                        .putString(MediaMetadataCompat.METADATA_KEY_TITLE, getTrackName())
                        .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration())
                        .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, getQueuePosition() + 1)
                        .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getQueue().length)
                        .putString(MediaMetadataCompat.METADATA_KEY_GENRE, getGenreName())
                        .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt)
                        .build());

                mSession.setPlaybackState(new PlaybackStateCompat.Builder()
                        .setState(playState, position(), 1.0f)
                        .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE |
                                PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)
                        .build());
            }
        }
    }

    private void createNotificationChannel() {
        if (TimberUtils.isOreo()) {
            CharSequence name = "Timber";
            int importance = NotificationManager.IMPORTANCE_LOW;
            NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
            manager.createNotificationChannel(mChannel);
        }
    }

    private Notification buildNotification() {
        final String albumName = getAlbumName();
        final String artistName = getArtistName();
        final boolean isPlaying = isPlaying();
        String text = TextUtils.isEmpty(albumName)
                ? artistName : artistName + " - " + albumName;

        int playButtonResId = isPlaying
                ? R.drawable.ic_pause_white_36dp : R.drawable.ic_play_white_36dp;

        Intent nowPlayingIntent = NavigationUtils.getNowPlayingIntent(this);
        PendingIntent clickIntent = PendingIntent.getActivity(this, 0, nowPlayingIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        Bitmap artwork;
        artwork = ImageLoader.getInstance().loadImageSync(TimberUtils.getAlbumArtUri(getAlbumId()).toString());

        if (artwork == null) {
            artwork = ImageLoader.getInstance().loadImageSync("drawable://" + R.drawable.ic_empty_music2);
        }

        if (mNotificationPostTime == 0) {
            mNotificationPostTime = System.currentTimeMillis();
        }

        androidx.core.app.NotificationCompat.Builder builder = new androidx.core.app.NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(artwork)
                .setContentIntent(clickIntent)
                .setContentTitle(getTrackName())
                .setContentText(text)
                .setWhen(mNotificationPostTime)
                .addAction(R.drawable.ic_skip_previous_white_36dp,
                        "",
                        retrievePlaybackAction(PREVIOUS_ACTION))
                .addAction(playButtonResId, "",
                        retrievePlaybackAction(TOGGLEPAUSE_ACTION))
                .addAction(R.drawable.ic_skip_next_white_36dp,
                        "",
                        retrievePlaybackAction(NEXT_ACTION));

        if (TimberUtils.isJellyBeanMR1()) {
            builder.setShowWhen(false);
        }

        if (TimberUtils.isLollipop()) {
            builder.setVisibility(Notification.VISIBILITY_PUBLIC);
            NotificationCompat.MediaStyle style = new NotificationCompat.MediaStyle()
                    .setMediaSession(mSession.getSessionToken())
                    .setShowActionsInCompactView(0, 1, 2, 3);
            builder.setStyle(style);
        }
        if (artwork != null && TimberUtils.isLollipop()) {
            builder.setColor(Palette.from(artwork).generate().getVibrantColor(Color.parseColor("#403f4d")));
        }

        if (TimberUtils.isOreo()) {
            builder.setColorized(true);
        }

        Notification n = builder.build();

        if (mActivateXTrackSelector) {
            addXTrackSelector(n);
        }

        return n;
    }

    private void addXTrackSelector(Notification n) {
        if (NotificationHelper.isSupported(n)) {
            StringBuilder selection = new StringBuilder();
            StringBuilder order = new StringBuilder().append("CASE _id \n");
            for (int i = 0; i < mPlaylist.size(); i++) {
                selection.append("_id=").append(mPlaylist.get(i).mId).append(" OR ");
                order.append("WHEN ").append(mPlaylist.get(i).mId).append(" THEN ").append(i).append("\n");
            }
            order.append("END");
            Cursor c = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, NOTIFICATION_PROJECTION, selection.substring(0, selection.length() - 3), null, order.toString());
            if (c != null && c.getCount() != 0) {
                c.moveToFirst();
                ArrayList<Bundle> list = new ArrayList<>();
                do {
                    TrackItem t = new TrackItem()
                            .setArt(TimberUtils.getAlbumArtUri(c.getLong(c.getColumnIndexOrThrow(AudioColumns.ALBUM_ID))))
                            .setTitle(c.getString(c.getColumnIndexOrThrow(AudioColumns.TITLE)))
                            .setArtist(c.getString(c.getColumnIndexOrThrow(AudioColumns.ARTIST)))
                            .setDuration(TimberUtils.makeShortTimeString(this, c.getInt(c.getColumnIndexOrThrow(AudioColumns.DURATION)) / 1000));
                    list.add(t.get());
                } while (c.moveToNext());
                try {
                    NotificationHelper.insertToNotification(n, list, this, getQueuePosition());
                } catch (ModNotInstalledException e) {
                    e.printStackTrace();
                }
                c.close();
            }
        }
    }

    private final PendingIntent retrievePlaybackAction(final String action) {
        final ComponentName serviceName = new ComponentName(this, MusicService.class);
        Intent intent = new Intent(action);
        intent.setComponent(serviceName);

        return PendingIntent.getService(this, 0, intent, 0);
    }

    private void saveQueue(final boolean full) {
        if (!mQueueIsSaveable) {
            return;
        }

        final SharedPreferences.Editor editor = mPreferences.edit();
        if (full) {
            mPlaybackStateStore.saveState(mPlaylist,
                    mShuffleMode != SHUFFLE_NONE ? mHistory : null);
            editor.putInt("cardid", mCardId);
        }
        editor.putInt("curpos", mPlayPos);
        if (mPlayer.isInitialized()) {
            editor.putLong("seekpos", mPlayer.position());
        }
        editor.putInt("repeatmode", mRepeatMode);
        editor.putInt("shufflemode", mShuffleMode);
        editor.apply();
    }

    private void reloadQueueAfterPermissionCheck() {
        if (TimberUtils.isMarshmallow()) {
            if (Nammu.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
                reloadQueue();
            }
        } else {
            reloadQueue();
        }
    }

    private void reloadQueue() {
        int id = mCardId;
        if (mPreferences.contains("cardid")) {
            id = mPreferences.getInt("cardid", ~mCardId);
        }
        if (id == mCardId) {
            mPlaylist = mPlaybackStateStore.getQueue();
        }
        if (mPlaylist.size() > 0) {
            final int pos = mPreferences.getInt("curpos", 0);
            if (pos < 0 || pos >= mPlaylist.size()) {
                mPlaylist.clear();
                return;
            }
            mPlayPos = pos;
            updateCursor(mPlaylist.get(mPlayPos).mId);
            if (mCursor == null) {
                SystemClock.sleep(3000);
                updateCursor(mPlaylist.get(mPlayPos).mId);
            }
            synchronized (this) {
                closeCursor();
                mOpenFailedCounter = 20;
                openCurrentAndNext();
            }
            if (!mPlayer.isInitialized()) {
                mPlaylist.clear();
                return;
            }

            final long seekpos = mPreferences.getLong("seekpos", 0);
            seek(seekpos >= 0 && seekpos < duration() ? seekpos : 0);

            if (D) {
                Log.d(TAG, "restored queue, currently at position "
                        + position() + "/" + duration()
                        + " (requested " + seekpos + ")");
            }

            int repmode = mPreferences.getInt("repeatmode", REPEAT_NONE);
            if (repmode != REPEAT_ALL && repmode != REPEAT_CURRENT) {
                repmode = REPEAT_NONE;
            }
            mRepeatMode = repmode;

            int shufmode = mPreferences.getInt("shufflemode", SHUFFLE_NONE);
            if (shufmode != SHUFFLE_AUTO && shufmode != SHUFFLE_NORMAL) {
                shufmode = SHUFFLE_NONE;
            }
            if (shufmode != SHUFFLE_NONE) {
                mHistory = mPlaybackStateStore.getHistory(mPlaylist.size());
            }
            if (shufmode == SHUFFLE_AUTO) {
                if (!makeAutoShuffleList()) {
                    shufmode = SHUFFLE_NONE;
                }
            }
            mShuffleMode = shufmode;
        }
    }

    public boolean openFile(final String path) {
        if (D) Log.d(TAG, "openFile: path = " + path);
        synchronized (this) {
            if (path == null) {
                return false;
            }

            if (mCursor == null) {
                Uri uri = Uri.parse(path);
                boolean shouldAddToPlaylist = true;
                long id = -1;
                try {
                    id = Long.valueOf(uri.getLastPathSegment());
                } catch (NumberFormatException ex) {
                    // Ignore
                }

                if (id != -1 && path.startsWith(
                        MediaStore.Audio.Media.EXTERNAL_CONTENT_URI.toString())) {
                    updateCursor(uri);

                } else if (id != -1 && path.startsWith(
                        MediaStore.Files.getContentUri("external").toString())) {
                    updateCursor(id);

                } else if (path.startsWith("content://downloads/")) {

                    String mpUri = getValueForDownloadedFile(this, uri, "mediaprovider_uri");
                    if (D) Log.i(TAG, "Downloaded file's MP uri : " + mpUri);
                    if (!TextUtils.isEmpty(mpUri)) {
                        if (openFile(mpUri)) {
                            notifyChange(META_CHANGED);
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        updateCursorForDownloadedFile(this, uri);
                        shouldAddToPlaylist = false;
                    }

                } else {
                    String where = MediaStore.Audio.Media.DATA + "=?";
                    String[] selectionArgs = new String[]{path};
                    updateCursor(where, selectionArgs);
                }
                try {
                    if (mCursor != null && shouldAddToPlaylist) {
                        mPlaylist.clear();
                        mPlaylist.add(new MusicPlaybackTrack(
                                mCursor.getLong(IDCOLIDX), -1, TimberUtils.IdType.NA, -1));
                        notifyChange(QUEUE_CHANGED);
                        mPlayPos = 0;
                        mHistory.clear();
                    }
                } catch (final UnsupportedOperationException ex) {
                    // Ignore
                }
            }

            mFileToPlay = path;
            mPlayer.setDataSource(mFileToPlay);
            if (mPlayer.isInitialized()) {
                mOpenFailedCounter = 0;
                return true;
            }

            String trackName = getTrackName();
            if (TextUtils.isEmpty(trackName)) {
                trackName = path;
            }
            sendErrorMessage(trackName);

            stop(true);
            return false;
        }
    }

    private void updateCursorForDownloadedFile(Context context, Uri uri) {
        synchronized (this) {
            closeCursor();
            MatrixCursor cursor = new MatrixCursor(PROJECTION_MATRIX);
            String title = getValueForDownloadedFile(this, uri, "title");
            cursor.addRow(new Object[]{
                    null,
                    null,
                    null,
                    title,
                    null,
                    null,
                    null,
                    null
            });
            mCursor = cursor;
            mCursor.moveToFirst();
        }
    }

    private String getValueForDownloadedFile(Context context, Uri uri, String column) {

        Cursor cursor = null;
        final String[] projection = {
                column
        };

        try {
            cursor = context.getContentResolver().query(uri, projection, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
                return cursor.getString(0);
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        return null;
    }

    public int getAudioSessionId() {
        synchronized (this) {
            return mPlayer.getAudioSessionId();
        }
    }

    public int getMediaMountedCount() {
        return mMediaMountedCount;
    }

    public int getShuffleMode() {
        return mShuffleMode;
    }

    public void setShuffleMode(final int shufflemode) {
        synchronized (this) {
            if (mShuffleMode == shufflemode && mPlaylist.size() > 0) {
                return;
            }

            mShuffleMode = shufflemode;
            if (mShuffleMode == SHUFFLE_AUTO) {
                if (makeAutoShuffleList()) {
                    mPlaylist.clear();
                    doAutoShuffleUpdate();
                    mPlayPos = 0;
                    openCurrentAndNext();
                    play();
                    notifyChange(META_CHANGED);
                    return;
                } else {
                    mShuffleMode = SHUFFLE_NONE;
                }
            } else {
                setNextTrack();
            }
            saveQueue(false);
            notifyChange(SHUFFLEMODE_CHANGED);
        }
    }

    public int getRepeatMode() {
        return mRepeatMode;
    }

    public void setRepeatMode(final int repeatmode) {
        synchronized (this) {
            mRepeatMode = repeatmode;
            setNextTrack();
            saveQueue(false);
            notifyChange(REPEATMODE_CHANGED);
        }
    }

    public int removeTrack(final long id) {
        int numremoved = 0;
        synchronized (this) {
            for (int i = 0; i < mPlaylist.size(); i++) {
                if (mPlaylist.get(i).mId == id) {
                    numremoved += removeTracksInternal(i, i);
                    i--;
                }
            }
        }
        if (numremoved > 0) {
            notifyChange(QUEUE_CHANGED);
        }
        return numremoved;
    }

    public boolean removeTrackAtPosition(final long id, final int position) {
        synchronized (this) {
            if (position >= 0 &&
                    position < mPlaylist.size() &&
                    mPlaylist.get(position).mId == id) {

                return removeTracks(position, position) > 0;
            }
        }
        return false;
    }

    public int removeTracks(final int first, final int last) {
        final int numremoved = removeTracksInternal(first, last);
        if (numremoved > 0) {
            notifyChange(QUEUE_CHANGED);
        }
        return numremoved;
    }

    public int getQueuePosition() {
        synchronized (this) {
            return mPlayPos;
        }
    }

    public void setQueuePosition(final int index) {
        synchronized (this) {
            stop(false);
            mPlayPos = index;
            openCurrentAndNext();
            play();
            notifyChange(META_CHANGED);
            if (mShuffleMode == SHUFFLE_AUTO) {
                doAutoShuffleUpdate();
            }
        }
    }

    public int getQueueHistorySize() {
        synchronized (this) {
            return mHistory.size();
        }
    }

    public int getQueueHistoryPosition(int position) {
        synchronized (this) {
            if (position >= 0 && position < mHistory.size()) {
                return mHistory.get(position);
            }
        }

        return -1;
    }

    public int[] getQueueHistoryList() {
        synchronized (this) {
            int[] history = new int[mHistory.size()];
            for (int i = 0; i < mHistory.size(); i++) {
                history[i] = mHistory.get(i);
            }

            return history;
        }
    }

    public String getPath() {
        synchronized (this) {
            if (mCursor == null) {
                return null;
            }
            return mCursor.getString(mCursor.getColumnIndexOrThrow(AudioColumns.DATA));
        }
    }

    public String getAlbumName() {
        synchronized (this) {
            if (mCursor == null) {
                return null;
            }
            return mCursor.getString(mCursor.getColumnIndexOrThrow(AudioColumns.ALBUM));
        }
    }

    public String getTrackName() {
        synchronized (this) {
            if (mCursor == null) {
                return null;
            }
            return mCursor.getString(mCursor.getColumnIndexOrThrow(AudioColumns.TITLE));
        }
    }

    public String getGenreName() {
        synchronized (this) {
            if (mCursor == null || mPlayPos < 0 || mPlayPos >= mPlaylist.size()) {
                return null;
            }
            String[] genreProjection = {MediaStore.Audio.Genres.NAME};
            Uri genreUri = MediaStore.Audio.Genres.getContentUriForAudioId("external",
                    (int) mPlaylist.get(mPlayPos).mId);
            Cursor genreCursor = getContentResolver().query(genreUri, genreProjection,
                    null, null, null);
            if (genreCursor != null) {
                try {
                    if (genreCursor.moveToFirst()) {
                        return genreCursor.getString(
                                genreCursor.getColumnIndexOrThrow(MediaStore.Audio.Genres.NAME));
                    }
                } finally {
                    genreCursor.close();
                }
            }
            return null;
        }
    }

    public String getArtistName() {
        synchronized (this) {
            if (mCursor == null) {
                return null;
            }
            return mCursor.getString(mCursor.getColumnIndexOrThrow(AudioColumns.ARTIST));
        }
    }

    public String getAlbumArtistName() {
        synchronized (this) {
            if (mAlbumCursor == null) {
                return null;
            }
            return mAlbumCursor.getString(mAlbumCursor.getColumnIndexOrThrow(AlbumColumns.ARTIST));
        }
    }

    public long getAlbumId() {
        synchronized (this) {
            if (mCursor == null) {
                return -1;
            }
            return mCursor.getLong(mCursor.getColumnIndexOrThrow(AudioColumns.ALBUM_ID));
        }
    }

    public long getArtistId() {
        synchronized (this) {
            if (mCursor == null) {
                return -1;
            }
            return mCursor.getLong(mCursor.getColumnIndexOrThrow(AudioColumns.ARTIST_ID));
        }
    }

    public long getAudioId() {
        MusicPlaybackTrack track = getCurrentTrack();
        if (track != null) {
            return track.mId;
        }

        return -1;
    }

    public MusicPlaybackTrack getCurrentTrack() {
        return getTrack(mPlayPos);
    }

    public synchronized MusicPlaybackTrack getTrack(int index) {
        if (index >= 0 && index < mPlaylist.size() && mPlayer.isInitialized()) {
            return mPlaylist.get(index);
        }

        return null;
    }

    public long getNextAudioId() {
        synchronized (this) {
            if (mNextPlayPos >= 0 && mNextPlayPos < mPlaylist.size() && mPlayer.isInitialized()) {
                return mPlaylist.get(mNextPlayPos).mId;
            }
        }
        return -1;
    }

    public long getPreviousAudioId() {
        synchronized (this) {
            if (mPlayer.isInitialized()) {
                int pos = getPreviousPlayPosition(false);
                if (pos >= 0 && pos < mPlaylist.size()) {
                    return mPlaylist.get(pos).mId;
                }
            }
        }
        return -1;
    }

    public long seek(long position) {
        if (mPlayer.isInitialized()) {
            if (position < 0) {
                position = 0;
            } else if (position > mPlayer.duration()) {
                position = mPlayer.duration();
            }
            long result = mPlayer.seek(position);
            notifyChange(POSITION_CHANGED);
            return result;
        }
        return -1;
    }

    public void seekRelative(long deltaInMs) {
        synchronized (this) {
            if (mPlayer.isInitialized()) {
                final long newPos = position() + deltaInMs;
                final long duration = duration();
                if (newPos < 0) {
                    prev(true);
                    // seek to the new duration + the leftover position
                    seek(duration() + newPos);
                } else if (newPos >= duration) {
                    gotoNext(true);
                    // seek to the leftover duration
                    seek(newPos - duration);
                } else {
                    seek(newPos);
                }
            }
        }
    }

    public long position() {
        if (mPlayer.isInitialized()) {
            return mPlayer.position();
        }
        return -1;
    }

    public long duration() {
        if (mPlayer.isInitialized()) {
            return mPlayer.duration();
        }
        return -1;
    }

    public long[] getQueue() {
        synchronized (this) {
            final int len = mPlaylist.size();
            final long[] list = new long[len];
            for (int i = 0; i < len; i++) {
                list[i] = mPlaylist.get(i).mId;
            }
            return list;
        }
    }

    public long getQueueItemAtPosition(int position) {
        synchronized (this) {
            if (position >= 0 && position < mPlaylist.size()) {
                return mPlaylist.get(position).mId;
            }
        }

        return -1;
    }

    public int getQueueSize() {
        synchronized (this) {
            return mPlaylist.size();
        }
    }

    public boolean isPlaying() {
        return mIsSupposedToBePlaying;
    }

    private void setIsSupposedToBePlaying(boolean value, boolean notify) {
        if (mIsSupposedToBePlaying != value) {
            mIsSupposedToBePlaying = value;


            if (!mIsSupposedToBePlaying) {
                scheduleDelayedShutdown();
                mLastPlayedTime = System.currentTimeMillis();
            }

            if (notify) {
                notifyChange(PLAYSTATE_CHANGED);
            }
        }
    }

    private boolean recentlyPlayed() {
        return isPlaying() || System.currentTimeMillis() - mLastPlayedTime < IDLE_DELAY;
    }

    public void open(final long[] list, final int position, long sourceId, TimberUtils.IdType sourceType) {
        synchronized (this) {
            if (mShuffleMode == SHUFFLE_AUTO) {
                mShuffleMode = SHUFFLE_NORMAL;
            }
            final long oldId = getAudioId();
            final int listlength = list.length;
            boolean newlist = true;
            if (mPlaylist.size() == listlength) {
                newlist = false;
                for (int i = 0; i < listlength; i++) {
                    if (list[i] != mPlaylist.get(i).mId) {
                        newlist = true;
                        break;
                    }
                }
            }
            if (newlist) {
                addToPlayList(list, -1, sourceId, sourceType);
                notifyChange(QUEUE_CHANGED);
            }
            if (position >= 0) {
                mPlayPos = position;
            } else {
                mPlayPos = mShuffler.nextInt(mPlaylist.size());
            }
            mHistory.clear();
            openCurrentAndNext();
            if (oldId != getAudioId()) {
                notifyChange(META_CHANGED);
            }
        }
    }

    public void stop() {
        stop(true);
    }

    public void play() {
        play(true);
    }

    public void play(boolean createNewNextTrack) {
        int status = mAudioManager.requestAudioFocus(mAudioFocusListener,
                AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);

        if (D) Log.d(TAG, "Starting playback: audio focus request status = " + status);

        if (status != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
            return;
        }

        final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
        intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
        intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
        sendBroadcast(intent);

        mAudioManager.registerMediaButtonEventReceiver(new ComponentName(getPackageName(),
                MediaButtonIntentReceiver.class.getName()));
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
            mSession.setActive(true);

        if (createNewNextTrack) {
            setNextTrack();
        } else {
            setNextTrack(mNextPlayPos);
        }

        if (mPlayer.isInitialized()) {
            final long duration = mPlayer.duration();
            if (mRepeatMode != REPEAT_CURRENT && duration > 2000
                    && mPlayer.position() >= duration - 2000) {
                gotoNext(true);
            }

            mPlayer.start();
            mPlayerHandler.removeMessages(FADEDOWN);
            mPlayerHandler.sendEmptyMessage(FADEUP);

            setIsSupposedToBePlaying(true, true);

            cancelShutdown();
            updateNotification();
            notifyChange(META_CHANGED);
        } else if (mPlaylist.size() <= 0) {
            setShuffleMode(SHUFFLE_AUTO);
        }
    }

    public void pause() {
        if (D) Log.d(TAG, "Pausing playback");
        synchronized (this) {
            mPlayerHandler.removeMessages(FADEUP);
            if (mIsSupposedToBePlaying) {
                final Intent intent = new Intent(
                        AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION);
                intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, getAudioSessionId());
                intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, getPackageName());
                sendBroadcast(intent);

                mPlayer.pause();
                notifyChange(META_CHANGED);
                setIsSupposedToBePlaying(false, true);
            }
        }
    }

    public void gotoNext(final boolean force) {
        if (D) Log.d(TAG, "Going to next track");
        synchronized (this) {
            if (mPlaylist.size() <= 0) {
                if (D) Log.d(TAG, "No play queue");
                scheduleDelayedShutdown();
                return;
            }
            int pos = mNextPlayPos;
            if (pos < 0) {
                pos = getNextPosition(force);
            }

            if (pos < 0) {
                setIsSupposedToBePlaying(false, true);
                return;
            }

            stop(false);
            setAndRecordPlayPos(pos);
            openCurrentAndNext();
            play();
            notifyChange(META_CHANGED);
        }
    }

    public void goToPosition(int pos) {
        synchronized (this) {
            if (mPlaylist.size() <= 0) {
                if (D) Log.d(TAG, "No play queue");
                scheduleDelayedShutdown();
                return;
            }
            if (pos < 0) {
                return;
            }
            if (pos == mPlayPos) {
                if (!isPlaying()) {
                    play();
                }
                return;
            }
            stop(false);
            setAndRecordPlayPos(pos);
            openCurrentAndNext();
            play();
            notifyChange(META_CHANGED);
        }
    }

    public void setAndRecordPlayPos(int nextPos) {
        synchronized (this) {

            if (mShuffleMode != SHUFFLE_NONE) {
                mHistory.add(mPlayPos);
                if (mHistory.size() > MAX_HISTORY_SIZE) {
                    mHistory.remove(0);
                }
            }

            mPlayPos = nextPos;
        }
    }

    public void prev(boolean forcePrevious) {
        synchronized (this) {
            boolean goPrevious = getRepeatMode() != REPEAT_CURRENT &&
                    (position() < REWIND_INSTEAD_PREVIOUS_THRESHOLD || forcePrevious);

            if (goPrevious) {
                if (D) Log.d(TAG, "Going to previous track");
                int pos = getPreviousPlayPosition(true);

                if (pos < 0) {
                    return;
                }
                mNextPlayPos = mPlayPos;
                mPlayPos = pos;
                stop(false);
                openCurrent();
                play(false);
                notifyChange(META_CHANGED);
            } else {
                if (D) Log.d(TAG, "Going to beginning of track");
                seek(0);
                play(false);
            }
        }
    }

    public int getPreviousPlayPosition(boolean removeFromHistory) {
        synchronized (this) {
            if (mShuffleMode == SHUFFLE_NORMAL) {

                final int histsize = mHistory.size();
                if (histsize == 0) {
                    return -1;
                }
                final Integer pos = mHistory.get(histsize - 1);
                if (removeFromHistory) {
                    mHistory.remove(histsize - 1);
                }
                return pos.intValue();
            } else {
                if (mPlayPos > 0) {
                    return mPlayPos - 1;
                } else {
                    return mPlaylist.size() - 1;
                }
            }
        }
    }

    private void openCurrent() {
        openCurrentAndMaybeNext(false);
    }

    public void moveQueueItem(int index1, int index2) {
        synchronized (this) {
            if (index1 >= mPlaylist.size()) {
                index1 = mPlaylist.size() - 1;
            }
            if (index2 >= mPlaylist.size()) {
                index2 = mPlaylist.size() - 1;
            }

            if (index1 == index2) {
                return;
            }

            final MusicPlaybackTrack track = mPlaylist.remove(index1);
            if (index1 < index2) {
                mPlaylist.add(index2, track);
                if (mPlayPos == index1) {
                    mPlayPos = index2;
                } else if (mPlayPos >= index1 && mPlayPos <= index2) {
                    mPlayPos--;
                }
            } else if (index2 < index1) {
                mPlaylist.add(index2, track);
                if (mPlayPos == index1) {
                    mPlayPos = index2;
                } else if (mPlayPos >= index2 && mPlayPos <= index1) {
                    mPlayPos++;
                }
            }
            notifyChange(QUEUE_CHANGED);
        }
    }

    public void enqueue(final long[] list, final int action, long sourceId, IdType sourceType) {
        synchronized (this) {
            if (action == NEXT && mPlayPos + 1 < mPlaylist.size()) {
                addToPlayList(list, mPlayPos + 1, sourceId, sourceType);
                mNextPlayPos = mPlayPos + 1;
                notifyChange(QUEUE_CHANGED);
            } else {
                addToPlayList(list, Integer.MAX_VALUE, sourceId, sourceType);
                notifyChange(QUEUE_CHANGED);
            }

            if (mPlayPos < 0) {
                mPlayPos = 0;
                openCurrentAndNext();
                play();
                notifyChange(META_CHANGED);
            }
        }
    }

    private void cycleRepeat() {
        if (mRepeatMode == REPEAT_NONE) {
            setRepeatMode(REPEAT_CURRENT);
            if (mShuffleMode != SHUFFLE_NONE) {
                setShuffleMode(SHUFFLE_NONE);
            }
        } else {
            setRepeatMode(REPEAT_NONE);
        }
    }

    private void cycleShuffle() {
        if (mShuffleMode == SHUFFLE_NONE) {
            setShuffleMode(SHUFFLE_NORMAL);
//            if (mRepeatMode == REPEAT_CURRENT) {
//                setRepeatMode(REPEAT_ALL);
//            }
        } else if (mShuffleMode == SHUFFLE_NORMAL || mShuffleMode == SHUFFLE_AUTO) {
            setShuffleMode(SHUFFLE_NONE);
        }
    }

    public void refresh() {
        notifyChange(REFRESH);
    }

    public void playlistChanged() {
        notifyChange(PLAYLIST_CHANGED);
    }

    public interface TrackErrorExtra {

        String TRACK_NAME = "trackname";
    }

    private static final class MusicPlayerHandler extends Handler {
        private final WeakReference<MusicService> mService;
        private float mCurrentVolume = 1.0f;


        public MusicPlayerHandler(final MusicService service, final Looper looper) {
            super(looper);
            mService = new WeakReference<MusicService>(service);
        }


        @Override
        public void handleMessage(final Message msg) {
            final MusicService service = mService.get();
            if (service == null) {
                return;
            }

            synchronized (service) {
                switch (msg.what) {
                    case FADEDOWN:
                        mCurrentVolume -= .05f;
                        if (mCurrentVolume > .2f) {
                            sendEmptyMessageDelayed(FADEDOWN, 10);
                        } else {
                            mCurrentVolume = .2f;
                        }
                        service.mPlayer.setVolume(mCurrentVolume);
                        break;
                    case FADEUP:
                        mCurrentVolume += .01f;
                        if (mCurrentVolume < 1.0f) {
                            sendEmptyMessageDelayed(FADEUP, 10);
                        } else {
                            mCurrentVolume = 1.0f;
                        }
                        service.mPlayer.setVolume(mCurrentVolume);
                        break;
                    case SERVER_DIED:
                        if (service.isPlaying()) {
                            final TrackErrorInfo info = (TrackErrorInfo) msg.obj;
                            service.sendErrorMessage(info.mTrackName);


                            service.removeTrack(info.mId);
                        } else {
                            service.openCurrentAndNext();
                        }
                        break;
                    case TRACK_WENT_TO_NEXT:
                        mService.get().scrobble();
                        service.setAndRecordPlayPos(service.mNextPlayPos);
                        service.setNextTrack();
                        if (service.mCursor != null) {
                            service.mCursor.close();
                            service.mCursor = null;
                        }
                        service.updateCursor(service.mPlaylist.get(service.mPlayPos).mId);
                        service.notifyChange(META_CHANGED);
                        service.updateNotification();
                        break;
                    case TRACK_ENDED:
                        if (service.mRepeatMode == REPEAT_CURRENT) {
                            service.seek(0);
                            service.play();
                        } else {
                            service.gotoNext(false);
                        }
                        break;
                    case RELEASE_WAKELOCK:
                        service.mWakeLock.release();
                        break;
                    case FOCUSCHANGE:
                        if (D) Log.d(TAG, "Received audio focus change event " + msg.arg1);
                        switch (msg.arg1) {
                            case AudioManager.AUDIOFOCUS_LOSS:
                            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                                if (service.isPlaying()) {
                                    service.mPausedByTransientLossOfFocus =
                                            msg.arg1 == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT;
                                }
                                service.pause();
                                break;
                            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                                removeMessages(FADEUP);
                                sendEmptyMessage(FADEDOWN);
                                break;
                            case AudioManager.AUDIOFOCUS_GAIN:
                                if (!service.isPlaying()
                                        && service.mPausedByTransientLossOfFocus) {
                                    service.mPausedByTransientLossOfFocus = false;
                                    mCurrentVolume = 0f;
                                    service.mPlayer.setVolume(mCurrentVolume);
                                    service.play();
                                } else {
                                    removeMessages(FADEDOWN);
                                    sendEmptyMessage(FADEUP);
                                }
                                break;
                            default:
                        }
                        break;
                    default:
                        break;
                }
            }
        }
    }

    private static final class Shuffler {

        private final LinkedList<Integer> mHistoryOfNumbers = new LinkedList<Integer>();

        private final TreeSet<Integer> mPreviousNumbers = new TreeSet<Integer>();

        private final Random mRandom = new Random();

        private int mPrevious;


        public Shuffler() {
            super();
        }


        public int nextInt(final int interval) {
            int next;
            do {
                next = mRandom.nextInt(interval);
            } while (next == mPrevious && interval > 1
                    && !mPreviousNumbers.contains(Integer.valueOf(next)));
            mPrevious = next;
            mHistoryOfNumbers.add(mPrevious);
            mPreviousNumbers.add(mPrevious);
            cleanUpHistory();
            return next;
        }


        private void cleanUpHistory() {
            if (!mHistoryOfNumbers.isEmpty() && mHistoryOfNumbers.size() >= MAX_HISTORY_SIZE) {
                for (int i = 0; i < Math.max(1, MAX_HISTORY_SIZE / 2); i++) {
                    mPreviousNumbers.remove(mHistoryOfNumbers.removeFirst());
                }
            }
        }
    }

    private static final class TrackErrorInfo {
        public long mId;
        public String mTrackName;

        public TrackErrorInfo(long id, String trackName) {
            mId = id;
            mTrackName = trackName;
        }
    }

    private static final class MultiPlayer implements MediaPlayer.OnErrorListener,
            MediaPlayer.OnCompletionListener {

        private final WeakReference<MusicService> mService;

        private MediaPlayer mCurrentMediaPlayer = new MediaPlayer();

        private MediaPlayer mNextMediaPlayer;

        private Handler mHandler;

        private boolean mIsInitialized = false;

        private String mNextMediaPath;


        public MultiPlayer(final MusicService service) {
            mService = new WeakReference<MusicService>(service);
            mCurrentMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK);

        }


        public void setDataSource(final String path) {
            try {
                mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path);
                if (mIsInitialized) {
                    setNextDataSource(null);
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }
        }


        private boolean setDataSourceImpl(final MediaPlayer player, final String path) {
            try {
                player.reset();
                player.setOnPreparedListener(null);
                if (path.startsWith("content://")) {
                    player.setDataSource(mService.get(), Uri.parse(path));
                } else {
                    player.setDataSource(path);
                }
                player.setAudioStreamType(AudioManager.STREAM_MUSIC);

                player.prepare();
            } catch (final IOException todo) {

                return false;
            } catch (final IllegalArgumentException todo) {

                return false;
            }
            player.setOnCompletionListener(this);
            player.setOnErrorListener(this);
            return true;
        }


        public void setNextDataSource(final String path) {
            mNextMediaPath = null;
            try {
                mCurrentMediaPlayer.setNextMediaPlayer(null);
            } catch (IllegalArgumentException e) {
                Log.i(TAG, "Next media player is current one, continuing");
            } catch (IllegalStateException e) {
                Log.e(TAG, "Media player not initialized!");
                return;
            }
            if (mNextMediaPlayer != null) {
                mNextMediaPlayer.release();
                mNextMediaPlayer = null;
            }
            if (path == null) {
                return;
            }
            mNextMediaPlayer = new MediaPlayer();
            mNextMediaPlayer.setWakeMode(mService.get(), PowerManager.PARTIAL_WAKE_LOCK);
            mNextMediaPlayer.setAudioSessionId(getAudioSessionId());
            try {
                if (setDataSourceImpl(mNextMediaPlayer, path)) {
                    mNextMediaPath = path;
                    mCurrentMediaPlayer.setNextMediaPlayer(mNextMediaPlayer);
                } else {
                    if (mNextMediaPlayer != null) {
                        mNextMediaPlayer.release();
                        mNextMediaPlayer = null;
                    }
                }
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }
        }


        public void setHandler(final Handler handler) {
            mHandler = handler;
        }


        public boolean isInitialized() {
            return mIsInitialized;
        }


        public void start() {
            mCurrentMediaPlayer.start();
        }


        public void stop() {
            mCurrentMediaPlayer.reset();
            mIsInitialized = false;
        }


        public void release() {
            mCurrentMediaPlayer.release();
        }


        public void pause() {
            mCurrentMediaPlayer.pause();
        }


        public long duration() {
            return mCurrentMediaPlayer.getDuration();
        }


        public long position() {
            return mCurrentMediaPlayer.getCurrentPosition();
        }


        public long seek(final long whereto) {
            mCurrentMediaPlayer.seekTo((int) whereto);
            return whereto;
        }


        public void setVolume(final float vol) {
            try {
                mCurrentMediaPlayer.setVolume(vol, vol);
            } catch (IllegalStateException e) {
                e.printStackTrace();
            }
        }

        public int getAudioSessionId() {
            return mCurrentMediaPlayer.getAudioSessionId();
        }

        public void setAudioSessionId(final int sessionId) {
            mCurrentMediaPlayer.setAudioSessionId(sessionId);
        }

        @Override
        public boolean onError(final MediaPlayer mp, final int what, final int extra) {
            Log.w(TAG, "Music Server Error what: " + what + " extra: " + extra);
            switch (what) {
                case MediaPlayer.MEDIA_ERROR_SERVER_DIED:
                    final MusicService service = mService.get();
                    final TrackErrorInfo errorInfo = new TrackErrorInfo(service.getAudioId(),
                            service.getTrackName());

                    mIsInitialized = false;
                    mCurrentMediaPlayer.release();
                    mCurrentMediaPlayer = new MediaPlayer();
                    mCurrentMediaPlayer.setWakeMode(service, PowerManager.PARTIAL_WAKE_LOCK);
                    Message msg = mHandler.obtainMessage(SERVER_DIED, errorInfo);
                    mHandler.sendMessageDelayed(msg, 2000);
                    return true;
                default:
                    break;
            }
            return false;
        }


        @Override
        public void onCompletion(final MediaPlayer mp) {
            if (mp == mCurrentMediaPlayer && mNextMediaPlayer != null) {
                mCurrentMediaPlayer.release();
                mCurrentMediaPlayer = mNextMediaPlayer;
                mNextMediaPath = null;
                mNextMediaPlayer = null;
                mHandler.sendEmptyMessage(TRACK_WENT_TO_NEXT);
            } else {
                mService.get().mWakeLock.acquire(30000);
                mHandler.sendEmptyMessage(TRACK_ENDED);
                mHandler.sendEmptyMessage(RELEASE_WAKELOCK);
            }
        }
    }

    private static final class ServiceStub extends ITimberService.Stub {

        private final WeakReference<MusicService> mService;

        private ServiceStub(final MusicService service) {
            mService = new WeakReference<MusicService>(service);
        }


        @Override
        public void openFile(final String path) throws RemoteException {
            mService.get().openFile(path);
        }

        @Override
        public void open(final long[] list, final int position, long sourceId, int sourceType)
                throws RemoteException {
            mService.get().open(list, position, sourceId, IdType.getTypeById(sourceType));
        }

        @Override
        public void stop() throws RemoteException {
            mService.get().stop();
        }

        @Override
        public void pause() throws RemoteException {
            mService.get().pause();
        }


        @Override
        public void play() throws RemoteException {
            mService.get().play();
        }

        @Override
        public void prev(boolean forcePrevious) throws RemoteException {
            mService.get().prev(forcePrevious);
        }

        @Override
        public void next() throws RemoteException {
            mService.get().gotoNext(true);
        }

        @Override
        public void enqueue(final long[] list, final int action, long sourceId, int sourceType)
                throws RemoteException {
            mService.get().enqueue(list, action, sourceId, IdType.getTypeById(sourceType));
        }

        @Override
        public void moveQueueItem(final int from, final int to) throws RemoteException {
            mService.get().moveQueueItem(from, to);
        }

        @Override
        public void refresh() throws RemoteException {
            mService.get().refresh();
        }

        @Override
        public void playlistChanged() throws RemoteException {
            mService.get().playlistChanged();
        }

        @Override
        public boolean isPlaying() throws RemoteException {
            return mService.get().isPlaying();
        }

        @Override
        public long[] getQueue() throws RemoteException {
            return mService.get().getQueue();
        }

        @Override
        public long getQueueItemAtPosition(int position) throws RemoteException {
            return mService.get().getQueueItemAtPosition(position);
        }

        @Override
        public int getQueueSize() throws RemoteException {
            return mService.get().getQueueSize();
        }

        @Override
        public int getQueueHistoryPosition(int position) throws RemoteException {
            return mService.get().getQueueHistoryPosition(position);
        }

        @Override
        public int getQueueHistorySize() throws RemoteException {
            return mService.get().getQueueHistorySize();
        }

        @Override
        public int[] getQueueHistoryList() throws RemoteException {
            return mService.get().getQueueHistoryList();
        }

        @Override
        public long duration() throws RemoteException {
            return mService.get().duration();
        }

        @Override
        public long position() throws RemoteException {
            return mService.get().position();
        }

        @Override
        public long seek(final long position) throws RemoteException {
            return mService.get().seek(position);
        }

        @Override
        public void seekRelative(final long deltaInMs) throws RemoteException {
            mService.get().seekRelative(deltaInMs);
        }

        @Override
        public long getAudioId() throws RemoteException {
            return mService.get().getAudioId();
        }

        @Override
        public MusicPlaybackTrack getCurrentTrack() throws RemoteException {
            return mService.get().getCurrentTrack();
        }

        @Override
        public MusicPlaybackTrack getTrack(int index) throws RemoteException {
            return mService.get().getTrack(index);
        }

        @Override
        public long getNextAudioId() throws RemoteException {
            return mService.get().getNextAudioId();
        }

        @Override
        public long getPreviousAudioId() throws RemoteException {
            return mService.get().getPreviousAudioId();
        }

        @Override
        public long getArtistId() throws RemoteException {
            return mService.get().getArtistId();
        }

        @Override
        public long getAlbumId() throws RemoteException {
            return mService.get().getAlbumId();
        }

        @Override
        public String getArtistName() throws RemoteException {
            return mService.get().getArtistName();
        }

        @Override
        public String getTrackName() throws RemoteException {
            return mService.get().getTrackName();
        }

        @Override
        public String getAlbumName() throws RemoteException {
            return mService.get().getAlbumName();
        }

        @Override
        public String getPath() throws RemoteException {
            return mService.get().getPath();
        }

        @Override
        public int getQueuePosition() throws RemoteException {
            return mService.get().getQueuePosition();
        }

        @Override
        public void setQueuePosition(final int index) throws RemoteException {
            mService.get().setQueuePosition(index);
        }

        @Override
        public int getShuffleMode() throws RemoteException {
            return mService.get().getShuffleMode();
        }

        @Override
        public void setShuffleMode(final int shufflemode) throws RemoteException {
            mService.get().setShuffleMode(shufflemode);
        }

        @Override
        public int getRepeatMode() throws RemoteException {
            return mService.get().getRepeatMode();
        }

        @Override
        public void setRepeatMode(final int repeatmode) throws RemoteException {
            mService.get().setRepeatMode(repeatmode);
        }

        @Override
        public int removeTracks(final int first, final int last) throws RemoteException {
            return mService.get().removeTracks(first, last);
        }


        @Override
        public int removeTrack(final long id) throws RemoteException {
            return mService.get().removeTrack(id);
        }


        @Override
        public boolean removeTrackAtPosition(final long id, final int position)
                throws RemoteException {
            return mService.get().removeTrackAtPosition(id, position);
        }


        @Override
        public int getMediaMountedCount() throws RemoteException {
            return mService.get().getMediaMountedCount();
        }


        @Override
        public int getAudioSessionId() throws RemoteException {
            return mService.get().getAudioSessionId();
        }

    }

    private class MediaStoreObserver extends ContentObserver implements Runnable {

        private static final long REFRESH_DELAY = 500;
        private Handler mHandler;

        public MediaStoreObserver(Handler handler) {
            super(handler);
            mHandler = handler;
        }

        @Override
        public void onChange(boolean selfChange) {


            mHandler.removeCallbacks(this);
            mHandler.postDelayed(this, REFRESH_DELAY);
        }

        @Override
        public void run() {

            Log.e("ELEVEN", "calling refresh!");
            refresh();
        }
    }
}


================================================
FILE: app/src/main/java/com/naman14/timber/TimberApp.java
================================================
/*
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the GNU General Public License v3
 *
 * This is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */

package com.naman14.timber;

import androidx.multidex.MultiDexApplication;

import com.afollestad.appthemeengine.ATE;
import com.naman14.timber.permissions.Nammu;
import com.naman14.timber.utils.PreferencesUtility;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.nostra13.universalimageloader.utils.L;

import java.io.IOException;
import java.io.InputStream;

public class TimberApp extends MultiDexApplication {

    private static TimberApp mInstance;

    public static synchronized TimberApp getInstance() {
        return mInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mInstance = this;

        ImageLoaderConfiguration localImageLoaderConfiguration = new ImageLoaderConfiguration.Builder(this).imageDownloader(new BaseImageDownloader(this) {
            PreferencesUtility prefs = PreferencesUtility.getInstance(TimberApp.this);

            @Override
            protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
                if (prefs.loadArtistAndAlbumImages())
                    return super.getStreamFromNetwork(imageUri, extra);
                throw new IOException();
            }
        }).build();

        ImageLoader.getInstance().init(localImageLoaderConfiguration);
        L.writeLogs(false);
        L.disableLogging();
        L.writeDebugLogs(false);
        Nammu.init(this);

        if (!ATE.config(this, "light_theme").isConfigured()) {
            ATE.config(this, "light_theme")
                    .activityTheme(R.style.AppThemeLight)
                    .primaryColorRes(R.color.colorPrimaryLightDefault)
                    .accentColorRes(R.color.colorAccentLightDefault)
                    .coloredNavigationBar(false)
                    .usingMaterialDialogs(true)
                    .commit();
        }
        if (!ATE.config(this, "dark_theme").isConfigured()) {
            ATE.config(this, "dark_theme")
                    .activityTheme(R.style.AppThemeDark)
                    .primaryColorRes(R.color.colorPrimaryDarkDefault)
                    .accentColorRes(R.color.colorAccentDarkDefault)
                    .coloredNavigationBar(false)
                    .usingMaterialDialogs(true)
                    .commit();
        }
        if (!ATE.config(this, "light_theme_notoolbar").isConfigured()) {
            ATE.config(this, "light_theme_notoolbar")
                    .activityTheme(R.style.AppThemeLight)
                    .coloredActionBar(false)
                    .primaryColorRes(R.color.colorPrimaryLightDefault)
                    .accentColorRes(R.color.colorAccentLightDefault)
                    .coloredNavigationBar(false)
                    .usingMaterialDialogs(true)
                    .commit();
        }
        if (!ATE.config(this, "dark_theme_notoolbar").isConfigured()) {
            ATE.config(this, "dark_theme_notoolbar")
                    .activityTheme(R.style.AppThemeDark)
                    .coloredActionBar(false)
                    .primaryColorRes(R.color.colorPrimaryDarkDefault)
                    .accentColorRes(R.color.colorAccentDarkDefault)
                    .coloredNavigationBar(true)
                    .usingMaterialDialogs(true)
                    .commit();
        }

    }


}


================================================
FILE: app/src/main/java/com/naman14/timber/WearBrowserService.java
================================================
/*
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the GNU General Public License v3
 *
 * This is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */

package com.naman14.timber;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.media.MediaDescription;
import android.media.browse.MediaBrowser;
import android.media.session.MediaSession;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.service.media.MediaBrowserService;
import androidx.annotation.Nullable;

import com.naman14.timber.dataloaders.AlbumLoader;
import com.naman14.timber.dataloaders.AlbumSongLoader;
import com.naman14.timber.dataloaders.ArtistAlbumLoader;
import com.naman14.timber.dataloaders.ArtistLoader;
import com.naman14.timber.dataloaders.ArtistSongLoader;
import com.naman14.timber.dataloaders.PlaylistLoader;
import com.naman14.timber.dataloaders.PlaylistSongLoader;
import com.naman14.timber.dataloaders.SongLoader;
import com.naman14.timber.models.Album;
import com.naman14.timber.models.Artist;
import com.naman14.timber.models.Playlist;
import com.naman14.timber.models.Song;
import com.naman14.timber.utils.TimberUtils;

import java.util.ArrayList;
import java.util.List;

@TargetApi(21)
public class WearBrowserService extends MediaBrowserService {

    public static final String MEDIA_ID_ROOT = "__ROOT__";
    public static final int TYPE_ARTIST = 0;
    public static final int TYPE_ALBUM = 1;
    public static final int TYPE_SONG = 2;
    public static final int TYPE_PLAYLIST = 3;
    public static final int TYPE_ARTIST_SONG_ALBUMS = 4;
    public static final int TYPE_ALBUM_SONGS = 5;
    public static final int TYPE_ARTIST_ALL_SONGS = 6;
    public static final int TYPE_PLAYLIST_ALL_SONGS = 7;

    MediaSession mSession;
    public static WearBrowserService sInstance;

    private Context mContext;
    private boolean mServiceStarted;

    public static WearBrowserService getInstance() {
        return sInstance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
        mContext = this;
        mSession = new MediaSession(this, "WearBrowserService");
        setSessionToken(mSession.getSessionToken());
        mSession.setCallback(new MediaSessionCallback());
        mSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);

    }

    @Override
    public int onStartCommand(Intent startIntent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceStarted = false;
        mSession.release();
    }

    @Override
    public void onLoadChildren(String parentId, Result<List<MediaBrowser.MediaItem>> result) {

        result.detach();
        loadChildren(parentId, result);

    }

    @Nullable
    @Override
    public BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) {
        return new BrowserRoot(MEDIA_ID_ROOT, null);
    }

    private final class MediaSessionCallback extends MediaSession.Callback {

        @Override
        public void onPlay() {
            setSessionActive();
        }

        @Override
        public void onSeekTo(long position) {

        }

        @Override
        public void onPlayFromMediaId(final String mediaId, Bundle extras) {
            long songId = Long.parseLong(mediaId);
            setSessionActive();
            MusicPlayer.playAll(mContext, new long[]{songId}, 0, -1, TimberUtils.IdType.NA, false);
        }

        @Override
        public void onPause() {

        }

        @Override
        public void onStop() {
            setSessionInactive();
        }

        @Override
        public void onSkipToNext() {

        }

        @Override
        public void onSkipToPrevious() {

        }

        @Override
        public void onFastForward() {

        }

        @Override
        public void onRewind() {

        }

        @Override
        public void onCustomAction(String action, Bundle extras) {

        }
    }

    private void setSessionActive() {
        if (!mServiceStarted) {
            startService(new Intent(getApplicationContext(), WearBrowserService.class));
            mServiceStarted = true;
        }

        if (!mSession.isActive()) {
            mSession.setActive(true);
        }
    }

    private void setSessionInactive() {
        if (mServiceStarted) {
            stopSelf();
            mServiceStarted = false;
        }

        if (mSession.isActive()) {
            mSession.setActive(false);
        }
    }

    private void addMediaRoots(List<MediaBrowser.MediaItem> mMediaRoot) {
        mMediaRoot.add(new MediaBrowser.MediaItem(
                new MediaDescription.Builder()
                        .setMediaId(Integer.toString(TYPE_ARTIST))
                        .setTitle(getString(R.string.artists))
                        .setIconUri(Uri.parse("android.resource://" +
                                "naman14.timber/drawable/ic_empty_music2"))
                        .setSubtitle(getString(R.string.artists))
                        .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
        ));

        mMediaRoot.add(new MediaBrowser.MediaItem(
                new MediaDescription.Builder()
                        .setMediaId(Integer.toString(TYPE_ALBUM))
                        .setTitle(getString(R.string.albums))
                        .setIconUri(Uri.parse("android.resource://" +
                                "naman14.timber/drawable/ic_empty_music2"))
                        .setSubtitle(getString(R.string.albums))
                        .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
        ));

        mMediaRoot.add(new MediaBrowser.MediaItem(
                new MediaDescription.Builder()
                        .setMediaId(Integer.toString(TYPE_SONG))
                        .setTitle(getString(R.string.songs))
                        .setIconUri(Uri.parse("android.resource://" +
                                "naman14.timber/drawable/ic_empty_music2"))
                        .setSubtitle(getString(R.string.songs))
                        .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
        ));


        mMediaRoot.add(new MediaBrowser.MediaItem(
                new MediaDescription.Builder()
                        .setMediaId(Integer.toString(TYPE_PLAYLIST))
                        .setTitle(getString(R.string.playlists))
                        .setIconUri(Uri.parse("android.resource://" +
                                "naman14.timber/drawable/ic_empty_music2"))
                        .setSubtitle(getString(R.string.playlists))
                        .build(), MediaBrowser.MediaItem.FLAG_BROWSABLE
        ));

    }


    private void loadChildren(final String parentId, final Result<List<MediaBrowser.MediaItem>> result) {

        final List<MediaBrowser.MediaItem> mediaItems = new ArrayList<>();

        new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(final Void... unused) {

                if (parentId.equals(MEDIA_ID_ROOT)) {
                    addMediaRoots(mediaItems);
                } else {
                    switch (Integer.parseInt(Character.toString(parentId.charAt(0)))) {
                        case TYPE_ARTIST:
                            List<Artist> artistList = ArtistLoader.getAllArtists(mContext);
                            for (Artist artist : artistList) {
                                String albumNmber = TimberUtils.makeLabel(mContext, R.plurals.Nalbums, artist.albumCount);
                                String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, artist.songCount);
                                fillMediaItems(mediaItems, Integer.toString(TYPE_ARTIST_SONG_ALBUMS) + Long.toString(artist.id), artist.name, Uri.parse("android.resource://" +
                                        "naman14.timber/drawable/ic_empty_music2"), TimberUtils.makeCombinedString(mContext, albumNmber, songCount), MediaBrowser.MediaItem.FLAG_BROWSABLE);
                            }
                            break;
                        case TYPE_ALBUM:
                            List<Album> albumList = AlbumLoader.getAllAlbums(mContext);
                            for (Album album : albumList) {
                                fillMediaItems(mediaItems, Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.id), album.title, TimberUtils.getAlbumArtUri(album.id), album.artistName, MediaBrowser.MediaItem.FLAG_BROWSABLE);
                            }
                            break;
                        case TYPE_SONG:
                            List<Song> songList = SongLoader.getAllSongs(mContext);
                            for (Song song : songList) {
                                fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.artistName, MediaBrowser.MediaItem.FLAG_PLAYABLE);
                            }
                            break;
                        case TYPE_ALBUM_SONGS:
                            List<Song> albumSongList = AlbumSongLoader.getSongsForAlbum(mContext, Long.parseLong(parentId.substring(1)));
                            for (Song song : albumSongList) {
                                fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.artistName, MediaBrowser.MediaItem.FLAG_PLAYABLE);
                            }
                            break;
                        case TYPE_ARTIST_SONG_ALBUMS:
                            fillMediaItems(mediaItems, Integer.toString(TYPE_ARTIST_ALL_SONGS) + Long.parseLong(parentId.substring(1)), "All songs", Uri.parse("android.resource://" +
                                    "naman14.timber/drawable/ic_empty_music2"), "All songs by artist", MediaBrowser.MediaItem.FLAG_BROWSABLE);
                            List<Album> artistAlbums = ArtistAlbumLoader.getAlbumsForArtist(mContext, Long.parseLong(parentId.substring(1)));
                            for (Album album : artistAlbums) {
                                String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, album.songCount);
                                fillMediaItems(mediaItems, Integer.toString(TYPE_ALBUM_SONGS) + Long.toString(album.id), album.title, TimberUtils.getAlbumArtUri(album.id), songCount, MediaBrowser.MediaItem.FLAG_BROWSABLE);

                            }
                            break;
                        case TYPE_ARTIST_ALL_SONGS:
                            List<Song> artistSongs = ArtistSongLoader.getSongsForArtist(mContext, Long.parseLong(parentId.substring(1)));
                            for (Song song : artistSongs) {
                                fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.albumName, MediaBrowser.MediaItem.FLAG_PLAYABLE);
                            }
                            break;
                        case TYPE_PLAYLIST:
                            List<Playlist> playlistList = PlaylistLoader.getPlaylists(mContext, false);
                            for (Playlist playlist : playlistList) {
                                String songCount = TimberUtils.makeLabel(mContext, R.plurals.Nsongs, playlist.songCount);
                                fillMediaItems(mediaItems, Integer.toString(TYPE_PLAYLIST_ALL_SONGS) + Long.toString(playlist.id), playlist.name,
                                        Uri.parse("android.resource://" +
                                                "naman14.timber/drawable/ic_empty_music2"), songCount, MediaBrowser.MediaItem.FLAG_BROWSABLE);
                            }
                            break;
                        case TYPE_PLAYLIST_ALL_SONGS:
                            List<Song> playlistSongs = PlaylistSongLoader.getSongsInPlaylist(mContext, Long.parseLong(parentId.substring(1)));
                            for (Song song : playlistSongs) {
                                fillMediaItems(mediaItems, String.valueOf(song.id), song.title, TimberUtils.getAlbumArtUri(song.albumId), song.albumName, MediaBrowser.MediaItem.FLAG_PLAYABLE);
                            }
                            break;

                    }
                }
                return null;
            }

            @Override
            protected void onPostExecute(Void aVoid) {
                result.sendResult(mediaItems);
            }
        }.execute();

    }

    private void fillMediaItems(List<MediaBrowser.MediaItem> mediaItems, String mediaId, String title, Uri icon, String subTitle, int playableOrBrowsable) {
        mediaItems.add(new MediaBrowser.MediaItem(
                new MediaDescription.Builder()
                        .setMediaId(mediaId)
                        .setTitle(title)
                        .setIconUri(icon)
                        .setSubtitle(subTitle)
                        .build(), playableOrBrowsable
        ));
    }

}


================================================
FILE: app/src/main/java/com/naman14/timber/activities/BaseActivity.java
================================================
/*
 * Copyright (C) 2012 Andrew Neal
 * Copyright (C) 2014 The CyanogenMod Project
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
 * or agreed to in writing, software distributed under the License is
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.naman14.timber.activities;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.media.AudioManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;

import com.afollestad.appthemeengine.ATE;
import com.afollestad.appthemeengine.ATEActivity;
import com.google.android.gms.cast.framework.CastButtonFactory;
import com.google.android.gms.cast.framework.CastContext;
import com.google.android.gms.cast.framework.CastSession;
import com.google.android.gms.cast.framework.Session;
import com.google.android.gms.cast.framework.SessionManager;
import com.google.android.gms.cast.framework.SessionManagerListener;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.naman14.timber.ITimberService;
import com.naman14.timber.MusicPlayer;
import com.naman14.timber.MusicService;
import com.naman14.timber.R;
import com.naman14.timber.cast.SimpleSessionManagerListener;
import com.naman14.timber.cast.WebServer;
import com.naman14.timber.listeners.MusicStateListener;
import com.naman14.timber.slidinguppanel.SlidingUpPanelLayout;
import com.naman14.timber.subfragments.QuickControlsFragment;
import com.naman14.timber.utils.Helpers;
import com.naman14.timber.utils.NavigationUtils;
import com.naman14.timber.utils.TimberUtils;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import static com.naman14.timber.MusicPlayer.mService;

public class BaseActivity extends ATEActivity implements ServiceConnection, MusicStateListener {

    private final ArrayList<MusicStateListener> mMusicStateListener = new ArrayList<>();
    private MusicPlayer.ServiceToken mToken;
    private PlaybackStatus mPlaybackStatus;

    private CastSession mCastSession;
    private SessionManager mSessionManager;
    private final SessionManagerListener mSessionManagerListener =
            new SessionManagerListenerImpl();
    private WebServer castServer;

    public boolean playServicesAvailable = false;

    private class SessionManagerListenerImpl extends SimpleSessionManagerListener {
        @Override
        public void onSessionStarting(Session session) {
            super.onSessionStarting(session);
            startCastServer();
        }

        @Override
        public void onSessionStarted(Session session, String sessionId) {
            invalidateOptionsMenu();
            mCastSession = mSessionManager.getCurrentCastSession();
            showCastMiniController();
        }
        @Override
        public void onSessionResumed(Session session, boolean wasSuspended) {
            invalidateOptionsMenu();
            mCastSession = mSessionManager.getCurrentCastSession();
        }
        @Override
        public void onSessionEnded(Session session, int error) {
            mCastSession = null;
            hideCastMiniController();
            stopCastServer();
        }

        @Override
        public void onSessionResuming(Session session, String s) {
            super.onSessionResuming(session, s);
            startCastServer();
        }

        @Override
        public void onSessionSuspended(Session session, int i) {
            super.onSessionSuspended(session, i);
            stopCastServer();
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mToken = MusicPlayer.bindToService(this, this);

        mPlaybackStatus = new PlaybackStatus(this);
        //make volume keys change multimedia volume even if music is not playing now
        setVolumeControlStream(AudioManager.STREAM_MUSIC);

        try {
            playServicesAvailable = GoogleApiAvailability
                    .getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS;
        } catch (Exception ignored) {

        }

        if (playServicesAvailable)
            initCast();
    }

    @Override
    protected void onStart() {
        super.onStart();

        final IntentFilter filter = new IntentFilter();
        // Play and pause changes
        filter.addAction(MusicService.PLAYSTATE_CHANGED);
        // Track changes
        filter.addAction(MusicService.META_CHANGED);
        // Update a list, probably the playlist fragment's
        filter.addAction(MusicService.REFRESH);
        // If a playlist has changed, notify us
        filter.addAction(MusicService.PLAYLIST_CHANGED);
        // If there is an error playing a track
        filter.addAction(MusicService.TRACK_ERROR);

        registerReceiver(mPlaybackStatus, filter);

    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    public void onResume() {
        if (playServicesAvailable) {
            mCastSession = mSessionManager.getCurrentCastSession();
            mSessionManager.addSessionManagerListener(mSessionManagerListener);
        }
        //For Android 8.0+: service may get destroyed if in background too long
        if(mService == null){
            mToken = MusicPlayer.bindToService(this, this);
        }
        onMetaChanged();
        super.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (playServicesAvailable) {
            mSessionManager.removeSessionManagerListener(mSessionManagerListener);
            mCastSession = null;
        }
    }

    @Override
    public void onServiceConnected(final ComponentName name, final IBinder service) {
        mService = ITimberService.Stub.asInterface(service);
        onMetaChanged();
    }


    private void initCast() {
        CastContext castContext = CastContext.getSharedInstance(this);
        mSessionManager = castContext.getSessionManager();
    }

    @Override
    public void onServiceDisconnected(final ComponentName name) {
        mService = null;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Unbind from the service
        if (mToken != null) {
            MusicPlayer.unbindFromService(mToken);
            mToken = null;
        }

        try {
            unregisterReceiver(mPlaybackStatus);
        } catch (final Throwable e) {
        }
        mMusicStateListener.clear();
    }

    @Override
    public void onMetaChanged() {
        // Let the listener know to the meta chnaged
        for (final MusicStateListener listener : mMusicStateListener) {
            if (listener != null) {
                listener.onMetaChanged();
            }
        }
    }

    @Override
    public void restartLoader() {
        // Let the listener know to update a list
        for (final MusicStateListener listener : mMusicStateListener) {
            if (listener != null) {
                listener.restartLoader();
            }
        }
    }

    @Override
    public void onPlaylistChanged() {
        // Let the listener know to update a list
        for (final MusicStateListener listener : mMusicStateListener) {
            if (listener != null) {
                listener.onPlaylistChanged();
            }
        }
    }

    public void setMusicStateListenerListener(final MusicStateListener status) {
        if (status == this) {
            throw new UnsupportedOperationException("Override the method, don't add a listener");
        }

        if (status != null) {
            mMusicStateListener.add(status);
        }
    }

    public void removeMusicStateListenerListener(final MusicStateListener status) {
        if (status != null) {
            mMusicStateListener.remove(status);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);

        getMenuInflater().inflate(R.menu.menu_cast, menu);

        if (playServicesAvailable) {
            CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                    menu,
                    R.id.media_route_menu_item);
        }

        if (!TimberUtils.hasEffectsPanel(BaseActivity.this)) {
            menu.removeItem(R.id.action_equalizer);
        }
        ATE.applyMenu(this, getATEKey(), menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                super.onBackPressed();
                return true;
            case R.id.action_settings:
                NavigationUtils.navigateToSettings(this);
                return true;
            case R.id.action_shuffle:
                Handler handler = new Handler();
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        MusicPlayer.shuffleAll(BaseActivity.this);
                    }
                }, 80);

                return true;
            case R.id.action_search:
                NavigationUtils.navigateToSearch(this);
                return true;
            case R.id.action_equalizer:
                NavigationUtils.navigateToEqualizer(this);
                return true;

        }
        return super.onOptionsItemSelected(item);
    }

    @Nullable
    @Override
    public String getATEKey() {
        return Helpers.getATEKey(this);
    }

    public void setPanelSlideListeners(SlidingUpPanelLayout panelLayout) {
        panelLayout.setPanelSlideListener(new SlidingUpPanelLayout.PanelSlideListener() {

            @Override
            public void onPanelSlide(View panel, float slideOffset) {
                View nowPlayingCard = QuickControlsFragment.topContainer;
                if (nowPlayingCard != null)
                    nowPlayingCard.setAlpha(1 - slideOffset);
            }

            @Override
            public void onPanelCollapsed(View panel) {
                View nowPlayingCard = QuickControlsFragment.topContainer;
                if (nowPlayingCard != null)
                    nowPlayingCard.setAlpha(1);
            }

            @Override
            public void onPanelExpanded(View panel) {
                View nowPlayingCard = QuickControlsFragment.topContainer;
                if (nowPlayingCard != null)
                    nowPlayingCard.setAlpha(0);
            }

            @Override
            public void onPanelAnchored(View panel) {

            }

            @Override
            public void onPanelHidden(View panel) {

            }
        });
    }

    private final static class PlaybackStatus extends BroadcastReceiver {

        private final WeakReference<BaseActivity> mReference;


        public PlaybackStatus(final BaseActivity activity) {
            mReference = new WeakReference<BaseActivity>(activity);
        }

        @Override
        public void onReceive(final Context context, final Intent intent) {
            final String action = intent.getAction();
            BaseActivity baseActivity = mReference.get();
            if (baseActivity != null) {
                if (action.equals(MusicService.META_CHANGED)) {
                    baseActivity.onMetaChanged();
                } else if (action.equals(MusicService.PLAYSTATE_CHANGED)) {
//                    baseActivity.mPlayPauseProgressButton.getPlayPauseButton().updateState();
                } else if (action.equals(MusicService.REFRESH)) {
                    baseActivity.restartLoader();
                } else if (action.equals(MusicService.PLAYLIST_CHANGED)) {
                    baseActivity.onPlaylistChanged();
                } else if (action.equals(MusicService.TRACK_ERROR)) {
                    final String errorMsg = context.getString(R.string.error_playing_track,
                            intent.getStringExtra(MusicService.TrackErrorExtra.TRACK_NAME));
                    Toast.makeText(baseActivity, errorMsg, Toast.LENGTH_SHORT).show();
                }
            }
        }
    }

    public class initQuickControls extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String... params) {
            QuickControlsFragment fragment1 = new QuickControlsFragment();
            FragmentManager fragmentManager1 = getSupportFragmentManager();
            fragmentManager1.beginTransaction()
                    .replace(R.id.quickcontrols_container, fragment1).commitAllowingStateLoss();
            return "Executed";
        }

        @Override
        protected void onPostExecute(String result) {
        }

        @Override
        protected void onPreExecute() {
        }
    }

    public void showCastMiniController() {
        //implement by overriding in activities
    }

    public void hideCastMiniController() {
        //implement by overriding in activities
    }

    public CastSession getCastSession() {
        return mCastSession;
    }

    private void startCastServer() {
        castServer = new WebServer(this);
        try {
            castServer.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void stopCastServer() {
        if (castServer != null) {
            castServer.stop();
        }
    }
}


================================================
FILE: app/src/main/java/com/naman14/timber/activities/BaseThemedActivity.java
================================================
package com.naman14.timber.activities;

import android.media.AudioManager;
import android.os.Bundle;
import androidx.annotation.Nullable;

import com.afollestad.appthemeengine.ATEActivity;
import com.naman14.timber.utils.Helpers;

/**
 * Created by naman on 31/12/15.
 */
public class BaseThemedActivity extends ATEActivity {

    @Nullable
    @Override
    public String getATEKey() {
        return Helpers.getATEKey(this);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //make volume keys change multimedia volume even if music is not playing now
        setVolumeControlStream(AudioManager.STREAM_MUSIC);
    }
}


================================================
FILE: app/src/main/java/com/naman14/timber/activities/DonateActivity.java
================================================
package com.naman14.timber.activities;

import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.anjlab.android.iab.v3.BillingProcessor;
import com.anjlab.android.iab.v3.SkuDetails;
import com.anjlab.android.iab.v3.TransactionDetails;
import com.naman14.timber.R;
import com.naman14.timber.utils.PreferencesUtility;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * Created by naman on 29/10/16.
 */
public class DonateActivity extends BaseThemedActivity implements BillingProcessor.IBillingHandler {

    private static final String DONATION_1 = "naman14.timber.donate_1";
    private static final String DONATION_2 = "naman14.timber.donate_2";
    private static final String DONATION_3 = "naman14.timber.donate_3";
    private static final String DONATION_5 = "naman14.timber.donate_5";
    private static final String DONATION_10 = "naman14.timber.donate_10";
    private static final String DONATION_20 = "naman14.timber.donate_20";


    private boolean readyToPurchase = false;
    BillingProcessor bp;

    private LinearLayout productListView;
    private ProgressBar progressBar;
    private TextView status;

    private String action = "support";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_donate);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setTitle("Support development");
        action = getIntent().getAction();

        productListView = (LinearLayout) findViewById(R.id.product_list);
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        status = (TextView) findViewById(R.id.donation_status);

        if (action != null && action.equals("restore")) {
            status.setText("Restoring purchases..");
        }

        bp = new BillingProcessor(this, getString(R.string.play_billing_license_key), this);

    }

    @Override
    public void onBillingInitialized() {
        readyToPurchase = true;
        checkStatus();
        if (!(action != null && action.equals("restore")))
            getProducts();
    }

    @Override
    public void onProductPurchased(String productId, TransactionDetails details) {
        checkStatus();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(DonateActivity.this, "Thanks for your support!", Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onBillingError(int errorCode, Throwable error) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(DonateActivity.this, "Unable to process purchase", Toast.LENGTH_SHORT).show();
            }
        });

    }

    @Override
    public void onPurchaseHistoryRestored() {

    }

    @Override
    public void onDestroy() {
        if (bp != null)
            bp.release();
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (!bp.handleActivityResult(requestCode, resultCode, data))
            super.onActivityResult(requestCode, resultCode, data);
    }

    private void checkStatus() {
        new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... voids) {
                List<String> owned = bp.listOwnedProducts();
                return owned != null && owned.size() != 0;
            }

            @Override
            protected void onPostExecute(Boolean b) {
                super.onPostExecute(b);
                if (b) {
                    PreferencesUtility.getInstance(DonateActivity.this).setFullUnlocked(true);
                    status.setText("Thanks for your support!");
                    if (action!=null && action.equals("restore")) {
                        status.setText("Your purchases has been restored. Thanks for your support");
                        progressBar.setVisibility(View.GONE);
                    }
                    if (getSupportActionBar() != null)
                        getSupportActionBar().setTitle("Support development");
                } else {
                    if (action!=null && action.equals("restore")) {
                        status.setText("No previous purchase found");
                        getProducts();
                    }
                }
            }
        }.execute();
    }

    private void getProducts() {

        new AsyncTask<Void, Void, List<SkuDetails>>() {
            @Override
            protected List<SkuDetails> doInBackground(Void... voids) {

                ArrayList<String> products = new ArrayList<>();

                products.add(DONATION_1);
                products.add(DONATION_2);
                products.add(DONATION_3);
                products.add(DONATION_5);
                products.add(DONATION_10);
                products.add(DONATION_20);

                return bp.getPurchaseListingDetails(products);
            }

            @Override
            protected void onPostExecute(List<SkuDetails> productList) {
                super.onPostExecute(productList);

                if (productList == null)
                    return;

                Collections.sort(productList, new Comparator<SkuDetails>() {
                    @Override
                    public int compare(SkuDetails skuDetails, SkuDetails t1) {
                        if (skuDetails.priceValue >= t1.priceValue)
                            return 1;
                        else if (skuDetails.priceValue <= t1.priceValue)
                            return -1;
                        else return 0;
                    }
                });
                for (int i = 0; i < productList.size(); i++) {
                    final SkuDetails product = productList.get(i);
                    View rootView = LayoutInflater.from(DonateActivity.this).inflate(R.layout.item_donate_product, productListView, false);

                    TextView detail = (TextView) rootView.findViewById(R.id.product_detail);
                    detail.setText(product.priceText);

                    rootView.findViewById(R.id.btn_donate).setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            if (readyToPurchase)
                                bp.purchase(DonateActivity.this, product.productId);
                            else
                                Toast.makeText(DonateActivity.this, "Unable to initiate purchase", Toast.LENGTH_SHORT).show();
                        }
                    });

                    productListView.addView(rootView);

                }
                progressBar.setVisibility(View.GONE);
            }
        }.execute();
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                super.onBackPressed();
                return true;
            default:
                break;
        }
        return super.onOptionsItemSelected(item);
    }

}


================================================
FILE: app/src/main/java/com/naman14/timber/activities/MainActivity.java
================================================
/*
 * Copyright (C) 2015 Naman Dwivedi
 *
 * Licensed under the GNU General Public License v3
 *
 * This is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 */

package com.naman14.timber.activities;

import android.Manifest;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import com.afollestad.appthemeengine.customizers.ATEActivityThemeCustomizer;
import com.anjlab.android.iab.v3.BillingProcessor;
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity;
import com.naman14.timber.MusicPlayer;
import com.naman14.timber.R;
import com.naman14.timber.cast.ExpandedControlsActivity;
import com.naman14.timber.fragments.AlbumDetailFragment;
import com.naman14.timber.fragments.ArtistDetailFragment;
import com.naman14.timber.fragments.FoldersFragment;
import com.naman14.timber.fragments.MainFragment;
import com.naman14.timber.fragments.PlaylistFragment;
import com.naman14.timber.fragments.QueueFragment;
import com.naman14.timber.permissions.Nammu;
import com.naman14.timber.permissions.PermissionCallback;
import com.naman14.timber.slidinguppanel.SlidingUpPanelLayout;
import com.naman14.timber.subfragments.LyricsFragment;
import com.naman14.timber.utils.Constants;
import com.naman14.timber.utils.Helpers;
import com.naman14.timber.utils.NavigationUtils;
import com.naman14.timber.utils.TimberUtils;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;

import java.util.HashMap;
import java.util.Map;

public class MainActivity extends BaseActivity implements ATEActivityThemeCustomizer {

    private SlidingUpPanelLayout panelLayout;
    private NavigationView navigationView;
    private TextView songtitle, songartist;
    private ImageView albumart;
    private String action;
    private Map<String, Runnable> navigationMap = new HashMap<String, Runnable>();
    private Handler navDrawerRunnable = new Handler();
    private Runnable runnable;
    private DrawerLayout mDrawerLayout;
    private boolean isDarkTheme;

    private Runnable navigateLibrary = new Runnable() {
        public void run() {
            navigationView.getMenu().findItem(R.id.nav_library).setChecked(true);
            Fragment fragment = new MainFragment();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.fragment_container, fragment).commitAllowingStateLoss();

        }
    };

    private Runnable navigatePlaylist = new Runnable() {
        public void run() {
            navigationView.getMenu().findItem(R.id.nav_playlists).setChecked(true);
            Fragment fragment = new PlaylistFragment();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.hide(getSupportFragmentManager().findFragmentById(R.id.fragment_container));
            transaction.replace(R.id.fragment_container, fragment).commit();

        }
    };

    private Runnable navigateFolder = new Runnable() {
        public void run() {
            navigationView.getMenu().findItem(R.id.nav_folders).setChecked(true);
            Fragment fragment = new FoldersFragment();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.hide(getSupportFragmentManager().findFragmentById(R.id.fragment_container));
            transaction.replace(R.id.fragment_container, fragment).commit();

        }
    };

    private Runnable navigateQueue = new Runnable() {
        public void run() {
            navigationView.getMenu().findItem(R.id.nav_queue).setChecked(true);
            Fragment fragment = new QueueFragment();
            FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
            transaction.hide(getSupportFragmentManager().findFragmentById(R.id.fragment_container));
            transaction.replace(R.id.fragment_container, fragment).commit();

        }
    };

    private Runnable navigateAlbum = new Runnable() {
        public void run() {
            long albumID = getIntent().getExtras().getLong(Constants.ALBUM_ID);
            Fragment fragment = AlbumDetailFragment.newInstance(albumID, false, null);
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.fragment_container, fragment).commit();
        }
    };

    private Runnable navigateArtist = new Runnable() {
        public void run() {
            long artistID = getIntent().getExtras().getLong(Constants.ARTIST_ID);
            Fragment fragment = ArtistDetailFragment.newInstance(artistID, false, null);
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.fragment_container, fragment).commit();
        }
    };

    private Runnable navigateLyrics = new Runnable() {
        public void run() {
            Fragment fragment = new LyricsFragment();
            FragmentManager fragmentManager = getSupportFragmentManager();
            fragmentManager.beginTransaction()
                    .replace(R.id.fragment_container, fragment).commit();
        }
    };

    private Runnable navigateNowplaying = new Runnable() {
        public void run() {
            navigateLibrary.run();
            startActivity(new Intent(MainActivity.this, NowPlayingActivity.class));
        }
    };

    private final PermissionCallback permissionReadstorageCallback = new PermissionCallback() {
        @Override
        public void permissionGranted() {
            loadEverything();
        }

        @Override
        public void permissionRefused() {
            finish();
        }
    };


    @Override
    public void onCreate(Bundle savedInstanceState) {

        action = getIntent().getAction();

        isDarkTheme = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false);

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        navigationMap.put(Constants.NAVIGATE_LIBRARY, navigateLibrary);
        navigationMap.put(Constants.NAVIGATE_PLAYLIST, navigatePlaylist);
        navigationMap.put(Constants.NAVIGATE_QUEUE, navigateQueue);
        navigationMap.put(Constants.NAVIGATE_NOWPLAYING, navigateNowplaying);
        navigationMap.put(Constants.NAVIGATE_ALBUM, navigateAlbum);
        navigationMap.put(Constants.NAVIGATE_ARTIST, navigateArtist);
        navigationMap.put(Constants.NAVIGATE_LYRICS, navigateLyrics);

        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        panelLayout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);

        navigationView = (NavigationView) findViewById(R.id.nav_view);
        View header = navigationView.inflateHeaderView(R.layout.nav_header);

        albumart = (ImageView) header.findViewById(R.id.album_art);
        songtitle = (TextView) header.findViewById(R.id.song_title);
        songartist = (TextView) header.findViewById(R.id.song_artist);

        setPanelSlideListeners(panelLayout);

        navDrawerRunnable.postDelayed(new Runnable() {
            @Override
            public void run() {
                setupDrawerContent(navigationView);
                setupNavigationIcons(navigationView);
            }
        }, 700);


        if (TimberUtils.isMarshmallow()) {
            checkPermissionAndThenLoad();
            //checkWritePermissions();
        } else {
            loadEverything();
        }

        addBackstackListener();

        if(Intent.ACTION_VIEW.equals(action)) {
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    MusicPlayer.clearQueue();
                    MusicPlayer.openFile(getIntent().getData().getPath());
                    MusicPlayer.playOrPause();
                    navigateNowplaying.run();
                }
            }, 350);
        }

        if (!panelLayout.isPanelHidden() && MusicPlayer.getTrackName() == null ) {
            panelLayout.hidePanel();
        }

        if (playServicesAvailable) {

            final FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
                    FrameLayout.LayoutParams.WRAP_CONTENT,
                    FrameLayout.LayoutParams.WRAP_CONTENT);
            params.gravity = Gravity.BOTTOM;

            FrameLayout contentRoot = findViewById(R.id.content_root);
            contentRoot.addView(LayoutInflater.from(this)
                    .inflate(R.layout.fragment_cast_mini_controller, null), params);

            findViewById(R.id.castMiniController).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    startActivity(new Intent(MainActivity.this, ExpandedControllerActivity.class));
                }
            });
        }

    }

    private void loadEverything() {
        Runnable navigation = navigationMap.get(action);
        if (navigation != null) {
            navigation.run();
        } else {
            navigateLibrary.run();
        }

        new initQuickControls().execute("");
    }

    private void checkPermissionAndThenLoad() {
        //check for permission
        if (Nammu.checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE) && Nammu.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            loadEverything();
        } else {
            if (Nammu.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
                Snackbar.make(panelLayout, "Timber will need to read external storage to display songs on your device.",
                        Snackbar.LENGTH_INDEFINITE)
                        .setAction("OK", new View.OnClickListener() {
                            @Override
                            public void onClick(View view) {
                                Nammu.askForPermission(MainActivity.this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, permissionReadstorageCallback);
                            }
                        }).show();
            } else {
                Nammu.askForPermission(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, permissionReadstorageCallback);
            }
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home: {
                if (isNavigatingMain()) {
                    mDrawerLayout.openDrawer(GravityCompat.START);
                } else super.onBackPressed();
                return true;
            }
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onBackPressed() {
        if (panelLayout.isPanelExpanded()) {
            panelLayout.collapsePanel();
        } else if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
            mDrawerLayout.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    private void setupDrawerContent(NavigationView navigationView) {
        navigationView.setNavigationItemSelectedListener(
                new NavigationView.OnNaviga
Download .txt
gitextract_5h1zqhrq/

├── .gitignore
├── .travis.yml
├── Changelog.md
├── README.md
├── app/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── naman14/
│       │               └── timber/
│       │                   └── ApplicationTest.java
│       └── main/
│           ├── AndroidManifest.xml
│           ├── aidl/
│           │   └── com/
│           │       └── naman14/
│           │           └── timber/
│           │               ├── ITimberService.aidl
│           │               └── helpers/
│           │                   └── MusicPlaybackTrack.aidl
│           ├── java/
│           │   └── com/
│           │       └── naman14/
│           │           └── timber/
│           │               ├── MusicPlayer.java
│           │               ├── MusicService.java
│           │               ├── TimberApp.java
│           │               ├── WearBrowserService.java
│           │               ├── activities/
│           │               │   ├── BaseActivity.java
│           │               │   ├── BaseThemedActivity.java
│           │               │   ├── DonateActivity.java
│           │               │   ├── MainActivity.java
│           │               │   ├── NowPlayingActivity.java
│           │               │   ├── PlaylistDetailActivity.java
│           │               │   ├── SearchActivity.java
│           │               │   └── SettingsActivity.java
│           │               ├── adapters/
│           │               │   ├── AlbumAdapter.java
│           │               │   ├── AlbumSongsAdapter.java
│           │               │   ├── ArtistAdapter.java
│           │               │   ├── ArtistAlbumAdapter.java
│           │               │   ├── ArtistSongAdapter.java
│           │               │   ├── BaseQueueAdapter.java
│           │               │   ├── BaseSongAdapter.java
│           │               │   ├── FolderAdapter.java
│           │               │   ├── PlayingQueueAdapter.java
│           │               │   ├── PlaylistAdapter.java
│           │               │   ├── SearchAdapter.java
│           │               │   ├── SlidingQueueAdapter.java
│           │               │   └── SongsListAdapter.java
│           │               ├── cast/
│           │               │   ├── CastOptionsProvider.java
│           │               │   ├── ExpandedControlsActivity.java
│           │               │   ├── SimpleSessionManagerListener.java
│           │               │   ├── TimberCastHelper.java
│           │               │   └── WebServer.java
│           │               ├── dataloaders/
│           │               │   ├── AlbumLoader.java
│           │               │   ├── AlbumSongLoader.java
│           │               │   ├── ArtistAlbumLoader.java
│           │               │   ├── ArtistLoader.java
│           │               │   ├── ArtistSongLoader.java
│           │               │   ├── FolderLoader.java
│           │               │   ├── LastAddedLoader.java
│           │               │   ├── NowPlayingCursor.java
│           │               │   ├── PlaylistLoader.java
│           │               │   ├── PlaylistSongLoader.java
│           │               │   ├── QueueLoader.java
│           │               │   ├── SongLoader.java
│           │               │   ├── SortedCursor.java
│           │               │   └── TopTracksLoader.java
│           │               ├── dialogs/
│           │               │   ├── AddPlaylistDialog.java
│           │               │   ├── CreatePlaylistDialog.java
│           │               │   ├── LastFmLoginDialog.java
│           │               │   └── StorageSelectDialog.java
│           │               ├── fragments/
│           │               │   ├── AlbumDetailFragment.java
│           │               │   ├── AlbumFragment.java
│           │               │   ├── ArtistBioFragment.java
│           │               │   ├── ArtistDetailFragment.java
│           │               │   ├── ArtistFragment.java
│           │               │   ├── ArtistMusicFragment.java
│           │               │   ├── FoldersFragment.java
│           │               │   ├── MainFragment.java
│           │               │   ├── PlaylistFragment.java
│           │               │   ├── QueueFragment.java
│           │               │   ├── SettingsFragment.java
│           │               │   ├── SimilarArtistFragment.java
│           │               │   └── SongsFragment.java
│           │               ├── helpers/
│           │               │   ├── MediaButtonIntentReceiver.java
│           │               │   └── MusicPlaybackTrack.java
│           │               ├── lastfmapi/
│           │               │   ├── LastFmClient.java
│           │               │   ├── LastFmRestService.java
│           │               │   ├── LastFmUserRestService.java
│           │               │   ├── RestServiceFactory.java
│           │               │   ├── callbacks/
│           │               │   │   ├── AlbumInfoListener.java
│           │               │   │   ├── ArtistInfoListener.java
│           │               │   │   └── UserListener.java
│           │               │   └── models/
│           │               │       ├── AlbumBio.java
│           │               │       ├── AlbumInfo.java
│           │               │       ├── AlbumQuery.java
│           │               │       ├── AlbumTracks.java
│           │               │       ├── ArtistBio.java
│           │               │       ├── ArtistInfo.java
│           │               │       ├── ArtistQuery.java
│           │               │       ├── ArtistTag.java
│           │               │       ├── Artwork.java
│           │               │       ├── LastfmAlbum.java
│           │               │       ├── LastfmArtist.java
│           │               │       ├── LastfmUserSession.java
│           │               │       ├── ScrobbleInfo.java
│           │               │       ├── ScrobbleQuery.java
│           │               │       ├── UserLoginInfo.java
│           │               │       └── UserLoginQuery.java
│           │               ├── listeners/
│           │               │   ├── MusicStateListener.java
│           │               │   └── SimplelTransitionListener.java
│           │               ├── models/
│           │               │   ├── Album.java
│           │               │   ├── Artist.java
│           │               │   ├── Playlist.java
│           │               │   └── Song.java
│           │               ├── nowplaying/
│           │               │   ├── BaseNowplayingFragment.java
│           │               │   ├── Timber1.java
│           │               │   ├── Timber2.java
│           │               │   ├── Timber3.java
│           │               │   ├── Timber4.java
│           │               │   ├── Timber5.java
│           │               │   └── Timber6.java
│           │               ├── permissions/
│           │               │   ├── Nammu.java
│           │               │   ├── PermissionCallback.java
│           │               │   ├── PermissionListener.java
│           │               │   └── PermissionRequest.java
│           │               ├── provider/
│           │               │   ├── MusicDB.java
│           │               │   ├── MusicPlaybackState.java
│           │               │   ├── RecentStore.java
│           │               │   ├── SearchHistory.java
│           │               │   └── SongPlayCount.java
│           │               ├── slidinguppanel/
│           │               │   ├── SlidingUpPanelLayout.java
│           │               │   └── ViewDragHelper.java
│           │               ├── subfragments/
│           │               │   ├── ArtistTagFragment.java
│           │               │   ├── LyricsFragment.java
│           │               │   ├── PlaylistPagerFragment.java
│           │               │   ├── QuickControlsFragment.java
│           │               │   ├── StyleSelectorFragment.java
│           │               │   └── SubStyleSelectorFragment.java
│           │               ├── timely/
│           │               │   ├── TimelyView.java
│           │               │   ├── animation/
│           │               │   │   └── TimelyEvaluator.java
│           │               │   └── model/
│           │               │       ├── NumberUtils.java
│           │               │       ├── core/
│           │               │       │   └── Figure.java
│           │               │       └── number/
│           │               │           ├── Eight.java
│           │               │           ├── Five.java
│           │               │           ├── Four.java
│           │               │           ├── Nine.java
│           │               │           ├── Null.java
│           │               │           ├── One.java
│           │               │           ├── Seven.java
│           │               │           ├── Six.java
│           │               │           ├── Three.java
│           │               │           ├── Two.java
│           │               │           └── Zero.java
│           │               ├── transition/
│           │               │   └── PlayTransition.java
│           │               ├── utils/
│           │               │   ├── ATEUtils.java
│           │               │   ├── Constants.java
│           │               │   ├── FabAnimationUtils.java
│           │               │   ├── Helpers.java
│           │               │   ├── ImageUtils.java
│           │               │   ├── LyricsExtractor.java
│           │               │   ├── LyricsLoader.java
│           │               │   ├── NavigationUtils.java
│           │               │   ├── PreferencesUtility.java
│           │               │   ├── SlideTrackSwitcher.java
│           │               │   ├── SortOrder.java
│           │               │   └── TimberUtils.java
│           │               └── widgets/
│           │                   ├── BaseRecyclerView.java
│           │                   ├── BubbleTextGetter.java
│           │                   ├── CircleImageView.java
│           │                   ├── CircularSeekBar.java
│           │                   ├── DividerItemDecoration.java
│           │                   ├── DragSortRecycler.java
│           │                   ├── FastScroller.java
│           │                   ├── MultiViewPager.java
│           │                   ├── MusicVisualizer.java
│           │                   ├── PlayPauseButton.java
│           │                   ├── PlayPauseDrawable.java
│           │                   ├── PopupImageView.java
│           │                   ├── SquareImageView.java
│           │                   ├── TextDrawable.java
│           │                   ├── ThemedPreferenceCategory.java
│           │                   └── desktop/
│           │                       ├── BaseWidget.java
│           │                       ├── SmallWidget.java
│           │                       ├── StandardWidget.java
│           │                       └── WhiteWidget.java
│           └── res/
│               ├── anim/
│               │   ├── activity_fade_in.xml
│               │   ├── activity_fade_out.xml
│               │   ├── design_fab_out.xml
│               │   ├── scale.xml
│               │   ├── slide_in_from_bottom.xml
│               │   ├── slide_in_from_left.xml
│               │   ├── slide_in_from_right.xml
│               │   ├── slide_out_to_bottom.xml
│               │   ├── slide_out_to_left.xml
│               │   └── slide_out_to_right.xml
│               ├── color/
│               │   ├── state_selector_black.xml
│               │   ├── state_selector_dark.xml
│               │   └── state_selector_light.xml
│               ├── drawable/
│               │   ├── bg_gradient.xml
│               │   ├── ic_file_music_dark.xml
│               │   ├── ic_folder_open_black_24dp.xml
│               │   ├── ic_folder_open_white_24dp.xml
│               │   ├── ic_folder_parent_dark.xml
│               │   ├── ic_menu.xml
│               │   ├── ic_timer_wait.xml
│               │   ├── item_divider_black.xml
│               │   ├── item_divider_white.xml
│               │   ├── progress_drawable.xml
│               │   ├── progress_drawable_black.xml
│               │   ├── progress_drawable_dark.xml
│               │   ├── progress_drawable_withbackground.xml
│               │   ├── progress_drawable_withbackground_black.xml
│               │   ├── progress_drawable_withbackground_dark.xml
│               │   ├── recyclerview_fastscroller_bubble.xml
│               │   ├── recyclerview_fastscroller_handle.xml
│               │   └── selectable_item_background.xml
│               ├── drawable-xhdpi/
│               │   ├── above_shadow.xml
│               │   └── below_shadow.xml
│               ├── layout/
│               │   ├── activity_donate.xml
│               │   ├── activity_main.xml
│               │   ├── activity_nowplaying.xml
│               │   ├── activity_playlist_detail.xml
│               │   ├── activity_search.xml
│               │   ├── activity_settings.xml
│               │   ├── artist_detail_albums_header.xml
│               │   ├── bottom_nowplaying_card.xml
│               │   ├── dialog_lastfm_login.xml
│               │   ├── empty_view.xml
│               │   ├── fragment_album_detail.xml
│               │   ├── fragment_artist_bio.xml
│               │   ├── fragment_artist_detail.xml
│               │   ├── fragment_artist_music.xml
│               │   ├── fragment_cast_mini_controller.xml
│               │   ├── fragment_folders.xml
│               │   ├── fragment_lyrics.xml
│               │   ├── fragment_main.xml
│               │   ├── fragment_playback_controls.xml
│               │   ├── fragment_playlist.xml
│               │   ├── fragment_playlist_pager.xml
│               │   ├── fragment_queue.xml
│               │   ├── fragment_recyclerview.xml
│               │   ├── fragment_similar_artists.xml
│               │   ├── fragment_style_selector.xml
│               │   ├── fragment_style_selector_pager.xml
│               │   ├── fragment_timber1.xml
│               │   ├── fragment_timber2.xml
│               │   ├── fragment_timber3.xml
│               │   ├── fragment_timber4.xml
│               │   ├── fragment_timber5.xml
│               │   ├── fragment_timber6.xml
│               │   ├── include_list_viewpager.xml
│               │   ├── item_album_grid.xml
│               │   ├── item_album_list.xml
│               │   ├── item_album_search.xml
│               │   ├── item_album_song.xml
│               │   ├── item_artist.xml
│               │   ├── item_artist_album.xml
│               │   ├── item_artist_grid.xml
│               │   ├── item_artist_song.xml
│               │   ├── item_donate_product.xml
│               │   ├── item_folder_list.xml
│               │   ├── item_playing_queue.xml
│               │   ├── item_song.xml
│               │   ├── item_song_playlist.xml
│               │   ├── item_song_sliding_queue.xml
│               │   ├── item_song_timber1.xml
│               │   ├── layout_artist_tag.xml
│               │   ├── layout_dummy_header_artist.xml
│               │   ├── nav_header.xml
│               │   ├── recyclerview_fastscroller.xml
│               │   ├── search_section_header.xml
│               │   ├── song_elapsedtime.xml
│               │   ├── widget_small.xml
│               │   ├── widget_standard.xml
│               │   └── widget_white.xml
│               ├── menu/
│               │   ├── album_detail.xml
│               │   ├── album_sort_by.xml
│               │   ├── artist_detail.xml
│               │   ├── artist_sort_by.xml
│               │   ├── drawer_view.xml
│               │   ├── menu_cast.xml
│               │   ├── menu_expanded_controller.xml
│               │   ├── menu_folders.xml
│               │   ├── menu_main.xml
│               │   ├── menu_playlist.xml
│               │   ├── menu_playlist_detail.xml
│               │   ├── menu_search.xml
│               │   ├── menu_show_as.xml
│               │   ├── now_playing.xml
│               │   ├── popup_playing_queue.xml
│               │   ├── popup_song.xml
│               │   └── song_sort_by.xml
│               ├── transition/
│               │   ├── image_transform.xml
│               │   └── play_transition.xml
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── plurals.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               ├── values-da/
│               │   └── strings.xml
│               ├── values-de/
│               │   └── strings.xml
│               ├── values-es/
│               │   └── strings.xml
│               ├── values-fr/
│               │   └── strings.xml
│               ├── values-id/
│               │   └── strings.xml
│               ├── values-it/
│               │   └── strings.xml
│               ├── values-ko/
│               │   └── strings.xml
│               ├── values-nb-rNO/
│               │   └── strings.xml
│               ├── values-pt/
│               │   └── strings.xml
│               ├── values-ru/
│               │   └── strings.xml
│               ├── values-tr/
│               │   └── strings.xml
│               ├── values-v19/
│               │   └── styles.xml
│               ├── values-v21/
│               │   ├── dimens.xml
│               │   └── styles.xml
│               ├── values-w820dp/
│               │   └── dimens.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   ├── preferences.xml
│                   ├── widget_small.xml
│                   ├── widget_standard.xml
│                   └── widget_white.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── mock/
│   ├── mock-google-services.json
│   └── mock-secret.xml
├── mock.gradle
└── settings.gradle
Download .txt
SYMBOL INDEX (1896 symbols across 164 files)

FILE: app/src/androidTest/java/com/naman14/timber/ApplicationTest.java
  class ApplicationTest (line 9) | public class ApplicationTest extends ApplicationTestCase<Application> {
    method ApplicationTest (line 10) | public ApplicationTest() {

FILE: app/src/main/java/com/naman14/timber/MusicPlayer.java
  class MusicPlayer (line 42) | public class MusicPlayer {
    method bindToService (line 54) | public static final ServiceToken bindToService(final Context context,
    method unbindFromService (line 73) | public static void unbindFromService(final ServiceToken token) {
    method isPlaybackServiceConnected (line 88) | public static final boolean isPlaybackServiceConnected() {
    method next (line 92) | public static void next() {
    method initPlaybackServiceWithSettings (line 101) | public static void initPlaybackServiceWithSettings(final Context conte...
    method asyncNext (line 105) | public static void asyncNext(final Context context) {
    method previous (line 111) | public static void previous(final Context context, final boolean force) {
    method playOrPause (line 121) | public static void playOrPause() {
    method cycleRepeat (line 134) | public static void cycleRepeat() {
    method cycleShuffle (line 156) | public static void cycleShuffle() {
    method isPlaying (line 180) | public static final boolean isPlaying() {
    method getShuffleMode (line 190) | public static final int getShuffleMode() {
    method setShuffleMode (line 200) | public static void setShuffleMode(int mode) {
    method getRepeatMode (line 210) | public static final int getRepeatMode() {
    method getTrackName (line 220) | public static final String getTrackName() {
    method getArtistName (line 230) | public static final String getArtistName() {
    method getAlbumName (line 240) | public static final String getAlbumName() {
    method getCurrentAlbumId (line 250) | public static final long getCurrentAlbumId() {
    method getCurrentAudioId (line 260) | public static final long getCurrentAudioId() {
    method getCurrentTrack (line 270) | public static final MusicPlaybackTrack getCurrentTrack() {
    method getTrack (line 280) | public static final MusicPlaybackTrack getTrack(int index) {
    method getNextAudioId (line 290) | public static final long getNextAudioId() {
    method getPreviousAudioId (line 300) | public static final long getPreviousAudioId() {
    method getCurrentArtistId (line 310) | public static final long getCurrentArtistId() {
    method getAudioSessionId (line 320) | public static final int getAudioSessionId() {
    method getQueue (line 330) | public static final long[] getQueue() {
    method getQueueItemAtPosition (line 341) | public static final long getQueueItemAtPosition(int position) {
    method getQueueSize (line 352) | public static final int getQueueSize() {
    method getQueuePosition (line 363) | public static final int getQueuePosition() {
    method setQueuePosition (line 373) | public static void setQueuePosition(final int position) {
    method refresh (line 382) | public static void refresh() {
    method getQueueHistorySize (line 391) | public static final int getQueueHistorySize() {
    method getQueueHistoryPosition (line 401) | public static final int getQueueHistoryPosition(int position) {
    method getQueueHistoryList (line 411) | public static final int[] getQueueHistoryList() {
    method removeTrack (line 421) | public static final int removeTrack(final long id) {
    method removeTrackAtPosition (line 431) | public static final boolean removeTrackAtPosition(final long id, final...
    method moveQueueItem (line 441) | public static void moveQueueItem(final int from, final int to) {
    method playArtist (line 451) | public static void playArtist(final Context context, final long artist...
    method playAlbum (line 458) | public static void playAlbum(final Context context, final long albumId...
    method playAll (line 465) | public static void playAll(final Context context, final long[] list, i...
    method playNext (line 495) | public static void playNext(Context context, final long[] list, final ...
    method shuffleAll (line 507) | public static void shuffleAll(final Context context) {
    method getSongListForArtist (line 526) | public static final long[] getSongListForArtist(final Context context,...
    method getSongListForAlbum (line 544) | public static final long[] getSongListForAlbum(final Context context, ...
    method getSongCountForAlbumInt (line 562) | public static final int getSongCountForAlbumInt(final Context context,...
    method getReleaseDateForAlbum (line 585) | public static final String getReleaseDateForAlbum(final Context contex...
    method seek (line 605) | public static void seek(final long position) {
    method seekRelative (line 616) | public static void seekRelative(final long deltaInMs) {
    method position (line 627) | public static final long position() {
    method duration (line 639) | public static final long duration() {
    method clearQueue (line 651) | public static void clearQueue() {
    method addToQueue (line 660) | public static void addToQueue(final Context context, final long[] list...
    method makeLabel (line 673) | public static final String makeLabel(final Context context, final int ...
    method addToPlaylist (line 678) | public static void addToPlaylist(final Context context, final long[] i...
    method makeInsertItems (line 711) | public static void makeInsertItems(final long[] ids, final int offset,...
    method createPlaylist (line 728) | public static final long createPlaylist(final Context context, final S...
    method openFile (line 753) | public static final void openFile(final String path) {
    class ServiceBinder (line 762) | public static final class ServiceBinder implements ServiceConnection {
      method ServiceBinder (line 767) | public ServiceBinder(final ServiceConnection callback, final Context...
      method onServiceConnected (line 772) | @Override
      method onServiceDisconnected (line 781) | @Override
    class ServiceToken (line 790) | public static final class ServiceToken {
      method ServiceToken (line 793) | public ServiceToken(final ContextWrapper context) {

FILE: app/src/main/java/com/naman14/timber/MusicService.java
  class MusicService (line 98) | @SuppressLint("NewApi")
    method onAudioFocusChange (line 228) | @Override
    method onReceive (line 242) | @Override
    method onBind (line 253) | @Override
    method onUnbind (line 261) | @Override
    method onRebind (line 280) | @Override
    method onCreate (line 286) | @Override
    method setUpRemoteControlClient (line 374) | @SuppressWarnings("deprecation")
    method setUpMediaSession (line 396) | private void setUpMediaSession() {
    method onDestroy (line 437) | @Override
    method onStartCommand (line 481) | @Override
    method scrobble (line 507) | void scrobble() {
    method releaseServiceUiAndStop (line 516) | private void releaseServiceUiAndStop() {
    method handleCommandIntent (line 535) | private void handleCommandIntent(Intent intent) {
    method onPreferencesUpdate (line 582) | private void onPreferencesUpdate(Bundle extras) {
    method updateNotification (line 596) | private void updateNotification() {
    method cancelNotification (line 628) | private void cancelNotification() {
    method getCardId (line 635) | private int getCardId() {
    method getmCardId (line 645) | private int getmCardId() {
    method closeExternalStorageFiles (line 658) | public void closeExternalStorageFiles(final String storagePath) {
    method registerExternalStorageListener (line 664) | public void registerExternalStorageListener() {
    method scheduleDelayedShutdown (line 694) | private void scheduleDelayedShutdown() {
    method cancelShutdown (line 701) | private void cancelShutdown() {
    method stop (line 709) | private void stop(final boolean goToIdle) {
    method removeTracksInternal (line 731) | private int removeTracksInternal(int first, int last) {
    method addToPlayList (line 794) | private void addToPlayList(final long[] list, int position, long sourc...
    method updateCursor (line 819) | private void updateCursor(final long trackId) {
    method updateCursor (line 823) | private void updateCursor(final String selection, final String[] selec...
    method updateCursor (line 832) | private void updateCursor(final Uri uri) {
    method updateAlbumCursor (line 840) | private void updateAlbumCursor() {
    method openCursorAndGoToFirst (line 850) | private Cursor openCursorAndGoToFirst(Uri uri, String[] projection,
    method closeCursor (line 864) | private synchronized void closeCursor() {
    method openCurrentAndNext (line 875) | private void openCurrentAndNext() {
    method openCurrentAndMaybeNext (line 879) | private void openCurrentAndMaybeNext(final boolean openNext) {
    method sendErrorMessage (line 929) | private void sendErrorMessage(final String trackName) {
    method getNextPosition (line 935) | private int getNextPosition(final boolean force) {
    method setNextTrack (line 1015) | private void setNextTrack() {
    method setNextTrack (line 1019) | private void setNextTrack(int position) {
    method makeAutoShuffleList (line 1030) | private boolean makeAutoShuffleList() {
    method doAutoShuffleUpdate (line 1058) | private void doAutoShuffleUpdate() {
    method wasRecentlyUsed (line 1087) | private boolean wasRecentlyUsed(final int idx, int lookbacksize) {
    method notifyChange (line 1105) | private void notifyChange(final String what) {
    method updateRemoteControlClient (line 1158) | @SuppressWarnings("deprecation")
    method updateMediaSession (line 1194) | private void updateMediaSession(final String what) {
    method createNotificationChannel (line 1242) | private void createNotificationChannel() {
    method buildNotification (line 1252) | private Notification buildNotification() {
    method addXTrackSelector (line 1319) | private void addXTrackSelector(Notification n) {
    method retrievePlaybackAction (line 1350) | private final PendingIntent retrievePlaybackAction(final String action) {
    method saveQueue (line 1358) | private void saveQueue(final boolean full) {
    method reloadQueueAfterPermissionCheck (line 1378) | private void reloadQueueAfterPermissionCheck() {
    method reloadQueue (line 1388) | private void reloadQueue() {
    method openFile (line 1449) | public boolean openFile(final String path) {
    method updateCursorForDownloadedFile (line 1527) | private void updateCursorForDownloadedFile(Context context, Uri uri) {
    method getValueForDownloadedFile (line 1547) | private String getValueForDownloadedFile(Context context, Uri uri, Str...
    method getAudioSessionId (line 1567) | public int getAudioSessionId() {
    method getMediaMountedCount (line 1573) | public int getMediaMountedCount() {
    method getShuffleMode (line 1577) | public int getShuffleMode() {
    method setShuffleMode (line 1581) | public void setShuffleMode(final int shufflemode) {
    method getRepeatMode (line 1608) | public int getRepeatMode() {
    method setRepeatMode (line 1612) | public void setRepeatMode(final int repeatmode) {
    method removeTrack (line 1621) | public int removeTrack(final long id) {
    method removeTrackAtPosition (line 1637) | public boolean removeTrackAtPosition(final long id, final int position) {
    method removeTracks (line 1649) | public int removeTracks(final int first, final int last) {
    method getQueuePosition (line 1657) | public int getQueuePosition() {
    method setQueuePosition (line 1663) | public void setQueuePosition(final int index) {
    method getQueueHistorySize (line 1676) | public int getQueueHistorySize() {
    method getQueueHistoryPosition (line 1682) | public int getQueueHistoryPosition(int position) {
    method getQueueHistoryList (line 1692) | public int[] getQueueHistoryList() {
    method getPath (line 1703) | public String getPath() {
    method getAlbumName (line 1712) | public String getAlbumName() {
    method getTrackName (line 1721) | public String getTrackName() {
    method getGenreName (line 1730) | public String getGenreName() {
    method getArtistName (line 1754) | public String getArtistName() {
    method getAlbumArtistName (line 1763) | public String getAlbumArtistName() {
    method getAlbumId (line 1772) | public long getAlbumId() {
    method getArtistId (line 1781) | public long getArtistId() {
    method getAudioId (line 1790) | public long getAudioId() {
    method getCurrentTrack (line 1799) | public MusicPlaybackTrack getCurrentTrack() {
    method getTrack (line 1803) | public synchronized MusicPlaybackTrack getTrack(int index) {
    method getNextAudioId (line 1811) | public long getNextAudioId() {
    method getPreviousAudioId (line 1820) | public long getPreviousAudioId() {
    method seek (line 1832) | public long seek(long position) {
    method seekRelative (line 1846) | public void seekRelative(long deltaInMs) {
    method position (line 1866) | public long position() {
    method duration (line 1873) | public long duration() {
    method getQueue (line 1880) | public long[] getQueue() {
    method getQueueItemAtPosition (line 1891) | public long getQueueItemAtPosition(int position) {
    method getQueueSize (line 1901) | public int getQueueSize() {
    method isPlaying (line 1907) | public boolean isPlaying() {
    method setIsSupposedToBePlaying (line 1911) | private void setIsSupposedToBePlaying(boolean value, boolean notify) {
    method recentlyPlayed (line 1927) | private boolean recentlyPlayed() {
    method open (line 1931) | public void open(final long[] list, final int position, long sourceId,...
    method stop (line 1965) | public void stop() {
    method play (line 1969) | public void play() {
    method play (line 1973) | public void play(boolean createNewNextTrack) {
    method pause (line 2020) | public void pause() {
    method gotoNext (line 2038) | public void gotoNext(final boolean force) {
    method goToPosition (line 2064) | public void goToPosition(int pos) {
    method setAndRecordPlayPos (line 2088) | public void setAndRecordPlayPos(int nextPos) {
    method prev (line 2102) | public void prev(boolean forcePrevious) {
    method getPreviousPlayPosition (line 2128) | public int getPreviousPlayPosition(boolean removeFromHistory) {
    method openCurrent (line 2151) | private void openCurrent() {
    method moveQueueItem (line 2155) | public void moveQueueItem(int index1, int index2) {
    method enqueue (line 2188) | public void enqueue(final long[] list, final int action, long sourceId...
    method cycleRepeat (line 2208) | private void cycleRepeat() {
    method cycleShuffle (line 2219) | private void cycleShuffle() {
    method refresh (line 2230) | public void refresh() {
    method playlistChanged (line 2234) | public void playlistChanged() {
    type TrackErrorExtra (line 2238) | public interface TrackErrorExtra {
    class MusicPlayerHandler (line 2243) | private static final class MusicPlayerHandler extends Handler {
      method MusicPlayerHandler (line 2248) | public MusicPlayerHandler(final MusicService service, final Looper l...
      method handleMessage (line 2254) | @Override
    class Shuffler (line 2352) | private static final class Shuffler {
      method Shuffler (line 2363) | public Shuffler() {
      method nextInt (line 2368) | public int nextInt(final int interval) {
      method cleanUpHistory (line 2382) | private void cleanUpHistory() {
    class TrackErrorInfo (line 2391) | private static final class TrackErrorInfo {
      method TrackErrorInfo (line 2395) | public TrackErrorInfo(long id, String trackName) {
    class MultiPlayer (line 2401) | private static final class MultiPlayer implements MediaPlayer.OnErrorL...
      method MultiPlayer (line 2417) | public MultiPlayer(final MusicService service) {
      method setDataSource (line 2424) | public void setDataSource(final String path) {
      method setDataSourceImpl (line 2436) | private boolean setDataSourceImpl(final MediaPlayer player, final St...
      method setNextDataSource (line 2461) | public void setNextDataSource(final String path) {
      method setHandler (line 2497) | public void setHandler(final Handler handler) {
      method isInitialized (line 2502) | public boolean isInitialized() {
      method start (line 2507) | public void start() {
      method stop (line 2512) | public void stop() {
      method release (line 2518) | public void release() {
      method pause (line 2523) | public void pause() {
      method duration (line 2528) | public long duration() {
      method position (line 2533) | public long position() {
      method seek (line 2538) | public long seek(final long whereto) {
      method setVolume (line 2544) | public void setVolume(final float vol) {
      method getAudioSessionId (line 2552) | public int getAudioSessionId() {
      method setAudioSessionId (line 2556) | public void setAudioSessionId(final int sessionId) {
      method onError (line 2560) | @Override
      method onCompletion (line 2583) | @Override
    class ServiceStub (line 2599) | private static final class ServiceStub extends ITimberService.Stub {
      method ServiceStub (line 2603) | private ServiceStub(final MusicService service) {
      method openFile (line 2608) | @Override
      method open (line 2613) | @Override
      method stop (line 2619) | @Override
      method pause (line 2624) | @Override
      method play (line 2630) | @Override
      method prev (line 2635) | @Override
      method next (line 2640) | @Override
      method enqueue (line 2645) | @Override
      method moveQueueItem (line 2651) | @Override
      method refresh (line 2656) | @Override
      method playlistChanged (line 2661) | @Override
      method isPlaying (line 2666) | @Override
      method getQueue (line 2671) | @Override
      method getQueueItemAtPosition (line 2676) | @Override
      method getQueueSize (line 2681) | @Override
      method getQueueHistoryPosition (line 2686) | @Override
      method getQueueHistorySize (line 2691) | @Override
      method getQueueHistoryList (line 2696) | @Override
      method duration (line 2701) | @Override
      method position (line 2706) | @Override
      method seek (line 2711) | @Override
      method seekRelative (line 2716) | @Override
      method getAudioId (line 2721) | @Override
      method getCurrentTrack (line 2726) | @Override
      method getTrack (line 2731) | @Override
      method getNextAudioId (line 2736) | @Override
      method getPreviousAudioId (line 2741) | @Override
      method getArtistId (line 2746) | @Override
      method getAlbumId (line 2751) | @Override
      method getArtistName (line 2756) | @Override
      method getTrackName (line 2761) | @Override
      method getAlbumName (line 2766) | @Override
      method getPath (line 2771) | @Override
      method getQueuePosition (line 2776) | @Override
      method setQueuePosition (line 2781) | @Override
      method getShuffleMode (line 2786) | @Override
      method setShuffleMode (line 2791) | @Override
      method getRepeatMode (line 2796) | @Override
      method setRepeatMode (line 2801) | @Override
      method removeTracks (line 2806) | @Override
      method removeTrack (line 2812) | @Override
      method removeTrackAtPosition (line 2818) | @Override
      method getMediaMountedCount (line 2825) | @Override
      method getAudioSessionId (line 2831) | @Override
    class MediaStoreObserver (line 2838) | private class MediaStoreObserver extends ContentObserver implements Ru...
      method MediaStoreObserver (line 2843) | public MediaStoreObserver(Handler handler) {
      method onChange (line 2848) | @Override
      method run (line 2856) | @Override

FILE: app/src/main/java/com/naman14/timber/TimberApp.java
  class TimberApp (line 30) | public class TimberApp extends MultiDexApplication {
    method getInstance (line 34) | public static synchronized TimberApp getInstance() {
    method onCreate (line 38) | @Override

FILE: app/src/main/java/com/naman14/timber/WearBrowserService.java
  class WearBrowserService (line 46) | @TargetApi(21)
    method getInstance (line 65) | public static WearBrowserService getInstance() {
    method onCreate (line 69) | @Override
    method onStartCommand (line 81) | @Override
    method onDestroy (line 86) | @Override
    method onLoadChildren (line 92) | @Override
    method onGetRoot (line 100) | @Nullable
    class MediaSessionCallback (line 106) | private final class MediaSessionCallback extends MediaSession.Callback {
      method onPlay (line 108) | @Override
      method onSeekTo (line 113) | @Override
      method onPlayFromMediaId (line 118) | @Override
      method onPause (line 125) | @Override
      method onStop (line 130) | @Override
      method onSkipToNext (line 135) | @Override
      method onSkipToPrevious (line 140) | @Override
      method onFastForward (line 145) | @Override
      method onRewind (line 150) | @Override
      method onCustomAction (line 155) | @Override
    method setSessionActive (line 161) | private void setSessionActive() {
    method setSessionInactive (line 172) | private void setSessionInactive() {
    method addMediaRoots (line 183) | private void addMediaRoots(List<MediaBrowser.MediaItem> mMediaRoot) {
    method loadChildren (line 228) | private void loadChildren(final String parentId, final Result<List<Med...
    method fillMediaItems (line 312) | private void fillMediaItems(List<MediaBrowser.MediaItem> mediaItems, S...

FILE: app/src/main/java/com/naman14/timber/activities/BaseActivity.java
  class BaseActivity (line 65) | public class BaseActivity extends ATEActivity implements ServiceConnecti...
    class SessionManagerListenerImpl (line 79) | private class SessionManagerListenerImpl extends SimpleSessionManagerL...
      method onSessionStarting (line 80) | @Override
      method onSessionStarted (line 86) | @Override
      method onSessionResumed (line 92) | @Override
      method onSessionEnded (line 97) | @Override
      method onSessionResuming (line 104) | @Override
      method onSessionSuspended (line 110) | @Override
    method onCreate (line 117) | @Override
    method onStart (line 138) | @Override
    method onStop (line 158) | @Override
    method onResume (line 163) | @Override
    method onPause (line 177) | @Override
    method onServiceConnected (line 186) | @Override
    method initCast (line 193) | private void initCast() {
    method onServiceDisconnected (line 198) | @Override
    method onDestroy (line 203) | @Override
    method onMetaChanged (line 219) | @Override
    method restartLoader (line 229) | @Override
    method onPlaylistChanged (line 239) | @Override
    method setMusicStateListenerListener (line 249) | public void setMusicStateListenerListener(final MusicStateListener sta...
    method removeMusicStateListenerListener (line 259) | public void removeMusicStateListenerListener(final MusicStateListener ...
    method onCreateOptionsMenu (line 265) | @Override
    method onOptionsItemSelected (line 284) | @Override
    method getATEKey (line 314) | @Nullable
    method setPanelSlideListeners (line 320) | public void setPanelSlideListeners(SlidingUpPanelLayout panelLayout) {
    class PlaybackStatus (line 356) | private final static class PlaybackStatus extends BroadcastReceiver {
      method PlaybackStatus (line 361) | public PlaybackStatus(final BaseActivity activity) {
      method onReceive (line 365) | @Override
    class initQuickControls (line 387) | public class initQuickControls extends AsyncTask<String, Void, String> {
      method doInBackground (line 389) | @Override
      method onPostExecute (line 398) | @Override
      method onPreExecute (line 402) | @Override
    method showCastMiniController (line 407) | public void showCastMiniController() {
    method hideCastMiniController (line 411) | public void hideCastMiniController() {
    method getCastSession (line 415) | public CastSession getCastSession() {
    method startCastServer (line 419) | private void startCastServer() {
    method stopCastServer (line 428) | private void stopCastServer() {

FILE: app/src/main/java/com/naman14/timber/activities/BaseThemedActivity.java
  class BaseThemedActivity (line 13) | public class BaseThemedActivity extends ATEActivity {
    method getATEKey (line 15) | @Nullable
    method onCreate (line 21) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/DonateActivity.java
  class DonateActivity (line 29) | public class DonateActivity extends BaseThemedActivity implements Billin...
    method onCreate (line 48) | @Override
    method onBillingInitialized (line 72) | @Override
    method onProductPurchased (line 80) | @Override
    method onBillingError (line 91) | @Override
    method onPurchaseHistoryRestored (line 102) | @Override
    method onDestroy (line 107) | @Override
    method onActivityResult (line 114) | @Override
    method checkStatus (line 120) | private void checkStatus() {
    method getProducts (line 150) | private void getProducts() {
    method onOptionsItemSelected (line 210) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/MainActivity.java
  class MainActivity (line 64) | public class MainActivity extends BaseActivity implements ATEActivityThe...
    method run (line 78) | public void run() {
    method run (line 88) | public void run() {
    method run (line 99) | public void run() {
    method run (line 110) | public void run() {
    method run (line 121) | public void run() {
    method run (line 131) | public void run() {
    method run (line 141) | public void run() {
    method run (line 150) | public void run() {
    method permissionGranted (line 157) | @Override
    method permissionRefused (line 162) | @Override
    method onCreate (line 169) | @Override
    method loadEverything (line 255) | private void loadEverything() {
    method checkPermissionAndThenLoad (line 266) | private void checkPermissionAndThenLoad() {
    method onCreateOptionsMenu (line 287) | @Override
    method onOptionsItemSelected (line 294) | @Override
    method onBackPressed (line 307) | @Override
    method setupDrawerContent (line 318) | private void setupDrawerContent(NavigationView navigationView) {
    method setupNavigationIcons (line 330) | private void setupNavigationIcons(NavigationView navigationView) {
    method updatePosition (line 366) | private void updatePosition(final MenuItem menuItem) {
    method setDetailsToHeader (line 425) | public void setDetailsToHeader() {
    method onMetaChanged (line 440) | @Override
    method onRequestPermissionsResult (line 450) | @Override
    method isNavigatingMain (line 456) | private boolean isNavigatingMain() {
    method addBackstackListener (line 462) | private void addBackstackListener() {
    method getActivityTheme (line 472) | @Override
    method onActivityResult (line 477) | @Override
    method showCastMiniController (line 484) | @Override
    method hideCastMiniController (line 491) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/NowPlayingActivity.java
  class NowPlayingActivity (line 24) | public class NowPlayingActivity extends BaseActivity implements ATEActiv...
    method onCreate (line 26) | @Override
    method getActivityTheme (line 41) | @StyleRes
    method getLightToolbarMode (line 47) | @Override
    method getLightStatusBarMode (line 52) | @Override
    method getToolbarColor (line 57) | @Override
    method getStatusBarColor (line 62) | @Override
    method onResume (line 67) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/PlaylistDetailActivity.java
  class PlaylistDetailActivity (line 64) | public class PlaylistDetailActivity extends BaseActivity implements ATEA...
    method run (line 79) | public void run() {
    method run (line 84) | @Override
    method run (line 91) | @Override
    method run (line 97) | @Override
    method onCreate (line 104) | @TargetApi(21)
    method onSaveInstanceState (line 146) | @Override
    method setAlbumart (line 152) | private void setAlbumart() {
    method setUpSongs (line 158) | private void setUpSongs() {
    method loadBitmap (line 188) | private void loadBitmap(String uri) {
    method setRecyclerViewAapter (line 196) | private void setRecyclerViewAapter() {
    method getActivityTheme (line 210) | @StyleRes
    class loadLastAdded (line 217) | private class loadLastAdded extends AsyncTask<String, Void, String> {
      method doInBackground (line 219) | @Override
      method onPostExecute (line 227) | @Override
      method onPreExecute (line 232) | @Override
    class loadRecentlyPlayed (line 237) | private class loadRecentlyPlayed extends AsyncTask<String, Void, Strin...
      method doInBackground (line 239) | @Override
      method onPostExecute (line 248) | @Override
      method onPreExecute (line 254) | @Override
    class loadTopTracks (line 259) | private class loadTopTracks extends AsyncTask<String, Void, String> {
      method doInBackground (line 261) | @Override
      method onPostExecute (line 270) | @Override
      method onPreExecute (line 275) | @Override
    class loadUserCreatedPlaylist (line 280) | private class loadUserCreatedPlaylist extends AsyncTask<String, Void, ...
      method doInBackground (line 282) | @Override
      method onPostExecute (line 291) | @Override
      method onPreExecute (line 296) | @Override
    class EnterTransitionListener (line 301) | private class EnterTransitionListener extends SimplelTransitionListener {
      method onTransitionEnd (line 303) | @TargetApi(21)
      method onTransitionStart (line 308) | public void onTransitionStart(Transition paramTransition) {
    method onCreateOptionsMenu (line 313) | @Override
    method onPrepareOptionsMenu (line 320) | @Override
    method onOptionsItemSelected (line 333) | @Override
    method showDeletePlaylistDialog (line 351) | private void showDeletePlaylistDialog() {
    method clearAutoPlaylists (line 375) | private void clearAutoPlaylists() {
    method onMetaChanged (line 392) | @Override
    method getToolbarColor (line 399) | @Override
    method getLightToolbarMode (line 404) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/SearchActivity.java
  class SearchActivity (line 49) | public class SearchActivity extends BaseActivity implements SearchView.O...
    method onCreate (line 66) | @Override
    method onSaveInstanceState (line 88) | @Override
    method onCreateOptionsMenu (line 97) | @Override
    method onPrepareOptionsMenu (line 134) | @Override
    method onOptionsItemSelected (line 141) | @Override
    method onQueryTextSubmit (line 153) | @Override
    method onQueryTextChange (line 161) | @Override
    method onTouch (line 184) | @Override
    method onDestroy (line 190) | @Override
    method hideInputManager (line 198) | public void hideInputManager() {
    class SearchTask (line 209) | private class SearchTask extends AsyncTask<String,Void,ArrayList<Objec...
      method doInBackground (line 211) | @Override
      method onPostExecute (line 244) | @Override

FILE: app/src/main/java/com/naman14/timber/activities/SettingsActivity.java
  class SettingsActivity (line 38) | public class SettingsActivity extends BaseThemedActivity implements Colo...
    method onCreate (line 42) | @Override
    method onOptionsItemSelected (line 76) | @Override
    method getActivityTheme (line 88) | @StyleRes
    method onColorSelection (line 95) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/AlbumAdapter.java
  class AlbumAdapter (line 43) | public class AlbumAdapter extends RecyclerView.Adapter<AlbumAdapter.Item...
    method AlbumAdapter (line 49) | public AlbumAdapter(Activity context, List<Album> arraylist) {
    method onCreateViewHolder (line 56) | @Override
    method onBindViewHolder (line 69) | @Override
    method getItemCount (line 131) | @Override
    method updateDataSet (line 136) | public void updateDataSet(List<Album> arraylist) {
    class ItemHolder (line 140) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 145) | public ItemHolder(View view) {
      method onClick (line 154) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/AlbumSongsAdapter.java
  class AlbumSongsAdapter (line 38) | public class AlbumSongsAdapter extends BaseSongAdapter<AlbumSongsAdapter...
    method AlbumSongsAdapter (line 45) | public AlbumSongsAdapter(Activity context, List<Song> arraylist, long ...
    method onCreateViewHolder (line 52) | @Override
    method onBindViewHolder (line 62) | @Override
    method setOnPopupMenuListener (line 79) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method getItemCount (line 129) | @Override
    method getSongIds (line 134) | public long[] getSongIds() {
    method updateDataSet (line 143) | @Override
    method removeSongAt (line 149) | @Override
    class ItemHolder (line 154) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 158) | public ItemHolder(View view) {
      method onClick (line 167) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/ArtistAdapter.java
  class ArtistAdapter (line 50) | public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.It...
    method ArtistAdapter (line 56) | public ArtistAdapter(Activity context, List<Artist> arraylist) {
    method getOpaqueColor (line 62) | public static int getOpaqueColor(@ColorInt int paramInt) {
    method onCreateViewHolder (line 66) | @Override
    method onBindViewHolder (line 79) | @Override
    method getItemId (line 158) | @Override
    method getItemCount (line 163) | @Override
    method getTextToShowInBubble (line 168) | @Override
    method updateDataSet (line 175) | public void updateDataSet(List<Artist> arrayList) {
    class ItemHolder (line 179) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 184) | public ItemHolder(View view) {
      method onClick (line 193) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/ArtistAlbumAdapter.java
  class ArtistAlbumAdapter (line 35) | public class ArtistAlbumAdapter extends RecyclerView.Adapter<ArtistAlbum...
    method ArtistAlbumAdapter (line 40) | public ArtistAlbumAdapter(Activity context, List<Album> arraylist) {
    method onCreateViewHolder (line 46) | @Override
    method onBindViewHolder (line 53) | @Override
    method getItemCount (line 69) | @Override
    class ItemHolder (line 75) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 80) | public ItemHolder(View view) {
      method onClick (line 89) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/ArtistSongAdapter.java
  class ArtistSongAdapter (line 44) | public class ArtistSongAdapter extends BaseSongAdapter<ArtistSongAdapter...
    method ArtistSongAdapter (line 51) | public ArtistSongAdapter(Activity context, List<Song> arraylist, long ...
    method onCreateViewHolder (line 58) | @Override
    method onBindViewHolder (line 71) | @Override
    method onViewRecycled (line 90) | @Override
    method getItemCount (line 98) | @Override
    method setOnPopupMenuListener (line 103) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method setUpAlbums (line 153) | private void setUpAlbums(RecyclerView albumsRecyclerview) {
    method clearExtraSpacingBetweenCards (line 168) | private void clearExtraSpacingBetweenCards(RecyclerView albumsRecycler...
    method getSongIds (line 175) | public long[] getSongIds() {
    method removeSongAt (line 185) | @Override
    method updateDataSet (line 191) | @Override
    method getItemViewType (line 197) | @Override
    class ItemHolder (line 206) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 211) | public ItemHolder(View view) {
      method onClick (line 225) | @Override
    class SpacesItemDecoration (line 241) | public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
      method SpacesItemDecoration (line 244) | public SpacesItemDecoration(int space) {
      method getItemOffsets (line 248) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/BaseQueueAdapter.java
  class BaseQueueAdapter (line 42) | public class BaseQueueAdapter extends RecyclerView.Adapter<BaseQueueAdap...
    method BaseQueueAdapter (line 49) | public BaseQueueAdapter(AppCompatActivity context, List<Song> arraylis...
    method onCreateViewHolder (line 56) | @Override
    method onBindViewHolder (line 63) | @Override
    method getItemCount (line 88) | @Override
    method setOnPopupMenuListener (line 93) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method getSongIds (line 143) | public long[] getSongIds() {
    method removeSongAt (line 152) | public void removeSongAt(int i){
    class ItemHolder (line 156) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 161) | public ItemHolder(View view) {
      method onClick (line 171) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/BaseSongAdapter.java
  class BaseSongAdapter (line 24) | public class BaseSongAdapter<V extends RecyclerView.ViewHolder> extends ...
    method onCreateViewHolder (line 26) | @Override
    method onBindViewHolder (line 31) | @Override
    method getItemCount (line 36) | @Override
    method getItemViewType (line 41) | @Override
    class ItemHolder (line 46) | public class ItemHolder extends RecyclerView.ViewHolder {
      method ItemHolder (line 48) | public ItemHolder(View view) {
    method playAll (line 54) | public void playAll(final Activity context, final long[] list, int pos...
    method removeSongAt (line 76) | public void removeSongAt(int i){}
    method updateDataSet (line 77) | public void updateDataSet(List<Song> arraylist) {}

FILE: app/src/main/java/com/naman14/timber/adapters/FolderAdapter.java
  class FolderAdapter (line 38) | public class FolderAdapter extends BaseSongAdapter<FolderAdapter.ItemHol...
    method FolderAdapter (line 49) | public FolderAdapter(Activity context, File root) {
    method applyTheme (line 61) | public void applyTheme(boolean dark) {
    method onCreateViewHolder (line 72) | @Override
    method onBindViewHolder (line 78) | @Override
    method getItemCount (line 94) | @Override
    method updateDataSet (line 99) | @Deprecated
    method goUp (line 113) | @Deprecated
    method goUpAsync (line 127) | public boolean goUpAsync() {
    method updateDataSetAsync (line 139) | public boolean updateDataSetAsync(File newRoot) {
    method getTextToShowInBubble (line 152) | @Override
    method getSongsForFiles (line 168) | private void getSongsForFiles(List<File> files) {
    class NavigateTask (line 176) | private class NavigateTask extends AsyncTask<File, Void, List<File>> {
      method onPreExecute (line 178) | @Override
      method doInBackground (line 184) | @Override
      method onPostExecute (line 191) | @Override
    class ItemHolder (line 201) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 206) | public ItemHolder(View view) {
      method onClick (line 213) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/PlayingQueueAdapter.java
  class PlayingQueueAdapter (line 44) | public class PlayingQueueAdapter extends RecyclerView.Adapter<PlayingQue...
    method PlayingQueueAdapter (line 52) | public PlayingQueueAdapter(Activity context, List<Song> arraylist) {
    method onCreateViewHolder (line 59) | @Override
    method onBindViewHolder (line 66) | @Override
    method setOnPopupMenuListener (line 91) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method getItemCount (line 130) | @Override
    method getSongIds (line 135) | public long[] getSongIds() {
    method getSongAt (line 144) | public Song getSongAt(int i) {
    method addSongTo (line 148) | public void addSongTo(int i, Song song) {
    method removeSongAt (line 152) | public void removeSongAt(int i) {
    class ItemHolder (line 156) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 161) | public ItemHolder(View view) {
      method onClick (line 172) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/PlaylistAdapter.java
  class PlaylistAdapter (line 37) | public class PlaylistAdapter extends RecyclerView.Adapter<PlaylistAdapte...
    method PlaylistAdapter (line 49) | public PlaylistAdapter(Activity context, List<Playlist> arraylist) {
    method onCreateViewHolder (line 60) | @Override
    method onBindViewHolder (line 73) | @Override
    method getAlbumArtUri (line 136) | private String getAlbumArtUri(int position, long id) {
    method getItemCount (line 210) | @Override
    method updateDataSet (line 215) | public void updateDataSet(List<Playlist> arraylist) {
    class ItemHolder (line 221) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 226) | public ItemHolder(View view) {
      method onClick (line 235) | @Override
    method getPlaylistType (line 243) | private String getPlaylistType(int position) {

FILE: app/src/main/java/com/naman14/timber/adapters/SearchAdapter.java
  class SearchAdapter (line 48) | public class SearchAdapter extends BaseSongAdapter<SearchAdapter.ItemHol...
    method SearchAdapter (line 53) | public SearchAdapter(Activity context) {
    method onCreateViewHolder (line 58) | @Override
    method onBindViewHolder (line 84) | @Override
    method onViewRecycled (line 145) | @Override
    method getItemCount (line 150) | @Override
    method setOnPopupMenuListener (line 155) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method getItemViewType (line 199) | @Override
    method updateSearchResults (line 212) | public void updateSearchResults(List searchResults) {
    class ItemHolder (line 216) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 220) | public ItemHolder(View view) {
      method onClick (line 239) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/SlidingQueueAdapter.java
  class SlidingQueueAdapter (line 36) | public class SlidingQueueAdapter extends RecyclerView.Adapter<SlidingQue...
    method SlidingQueueAdapter (line 43) | public SlidingQueueAdapter(Activity context, List<Song> arraylist) {
    method onCreateViewHolder (line 49) | @Override
    method onBindViewHolder (line 56) | @Override
    method getItemCount (line 68) | @Override
    method getSongIds (line 73) | public long[] getSongIds() {
    method setAnimation (line 82) | private void setAnimation(View viewToAnimate, int position) {
    class ItemHolder (line 91) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 94) | public ItemHolder(View view) {
      method onClick (line 100) | @Override

FILE: app/src/main/java/com/naman14/timber/adapters/SongsListAdapter.java
  class SongsListAdapter (line 47) | public class SongsListAdapter extends BaseSongAdapter<SongsListAdapter.I...
    method SongsListAdapter (line 59) | public SongsListAdapter(AppCompatActivity context, List<Song> arraylis...
    method onCreateViewHolder (line 68) | @Override
    method onBindViewHolder (line 81) | @Override
    method setPlaylistId (line 125) | public void setPlaylistId(long playlistId) {
    method getItemCount (line 129) | @Override
    method setOnPopupMenuListener (line 134) | private void setOnPopupMenuListener(ItemHolder itemHolder, final int p...
    method getSongIds (line 192) | public long[] getSongIds() {
    method getTextToShowInBubble (line 201) | @Override
    method setAnimation (line 212) | private void setAnimation(View viewToAnimate, int position) {
    method updateDataSet (line 221) | @Override
    class ItemHolder (line 227) | public class ItemHolder extends RecyclerView.ViewHolder implements Vie...
      method ItemHolder (line 232) | public ItemHolder(View view) {
      method onClick (line 242) | @Override
    method getSongAt (line 267) | public Song getSongAt(int i) {
    method addSongTo (line 271) | public void addSongTo(int i, Song song) {
    method removeSongAt (line 275) | @Override

FILE: app/src/main/java/com/naman14/timber/cast/CastOptionsProvider.java
  class CastOptionsProvider (line 16) | public class CastOptionsProvider implements OptionsProvider {
    method getCastOptions (line 18) | @Override
    method getAdditionalSessionProviders (line 43) | @Override

FILE: app/src/main/java/com/naman14/timber/cast/ExpandedControlsActivity.java
  class ExpandedControlsActivity (line 12) | public class ExpandedControlsActivity extends ExpandedControllerActivity {
    method onCreateOptionsMenu (line 14) | @Override
    method onCreate (line 22) | @Override

FILE: app/src/main/java/com/naman14/timber/cast/SimpleSessionManagerListener.java
  class SimpleSessionManagerListener (line 10) | public class SimpleSessionManagerListener implements SessionManagerListe...
    method onSessionStarted (line 12) | public void onSessionStarted(Session session, String sessionId) {
    method onSessionResumed (line 15) | public void onSessionResumed(Session session, boolean wasSuspended) {
    method onSessionEnded (line 18) | public void onSessionEnded(Session session, int error) {
    method onSessionSuspended (line 21) | public void onSessionSuspended(Session session, int i) {
    method onSessionStarting (line 25) | public void onSessionStarting(Session session) {
    method onSessionEnding (line 29) | public void onSessionEnding(Session session) {
    method onSessionResuming (line 33) | public void onSessionResuming(Session session, String s) {
    method onSessionResumeFailed (line 37) | public void onSessionResumeFailed(Session session, int i) {
    method onSessionStartFailed (line 41) | public void onSessionStartFailed(Session session, int i) {

FILE: app/src/main/java/com/naman14/timber/cast/TimberCastHelper.java
  class TimberCastHelper (line 23) | public class TimberCastHelper  {
    method startCasting (line 25) | public static void startCasting(CastSession castSession, Song song) {

FILE: app/src/main/java/com/naman14/timber/cast/WebServer.java
  class WebServer (line 17) | public class WebServer extends NanoHTTPD {
    method WebServer (line 22) | public WebServer(Context context) {
    method serve (line 27) | @Override

FILE: app/src/main/java/com/naman14/timber/dataloaders/AlbumLoader.java
  class AlbumLoader (line 27) | public class AlbumLoader {
    method getAlbum (line 30) | public static Album getAlbum(Cursor cursor) {
    method getAlbumsForCursor (line 42) | public static List<Album> getAlbumsForCursor(Cursor cursor) {
    method getAllAlbums (line 54) | public static List<Album> getAllAlbums(Context context) {
    method getAlbum (line 58) | public static Album getAlbum(Context context, long id) {
    method getAlbums (line 62) | public static List<Album> getAlbums(Context context, String paramStrin...
    method makeAlbumCursor (line 71) | public static Cursor makeAlbumCursor(Context context, String selection...

FILE: app/src/main/java/com/naman14/timber/dataloaders/AlbumSongLoader.java
  class AlbumSongLoader (line 28) | public class AlbumSongLoader {
    method getSongsForAlbum (line 32) | public static ArrayList<Song> getSongsForAlbum(Context context, long a...
    method makeAlbumSongCursor (line 59) | public static Cursor makeAlbumSongCursor(Context context, long albumID) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/ArtistAlbumLoader.java
  class ArtistAlbumLoader (line 27) | public class ArtistAlbumLoader {
    method getAlbumsForArtist (line 29) | public static ArrayList<Album> getAlbumsForArtist(Context context, lon...

FILE: app/src/main/java/com/naman14/timber/dataloaders/ArtistLoader.java
  class ArtistLoader (line 27) | public class ArtistLoader {
    method getArtist (line 29) | public static Artist getArtist(Cursor cursor) {
    method getArtistsForCursor (line 40) | public static List<Artist> getArtistsForCursor(Cursor cursor) {
    method getAllArtists (line 52) | public static List<Artist> getAllArtists(Context context) {
    method getArtist (line 56) | public static Artist getArtist(Context context, long id) {
    method getArtists (line 60) | public static List<Artist> getArtists(Context context, String paramStr...
    method makeArtistCursor (line 69) | public static Cursor makeArtistCursor(Context context, String selectio...

FILE: app/src/main/java/com/naman14/timber/dataloaders/ArtistSongLoader.java
  class ArtistSongLoader (line 28) | public class ArtistSongLoader {
    method getSongsForArtist (line 30) | public static ArrayList<Song> getSongsForArtist(Context context, long ...
    method makeArtistSongCursor (line 53) | public static Cursor makeArtistSongCursor(Context context, long artist...

FILE: app/src/main/java/com/naman14/timber/dataloaders/FolderLoader.java
  class FolderLoader (line 17) | public class FolderLoader {
    method getMediaFiles (line 28) | public static List<File> getMediaFiles(File dir, final boolean acceptD...
    method isMediaFile (line 53) | public static boolean isMediaFile(File file) {
    method checkDir (line 57) | private static boolean checkDir(File dir) {
    method checkFileExt (line 68) | private static boolean checkFileExt(String name) {
    class FilenameComparator (line 85) | private static class FilenameComparator implements Comparator<File> {
      method compare (line 86) | @Override
    class DirFirstComparator (line 92) | private static class DirFirstComparator implements Comparator<File> {
      method compare (line 93) | @Override

FILE: app/src/main/java/com/naman14/timber/dataloaders/LastAddedLoader.java
  class LastAddedLoader (line 28) | public class LastAddedLoader {
    method getLastAddedSongs (line 32) | public static List<Song> getLastAddedSongs(Context context) {
    method makeLastAddedCursor (line 60) | public static final Cursor makeLastAddedCursor(final Context context) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/NowPlayingCursor.java
  class NowPlayingCursor (line 32) | public class NowPlayingCursor extends AbstractCursor {
    method NowPlayingCursor (line 68) | public NowPlayingCursor(final Context context) {
    method getCount (line 74) | @Override
    method onMove (line 80) | @Override
    method getString (line 97) | @Override
    method getShort (line 108) | @Override
    method getInt (line 114) | @Override
    method getLong (line 125) | @Override
    method getFloat (line 136) | @Override
    method getDouble (line 142) | @Override
    method getType (line 148) | @Override
    method isNull (line 153) | @Override
    method getColumnNames (line 159) | @Override
    method deactivate (line 165) | @SuppressWarnings("deprecation")
    method requery (line 173) | @Override
    method close (line 180) | @Override
    method makeNowPlayingCursor (line 193) | private void makeNowPlayingCursor() {
    method removeItem (line 251) | public boolean removeItem(final int which) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/PlaylistLoader.java
  class PlaylistLoader (line 31) | public class PlaylistLoader {
    method getPlaylists (line 36) | public static List<Playlist> getPlaylists(Context context, boolean def...
    method makeDefaultPlaylists (line 66) | private static void makeDefaultPlaylists(Context context) {
    method makePlaylistCursor (line 86) | public static final Cursor makePlaylistCursor(final Context context) {
    method deletePlaylists (line 94) | public static void deletePlaylists(Context context, long playlistId) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/PlaylistSongLoader.java
  class PlaylistSongLoader (line 32) | public class PlaylistSongLoader {
    method getSongsInPlaylist (line 40) | public static List<Song> getSongsInPlaylist(Context mContext, long pla...
    method cleanupPlaylist (line 123) | private static void cleanupPlaylist(final Context context, final long ...
    method countPlaylist (line 156) | private static int countPlaylist(final Context context, final long pla...
    method makePlaylistSongCursor (line 180) | public static final Cursor makePlaylistSongCursor(final Context contex...

FILE: app/src/main/java/com/naman14/timber/dataloaders/QueueLoader.java
  class QueueLoader (line 25) | public class QueueLoader {
    method getQueueSongs (line 30) | public static List<Song> getQueueSongs(Context context) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/SongLoader.java
  class SongLoader (line 32) | public class SongLoader {
    method getSongsForCursor (line 36) | public static ArrayList<Song> getSongsForCursor(Cursor cursor) {
    method getSongForCursor (line 57) | public static Song getSongForCursor(Cursor cursor) {
    method getSongListForCursor (line 77) | public static final long[] getSongListForCursor(Cursor cursor) {
    method getSongFromPath (line 99) | public static Song getSongFromPath(String songPath, Context context) {
    method getAllSongs (line 118) | public static ArrayList<Song> getAllSongs(Context context) {
    method getSongListInFolder (line 122) | public static long[] getSongListInFolder(Context context, String path) {
    method getSongForID (line 127) | public static Song getSongForID(Context context, long id) {
    method searchSongs (line 131) | public static List<Song> searchSongs(Context context, String searchStr...
    method makeSongCursor (line 140) | public static Cursor makeSongCursor(Context context, String selection,...
    method makeSongCursor (line 145) | private static Cursor makeSongCursor(Context context, String selection...
    method songFromFile (line 155) | public static Song songFromFile(String filePath) {

FILE: app/src/main/java/com/naman14/timber/dataloaders/SortedCursor.java
  class SortedCursor (line 31) | public class SortedCursor extends AbstractCursor {
    method SortedCursor (line 48) | public SortedCursor(final Cursor cursor, final long[] order, final Str...
    method buildCursorPositionMapping (line 66) | private ArrayList<Long> buildCursorPositionMapping(final long[] order,
    method getMissingIds (line 106) | public ArrayList<Long> getMissingIds() {
    method getExtraIds (line 113) | public Collection<Long> getExtraIds() {
    method getExtraData (line 120) | public Object getExtraData() {
    method close (line 125) | @Override
    method getCount (line 132) | @Override
    method getColumnNames (line 137) | @Override
    method getString (line 142) | @Override
    method getShort (line 147) | @Override
    method getInt (line 152) | @Override
    method getLong (line 157) | @Override
    method getFloat (line 162) | @Override
    method getDouble (line 167) | @Override
    method isNull (line 172) | @Override
    method onMove (line 177) | @Override

FILE: app/src/main/java/com/naman14/timber/dataloaders/TopTracksLoader.java
  class TopTracksLoader (line 28) | public class TopTracksLoader extends SongLoader {
    method TopTracksLoader (line 34) | public TopTracksLoader(final Context context, QueryType type) {
    method getCursor (line 39) | public static Cursor getCursor() {
    method makeTopTracksCursor (line 63) | public static final SortedCursor makeTopTracksCursor(final Context con...
    method makeRecentTracksCursor (line 78) | public static final SortedCursor makeRecentTracksCursor(final Context ...
    method makeSortedCursor (line 93) | public static final SortedCursor makeSortedCursor(final Context contex...
    type QueryType (line 127) | public enum QueryType {

FILE: app/src/main/java/com/naman14/timber/dialogs/AddPlaylistDialog.java
  class AddPlaylistDialog (line 20) | public class AddPlaylistDialog extends DialogFragment {
    method newInstance (line 22) | public static AddPlaylistDialog newInstance(Song song) {
    method newInstance (line 28) | public static AddPlaylistDialog newInstance(long[] songList) {
    method onCreateDialog (line 36) | @NonNull

FILE: app/src/main/java/com/naman14/timber/dialogs/CreatePlaylistDialog.java
  class CreatePlaylistDialog (line 17) | public class CreatePlaylistDialog extends DialogFragment {
    method newInstance (line 19) | public static CreatePlaylistDialog newInstance() {
    method newInstance (line 23) | public static CreatePlaylistDialog newInstance(Song song) {
    method newInstance (line 34) | public static CreatePlaylistDialog newInstance(long[] songList) {
    method onCreateDialog (line 42) | @NonNull

FILE: app/src/main/java/com/naman14/timber/dialogs/LastFmLoginDialog.java
  class LastFmLoginDialog (line 22) | public class LastFmLoginDialog extends DialogFragment {
    method onCreateDialog (line 25) | @Override

FILE: app/src/main/java/com/naman14/timber/dialogs/StorageSelectDialog.java
  class StorageSelectDialog (line 17) | public class StorageSelectDialog implements DialogInterface.OnClickListe...
    method StorageSelectDialog (line 23) | public StorageSelectDialog(final Context context) {
    method setDirSelectListener (line 43) | public StorageSelectDialog setDirSelectListener(OnDirSelectListener di...
    method show (line 48) | public void show() {
    method onClick (line 52) | @Override
    method getAvailableStorages (line 59) | private static File[] getAvailableStorages(Context context) {
    type OnDirSelectListener (line 69) | public interface OnDirSelectListener {
      method onDirSelected (line 70) | void onDirSelected(File dir);

FILE: app/src/main/java/com/naman14/timber/fragments/AlbumDetailFragment.java
  class AlbumDetailFragment (line 71) | public class AlbumDetailFragment extends Fragment {
    method newInstance (line 96) | public static AlbumDetailFragment newInstance(long id, boolean useTran...
    method onCreate (line 107) | @Override
    method onCreateView (line 118) | @TargetApi(21)
    method setupToolbar (line 167) | private void setupToolbar() {
    method setAlbumart (line 176) | private void setAlbumart() {
    method setAlbumDetails (line 252) | private void setAlbumDetails() {
    method setUpAlbumSongs (line 264) | private void setUpAlbumSongs() {
    method setUpEverything (line 273) | private void setUpEverything() {
    method reloadAdapter (line 279) | private void reloadAdapter() {
    method onActivityCreated (line 295) | @Override
    method onCreateOptionsMenu (line 301) | @Override
    method onOptionsItemSelected (line 309) | @Override
    method onResume (line 345) | @Override
    class EnterTransitionListener (line 358) | private class EnterTransitionListener extends SimplelTransitionListener {
      method onTransitionEnd (line 360) | @TargetApi(21)
      method onTransitionStart (line 365) | public void onTransitionStart(Transition paramTransition) {

FILE: app/src/main/java/com/naman14/timber/fragments/AlbumFragment.java
  class AlbumFragment (line 42) | public class AlbumFragment extends Fragment {
    method onCreate (line 52) | @Override
    method onCreateView (line 59) | @Override
    method setLayoutManager (line 76) | private void setLayoutManager() {
    method setItemDecoration (line 88) | private void setItemDecoration() {
    method updateLayoutManager (line 98) | private void updateLayoutManager(int column) {
    method reloadAdapter (line 106) | private void reloadAdapter() {
    method onActivityCreated (line 122) | @Override
    method onCreateOptionsMenu (line 128) | @Override
    method onOptionsItemSelected (line 136) | @Override
    class SpacesItemDecoration (line 173) | public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
      method SpacesItemDecoration (line 176) | public SpacesItemDecoration(int space) {
      method getItemOffsets (line 180) | @Override
    class loadAlbums (line 193) | private class loadAlbums extends AsyncTask<String, Void, String> {
      method doInBackground (line 195) | @Override
      method onPostExecute (line 202) | @Override
      method onPreExecute (line 212) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/ArtistBioFragment.java
  class ArtistBioFragment (line 35) | public class ArtistBioFragment extends Fragment {
    method newInstance (line 39) | public static ArtistBioFragment newInstance(long id) {
    method onCreate (line 47) | @Override
    method onCreateView (line 55) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/ArtistDetailFragment.java
  class ArtistDetailFragment (line 62) | public class ArtistDetailFragment extends Fragment {
    method newInstance (line 73) | public static ArtistDetailFragment newInstance(long id, boolean useTra...
    method onCreate (line 84) | @Override
    method onCreateView (line 93) | @Override
    method setupToolbar (line 117) | private void setupToolbar() {
    method setUpArtistDetails (line 126) | private void setUpArtistDetails() {
    method setBlurredPlaceholder (line 193) | private void setBlurredPlaceholder(LastfmArtist artist) {
    method onActivityCreated (line 204) | @Override
    method onCreateOptionsMenu (line 210) | @Override
    method onOptionsItemSelected (line 217) | @Override
    method onResume (line 230) | @Override
    class setBlurredAlbumArt (line 242) | private class setBlurredAlbumArt extends AsyncTask<Bitmap, Void, Drawa...
      method doInBackground (line 244) | @Override
      method onPostExecute (line 255) | @Override
      method onPreExecute (line 262) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/ArtistFragment.java
  class ArtistFragment (line 42) | public class ArtistFragment extends Fragment {
    method onCreate (line 51) | @Override
    method onCreateView (line 58) | @Override
    method setLayoutManager (line 75) | private void setLayoutManager() {
    method setItemDecoration (line 84) | private void setItemDecoration() {
    method updateLayoutManager (line 94) | private void updateLayoutManager(int column) {
    method reloadAdapter (line 102) | private void reloadAdapter() {
    method onActivityCreated (line 118) | @Override
    method onCreateOptionsMenu (line 124) | @Override
    method onOptionsItemSelected (line 132) | @Override
    class loadArtists (line 165) | private class loadArtists extends AsyncTask<String, Void, String> {
      method doInBackground (line 167) | @Override
      method onPostExecute (line 174) | @Override
      method onPreExecute (line 185) | @Override
    class SpacesItemDecoration (line 190) | public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
      method SpacesItemDecoration (line 193) | public SpacesItemDecoration(int space) {
      method getItemOffsets (line 197) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/ArtistMusicFragment.java
  class ArtistMusicFragment (line 34) | public class ArtistMusicFragment extends Fragment {
    method newInstance (line 40) | public static ArtistMusicFragment newInstance(long id) {
    method onCreate (line 48) | @Override
    method onCreateView (line 56) | @Override
    method setUpSongs (line 70) | private void setUpSongs() {

FILE: app/src/main/java/com/naman14/timber/fragments/FoldersFragment.java
  class FoldersFragment (line 36) | public class FoldersFragment extends Fragment implements StorageSelectDi...
    method onCreateView (line 43) | @Override
    method onViewCreated (line 67) | @Override
    method setItemDecoration (line 82) | private void setItemDecoration() {
    method onActivityCreated (line 86) | @Override
    method onCreateOptionsMenu (line 92) | @Override
    method onOptionsItemSelected (line 98) | @Override
    method updateTheme (line 108) | public void updateTheme() {
    method onDirSelected (line 116) | @Override
    class loadFolders (line 121) | private class loadFolders extends AsyncTask<String, Void, String> {
      method doInBackground (line 123) | @Override
      method onPostExecute (line 133) | @Override
      method onPreExecute (line 146) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/MainFragment.java
  class MainFragment (line 41) | public class MainFragment extends Fragment {
    method onCreate (line 46) | @Override
    method onCreateView (line 52) | @Override
    method onViewCreated (line 78) | @Override
    method setupViewPager (line 89) | private void setupViewPager(ViewPager viewPager) {
    method onPause (line 97) | @Override
    method onResume (line 105) | @Override
    method onStart (line 113) | @Override
    class Adapter (line 118) | static class Adapter extends FragmentPagerAdapter {
      method Adapter (line 122) | public Adapter(FragmentManager fm) {
      method addFragment (line 126) | public void addFragment(Fragment fragment, String title) {
      method getItem (line 131) | @Override
      method getCount (line 136) | @Override
      method getPageTitle (line 141) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/PlaylistFragment.java
  class PlaylistFragment (line 53) | public class PlaylistFragment extends Fragment {
    method onCreate (line 70) | @Override
    method onCreateView (line 80) | @Override
    method initPager (line 111) | private void initPager() {
    method initRecyclerView (line 132) | private void initRecyclerView() {
    method setLayoutManager (line 146) | private void setLayoutManager() {
    method setItemDecoration (line 155) | private void setItemDecoration() {
    method updateLayoutManager (line 165) | private void updateLayoutManager(int column) {
    class SpacesItemDecoration (line 174) | public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
      method SpacesItemDecoration (line 177) | public SpacesItemDecoration(int space) {
      method getItemOffsets (line 181) | @Override
    method onViewCreated (line 195) | @Override
    method onActivityCreated (line 205) | @Override
    method onCreateOptionsMenu (line 211) | @Override
    method onPrepareOptionsMenu (line 218) | @Override
    method onOptionsItemSelected (line 226) | @Override
    method updatePlaylists (line 267) | public void updatePlaylists(final long id) {
    method reloadPlaylists (line 294) | public void reloadPlaylists() {
    method onActivityResult (line 305) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/QueueFragment.java
  class QueueFragment (line 41) | public class QueueFragment extends Fragment implements MusicStateListener {
    method onCreateView (line 46) | @Override
    method onViewCreated (line 70) | @Override
    method restartLoader (line 80) | public void restartLoader() {
    method onPlaylistChanged (line 84) | public void onPlaylistChanged() {
    method onMetaChanged (line 88) | public void onMetaChanged() {
    class loadQueueSongs (line 93) | private class loadQueueSongs extends AsyncTask<String, Void, String> {
      method doInBackground (line 95) | @Override
      method onPostExecute (line 101) | @Override
      method onPreExecute (line 127) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/SettingsFragment.java
  class SettingsFragment (line 41) | public class SettingsFragment extends PreferenceFragment implements Shar...
    method onCreate (line 64) | @Override
    method onSharedPreferenceChanged (line 88) | @Override
    method setPreferenceClickListeners (line 93) | private void setPreferenceClickListeners() {
    method onViewCreated (line 177) | @Override
    method invalidateSettings (line 184) | public void invalidateSettings() {
    method updateLastFM (line 254) | public void updateLastFM() {

FILE: app/src/main/java/com/naman14/timber/fragments/SimilarArtistFragment.java
  class SimilarArtistFragment (line 32) | public class SimilarArtistFragment extends Fragment {
    method newInstance (line 36) | public static SimilarArtistFragment newInstance(long id) {
    method onCreate (line 44) | @Override
    method onCreateView (line 52) | @Override

FILE: app/src/main/java/com/naman14/timber/fragments/SongsFragment.java
  class SongsFragment (line 44) | public class SongsFragment extends Fragment implements MusicStateListener {
    method onCreate (line 50) | @Override
    method onCreateView (line 56) | @Override
    method restartLoader (line 73) | public void restartLoader() {
    method onPlaylistChanged (line 77) | public void onPlaylistChanged() {
    method onMetaChanged (line 81) | public void onMetaChanged() {
    method reloadAdapter (line 86) | private void reloadAdapter() {
    method onActivityCreated (line 102) | @Override
    method onCreateOptionsMenu (line 108) | @Override
    method onOptionsItemSelected (line 114) | @Override
    class loadSongs (line 145) | private class loadSongs extends AsyncTask<String, Void, String> {
      method doInBackground (line 147) | @Override
      method onPostExecute (line 154) | @Override
      method onPreExecute (line 162) | @Override

FILE: app/src/main/java/com/naman14/timber/helpers/MediaButtonIntentReceiver.java
  class MediaButtonIntentReceiver (line 36) | public class MediaButtonIntentReceiver extends WakefulBroadcastReceiver {
    method handleMessage (line 57) | @Override
    method startService (line 102) | private static void startService(Context context, String command) {
    method acquireWakeLockAndSendMessage (line 110) | private static void acquireWakeLockAndSendMessage(Context context, Mes...
    method releaseWakeLockIfHandlerIdle (line 124) | private static void releaseWakeLockIfHandlerIdle() {
    method onReceive (line 138) | @Override

FILE: app/src/main/java/com/naman14/timber/helpers/MusicPlaybackTrack.java
  class MusicPlaybackTrack (line 29) | public class MusicPlaybackTrack implements Parcelable {
    method createFromParcel (line 32) | @Override
    method newArray (line 37) | @Override
    method MusicPlaybackTrack (line 47) | public MusicPlaybackTrack(long id, long sourceId, TimberUtils.IdType t...
    method MusicPlaybackTrack (line 54) | public MusicPlaybackTrack(Parcel in) {
    method describeContents (line 61) | @Override
    method writeToParcel (line 66) | @Override
    method equals (line 74) | @Override

FILE: app/src/main/java/com/naman14/timber/lastfmapi/LastFmClient.java
  class LastFmClient (line 47) | public class LastFmClient {
    method getInstance (line 73) | public static LastFmClient getInstance(Context context) {
    method generateMD5 (line 87) | private static String generateMD5(String in) {
    method getAlbumInfo (line 104) | public void getAlbumInfo(AlbumQuery albumQuery, final AlbumInfoListene...
    method getArtistInfo (line 119) | public void getArtistInfo(ArtistQuery artistQuery, final ArtistInfoLis...
    method getUserLoginInfo (line 134) | public void getUserLoginInfo(UserLoginQuery userLoginQuery, final User...
    method Scrobble (line 155) | public void Scrobble(final ScrobbleQuery scrobbleQuery) {
    class ScrobbleUploader (line 160) | private class ScrobbleUploader {
      method ScrobbleUploader (line 165) | ScrobbleUploader(ScrobbleQuery query) {
      method upload (line 184) | void upload() {
      method save (line 259) | void save() {
    method logout (line 268) | public void logout() {
    method getUsername (line 277) | public String getUsername() {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/LastFmRestService.java
  type LastFmRestService (line 25) | public interface LastFmRestService {
    method getAlbumInfo (line 30) | @Headers("Cache-Control: public")
    method getArtistInfo (line 34) | @Headers("Cache-Control: public")

FILE: app/src/main/java/com/naman14/timber/lastfmapi/LastFmUserRestService.java
  type LastFmUserRestService (line 17) | public interface LastFmUserRestService {
    method getUserLoginInfo (line 21) | @POST(BASE)
    method getScrobbleInfo (line 25) | @POST(BASE)

FILE: app/src/main/java/com/naman14/timber/lastfmapi/RestServiceFactory.java
  class RestServiceFactory (line 29) | public class RestServiceFactory {
    method createStatic (line 33) | public static <T> T createStatic(final Context context, String baseUrl...
    method create (line 65) | public static <T> T create(final Context context, String baseUrl, Clas...

FILE: app/src/main/java/com/naman14/timber/lastfmapi/callbacks/AlbumInfoListener.java
  type AlbumInfoListener (line 19) | public interface AlbumInfoListener {
    method albumInfoSuccess (line 21) | void albumInfoSuccess(LastfmAlbum album);
    method albumInfoFailed (line 23) | void albumInfoFailed();

FILE: app/src/main/java/com/naman14/timber/lastfmapi/callbacks/ArtistInfoListener.java
  type ArtistInfoListener (line 19) | public interface ArtistInfoListener {
    method artistInfoSucess (line 21) | void artistInfoSucess(LastfmArtist artist);
    method artistInfoFailed (line 23) | void artistInfoFailed();

FILE: app/src/main/java/com/naman14/timber/lastfmapi/callbacks/UserListener.java
  type UserListener (line 8) | public interface UserListener {
    method userSuccess (line 9) | void userSuccess();
    method userInfoFailed (line 11) | void userInfoFailed();

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumBio.java
  class AlbumBio (line 17) | public class AlbumBio {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumInfo.java
  class AlbumInfo (line 19) | public class AlbumInfo {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumQuery.java
  class AlbumQuery (line 19) | public class AlbumQuery {
    method AlbumQuery (line 30) | public AlbumQuery(String album, String artist) {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumTracks.java
  class AlbumTracks (line 17) | public class AlbumTracks {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistBio.java
  class ArtistBio (line 19) | public class ArtistBio {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistInfo.java
  class ArtistInfo (line 19) | public class ArtistInfo {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistQuery.java
  class ArtistQuery (line 19) | public class ArtistQuery {
    method ArtistQuery (line 26) | public ArtistQuery(String artist) {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistTag.java
  class ArtistTag (line 19) | public class ArtistTag {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/Artwork.java
  class Artwork (line 19) | public class Artwork {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmAlbum.java
  class LastfmAlbum (line 21) | public class LastfmAlbum {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmArtist.java
  class LastfmArtist (line 21) | public class LastfmArtist {
    class SimilarArtist (line 45) | public class SimilarArtist {
    class ArtistTag (line 53) | public class ArtistTag {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmUserSession.java
  class LastfmUserSession (line 12) | public class LastfmUserSession {
    method getSession (line 18) | public static LastfmUserSession getSession(Context context) {
    method isLogedin (line 27) | public boolean isLogedin(){
    method update (line 31) | public void update(Context context) {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ScrobbleInfo.java
  class ScrobbleInfo (line 6) | public class ScrobbleInfo {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/ScrobbleQuery.java
  class ScrobbleQuery (line 13) | public class ScrobbleQuery {
    method ScrobbleQuery (line 29) | public ScrobbleQuery(String in) {
    method ScrobbleQuery (line 38) | public ScrobbleQuery(String artist, String track, long timestamp) {
    method toString (line 44) | @Override

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/UserLoginInfo.java
  class UserLoginInfo (line 9) | public class UserLoginInfo {

FILE: app/src/main/java/com/naman14/timber/lastfmapi/models/UserLoginQuery.java
  class UserLoginQuery (line 9) | public class UserLoginQuery {
    method UserLoginQuery (line 21) | public UserLoginQuery(String username, String password) {
    method getSignature (line 26) | public String getSignature() {

FILE: app/src/main/java/com/naman14/timber/listeners/MusicStateListener.java
  type MusicStateListener (line 22) | public interface MusicStateListener {
    method restartLoader (line 27) | void restartLoader();
    method onPlaylistChanged (line 32) | void onPlaylistChanged();
    method onMetaChanged (line 37) | void onMetaChanged();

FILE: app/src/main/java/com/naman14/timber/listeners/SimplelTransitionListener.java
  class SimplelTransitionListener (line 20) | @TargetApi(21)
    method onTransitionCancel (line 23) | public void onTransitionCancel(Transition paramTransition) {
    method onTransitionEnd (line 26) | public void onTransitionEnd(Transition paramTransition) {
    method onTransitionPause (line 29) | public void onTransitionPause(Transition paramTransition) {
    method onTransitionResume (line 32) | public void onTransitionResume(Transition paramTransition) {
    method onTransitionStart (line 35) | public void onTransitionStart(Transition paramTransition) {

FILE: app/src/main/java/com/naman14/timber/models/Album.java
  class Album (line 17) | public class Album {
    method Album (line 25) | public Album() {
    method Album (line 34) | public Album(long _id, String _title, String _artistName, long _artist...

FILE: app/src/main/java/com/naman14/timber/models/Artist.java
  class Artist (line 17) | public class Artist {
    method Artist (line 24) | public Artist() {
    method Artist (line 31) | public Artist(long _id, String _name, int _albumCount, int _songCount) {

FILE: app/src/main/java/com/naman14/timber/models/Playlist.java
  class Playlist (line 17) | public class Playlist {
    method Playlist (line 23) | public Playlist() {
    method Playlist (line 29) | public Playlist(long _id, String _name, int _songCount) {

FILE: app/src/main/java/com/naman14/timber/models/Song.java
  class Song (line 17) | public class Song {
    method Song (line 28) | public Song() {
    method Song (line 39) | public Song(long _id, long _albumId, long _artistId, String _title, St...

FILE: app/src/main/java/com/naman14/timber/nowplaying/BaseNowplayingFragment.java
  class BaseNowplayingFragment (line 73) | public class BaseNowplayingFragment extends Fragment implements MusicSta...
    method run (line 104) | @Override
    method run (line 125) | @Override
    method run (line 147) | @Override
    method onClick (line 180) | @Override
    method onClick (line 205) | @Override
    method onCreate (line 229) | @Override
    method onActivityCreated (line 236) | @Override
    method onCreateOptionsMenu (line 242) | @Override
    method onOptionsItemSelected (line 248) | @Override
    method onPause (line 264) | @Override
    method onResume (line 270) | @Override
    method setSongDetails (line 281) | public void setSongDetails(View view) {
    method onViewCreated (line 371) | @Override
    method setSongDetails (line 381) | private void setSongDetails() {
    method updateShuffleState (line 433) | public void updateShuffleState() {
    method updateRepeatState (line 457) | public void updateRepeatState() {
    method setSeekBarListener (line 486) | private void setSeekBarListener() {
    method updateSongDetails (line 526) | public void updateSongDetails() {
    method setQueueSongs (line 606) | public void setQueueSongs() {
    method updatePlayPauseButton (line 614) | public void updatePlayPauseButton() {
    method updatePlayPauseFloatingButton (line 628) | public void updatePlayPauseFloatingButton() {
    method notifyPlayingDrawableChange (line 636) | public void notifyPlayingDrawableChange() {
    method restartLoader (line 641) | public void restartLoader() {
    method onPlaylistChanged (line 645) | public void onPlaylistChanged() {
    method onMetaChanged (line 649) | public void onMetaChanged() {
    method setMusicStateListener (line 656) | public void setMusicStateListener() {
    method doAlbumArtStuff (line 660) | public void doAlbumArtStuff(Bitmap loadedImage) {
    method changeDigit (line 664) | public void changeDigit(TimelyView tv, int end) {
    method changeDigit (line 670) | public void changeDigit(TimelyView tv, int start, int end) {
    method tv11 (line 680) | public void tv11(int a) {
    method tv12 (line 687) | public void tv12(int a) {
    method tv13 (line 694) | public void tv13(int a) {
    method tv14 (line 701) | public void tv14(int a) {
    method tv15 (line 708) | public void tv15(int a) {
    method initGestures (line 715) | protected void initGestures(View v) {
    class loadQueueSongs (line 726) | private class loadQueueSongs extends AsyncTask<String, Void, String> {
      method doInBackground (line 728) | @Override
      method onPostExecute (line 736) | @Override
      method onPreExecute (line 747) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber1.java
  class Timber1 (line 30) | public class Timber1 extends BaseNowplayingFragment {
    method onCreateView (line 32) | @Override
    method updateShuffleState (line 44) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber2.java
  class Timber2 (line 36) | public class Timber2 extends BaseNowplayingFragment {
    method onCreateView (line 40) | @Override
    method updateShuffleState (line 54) | @Override
    method updateRepeatState (line 77) | @Override
    method doAlbumArtStuff (line 110) | @Override
    class setBlurredAlbumArt (line 116) | private class setBlurredAlbumArt extends AsyncTask<Bitmap, Void, Drawa...
      method doInBackground (line 118) | @Override
      method onPostExecute (line 129) | @Override
      method onPreExecute (line 147) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber3.java
  class Timber3 (line 24) | public class Timber3 extends BaseNowplayingFragment {
    method onCreateView (line 26) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber4.java
  class Timber4 (line 39) | public class Timber4 extends BaseNowplayingFragment {
    method onCreateView (line 45) | @Override
    method updateShuffleState (line 62) | @Override
    method updateRepeatState (line 85) | @Override
    method doAlbumArtStuff (line 117) | @Override
    method setupHorizontalQueue (line 123) | private void setupHorizontalQueue() {
    class setBlurredAlbumArt (line 130) | private class setBlurredAlbumArt extends AsyncTask<Bitmap, Void, Drawa...
      method doInBackground (line 132) | @Override
      method onPostExecute (line 143) | @Override
      method onPreExecute (line 161) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber5.java
  class Timber5 (line 30) | public class Timber5 extends BaseNowplayingFragment {
    method onCreateView (line 36) | @Override
    method updateShuffleState (line 52) | @Override
    method updateRepeatState (line 75) | @Override
    method doAlbumArtStuff (line 108) | @Override
    method setupSlidingQueue (line 114) | private void setupSlidingQueue() {
    class setBlurredAlbumArt (line 122) | private class setBlurredAlbumArt extends AsyncTask<Bitmap, Void, Drawa...
      method doInBackground (line 124) | @Override
      method onPostExecute (line 135) | @Override
      method onPreExecute (line 153) | @Override

FILE: app/src/main/java/com/naman14/timber/nowplaying/Timber6.java
  class Timber6 (line 27) | public class Timber6 extends BaseNowplayingFragment {
    method onCreateView (line 32) | @Override
    method updateShuffleState (line 58) | @Override
    method updateRepeatState (line 81) | @Override
    method onMetaChanged (line 114) | @Override

FILE: app/src/main/java/com/naman14/timber/permissions/Nammu.java
  class Nammu (line 42) | public class Nammu {
    method init (line 50) | public static void init(Context context) {
    method verifyPermissions (line 59) | public static boolean verifyPermissions(int[] grantResults) {
    method hasPermission (line 71) | public static boolean hasPermission(Activity activity, String permissi...
    method hasPermission (line 78) | public static boolean hasPermission(Activity activity, String[] permis...
    method shouldShowRequestPermissionRationale (line 91) | public static boolean shouldShowRequestPermissionRationale(Activity ac...
    method askForPermission (line 95) | public static void askForPermission(Activity activity, String permissi...
    method askForPermission (line 99) | public static void askForPermission(Activity activity, String[] permis...
    method onRequestPermissionsResult (line 113) | public static void onRequestPermissionsResult(int requestCode, String[...
    method getGrantedPermissions (line 137) | public static ArrayList<String> getGrantedPermissions() {
    method refreshMonitoredList (line 195) | public static void refreshMonitoredList() {
    method getPreviousPermissions (line 208) | public static ArrayList<String> getPreviousPermissions() {
    method getIgnoredPermissions (line 214) | public static ArrayList<String> getIgnoredPermissions() {
    method isIgnoredPermission (line 223) | public static boolean isIgnoredPermission(String permission) {
    method ignorePermission (line 235) | public static void ignorePermission(String permission) {
    method permissionCompare (line 250) | public static void permissionCompare(PermissionListener permissionList...
    method checkPermission (line 298) | public static boolean checkPermission(String permissionName) {

FILE: app/src/main/java/com/naman14/timber/permissions/PermissionCallback.java
  type PermissionCallback (line 27) | public interface PermissionCallback {
    method permissionGranted (line 28) | void permissionGranted();
    method permissionRefused (line 30) | void permissionRefused();

FILE: app/src/main/java/com/naman14/timber/permissions/PermissionListener.java
  type PermissionListener (line 27) | public interface PermissionListener {
    method permissionsChanged (line 33) | void permissionsChanged(String permissionChanged);
    method permissionsGranted (line 40) | void permissionsGranted(String permissionGranted);
    method permissionsRemoved (line 47) | void permissionsRemoved(String permissionRemoved);

FILE: app/src/main/java/com/naman14/timber/permissions/PermissionRequest.java
  class PermissionRequest (line 30) | public class PermissionRequest {
    method PermissionRequest (line 36) | public PermissionRequest(int requestCode) {
    method PermissionRequest (line 40) | public PermissionRequest(ArrayList<String> permissions, PermissionCall...
    method getPermissions (line 49) | public ArrayList<String> getPermissions() {
    method getRequestCode (line 53) | public int getRequestCode() {
    method getPermissionCallback (line 57) | public PermissionCallback getPermissionCallback() {
    method equals (line 61) | public boolean equals(Object object) {
    method hashCode (line 71) | @Override

FILE: app/src/main/java/com/naman14/timber/provider/MusicDB.java
  class MusicDB (line 23) | public class MusicDB extends SQLiteOpenHelper {
    method MusicDB (line 31) | public MusicDB(final Context context) {
    method getInstance (line 37) | public static final synchronized MusicDB getInstance(final Context con...
    method onCreate (line 44) | @Override
    method onUpgrade (line 52) | @Override
    method onDowngrade (line 60) | @Override

FILE: app/src/main/java/com/naman14/timber/provider/MusicPlaybackState.java
  class MusicPlaybackState (line 34) | public class MusicPlaybackState {
    method MusicPlaybackState (line 39) | public MusicPlaybackState(final Context context) {
    method getInstance (line 43) | public static final synchronized MusicPlaybackState getInstance(final ...
    method onCreate (line 50) | public void onCreate(final SQLiteDatabase db) {
    method onUpgrade (line 81) | public void onUpgrade(final SQLiteDatabase db, final int oldVersion, f...
    method onDowngrade (line 88) | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVers...
    method saveState (line 95) | public synchronized void saveState(final ArrayList<MusicPlaybackTrack>...
    method getQueue (line 151) | public ArrayList<MusicPlaybackTrack> getQueue() {
    method getHistory (line 177) | public LinkedList<Integer> getHistory(final int playlistSize) {
    class PlaybackQueueColumns (line 203) | public class PlaybackQueueColumns {
    class PlaybackHistoryColumns (line 212) | public class PlaybackHistoryColumns {

FILE: app/src/main/java/com/naman14/timber/provider/RecentStore.java
  class RecentStore (line 24) | public class RecentStore {
    method RecentStore (line 32) | public RecentStore(final Context context) {
    method getInstance (line 36) | public static final synchronized RecentStore getInstance(final Context...
    method onCreate (line 43) | public void onCreate(final SQLiteDatabase db) {
    method onUpgrade (line 49) | public void onUpgrade(final SQLiteDatabase db, final int oldVersion, f...
    method onDowngrade (line 52) | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVers...
    method addSongId (line 57) | public void addSongId(final long songId) {
    method removeItem (line 112) | public void removeItem(final long songId) {
    method deleteAll (line 120) | public void deleteAll() {
    method queryRecentIds (line 126) | public Cursor queryRecentIds(final String limit) {
    type RecentStoreColumns (line 133) | public interface RecentStoreColumns {

FILE: app/src/main/java/com/naman14/timber/provider/SearchHistory.java
  class SearchHistory (line 26) | public class SearchHistory {
    method SearchHistory (line 34) | public SearchHistory(final Context context) {
    method getInstance (line 38) | public static final synchronized SearchHistory getInstance(final Conte...
    method onCreate (line 45) | public void onCreate(final SQLiteDatabase db) {
    method onUpgrade (line 51) | public void onUpgrade(final SQLiteDatabase db, final int oldVersion, f...
    method onDowngrade (line 54) | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVers...
    method addSearchString (line 59) | public void addSearchString(final String searchString) {
    method queryRecentSearches (line 112) | public Cursor queryRecentSearches(final String limit) {
    method getRecentSearches (line 119) | public ArrayList<String> getRecentSearches() {
    type SearchHistoryColumns (line 142) | public interface SearchHistoryColumns {

FILE: app/src/main/java/com/naman14/timber/provider/SongPlayCount.java
  class SongPlayCount (line 33) | public class SongPlayCount {
    method SongPlayCount (line 57) | public SongPlayCount(final Context context) {
    method getInstance (line 70) | public static final synchronized SongPlayCount getInstance(final Conte...
    method calculateScore (line 84) | private static float calculateScore(final int[] playCounts) {
    method getColumnNameForWeek (line 103) | private static String getColumnNameForWeek(final int week) {
    method getScoreMultiplierForWeek (line 113) | private static float getScoreMultiplierForWeek(final int week) {
    method getColumnIndexForWeek (line 125) | private static int getColumnIndexForWeek(final int week) {
    method onCreate (line 130) | public void onCreate(final SQLiteDatabase db) {
    method onUpgrade (line 155) | public void onUpgrade(final SQLiteDatabase db, final int oldVersion, f...
    method onDowngrade (line 159) | public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVers...
    method bumpSongCount (line 170) | public void bumpSongCount(final long songId) {
    method createNewPlayedEntry (line 185) | private void createNewPlayedEntry(final SQLiteDatabase database, final...
    method updateExistingRow (line 207) | private void updateExistingRow(final SQLiteDatabase database, final lo...
    method deleteAll (line 304) | public void deleteAll() {
    method getTopPlayedResults (line 316) | public Cursor getTopPlayedResults(int numResults) {
    method getTopPlayedResultsForList (line 331) | public long[] getTopPlayedResultsForList(long[] ids) {
    method updateResults (line 409) | private synchronized void updateResults() {
    method removeItem (line 446) | public void removeItem(final long songId) {
    method deleteEntry (line 457) | private void deleteEntry(final SQLiteDatabase database, final String s...
    type SongPlayCountColumns (line 461) | public interface SongPlayCountColumns {

FILE: app/src/main/java/com/naman14/timber/slidinguppanel/SlidingUpPanelLayout.java
  class SlidingUpPanelLayout (line 25) | public class SlidingUpPanelLayout extends ViewGroup {
    method SlidingUpPanelLayout (line 189) | public SlidingUpPanelLayout(Context context) {
    method SlidingUpPanelLayout (line 193) | public SlidingUpPanelLayout(Context context, AttributeSet attrs) {
    method SlidingUpPanelLayout (line 197) | public SlidingUpPanelLayout(Context context, AttributeSet attrs, int d...
    method hasOpaqueBackground (line 274) | private static boolean hasOpaqueBackground(View v) {
    method onFinishInflate (line 282) | @Override
    method getCoveredFadeColor (line 293) | public int getCoveredFadeColor() {
    method setCoveredFadeColor (line 303) | public void setCoveredFadeColor(int color) {
    method isSlidingEnabled (line 308) | public boolean isSlidingEnabled() {
    method setSlidingEnabled (line 317) | public void setSlidingEnabled(boolean enabled) {
    method getPanelHeight (line 324) | public int getPanelHeight() {
    method setPanelHeight (line 333) | public void setPanelHeight(int val) {
    method setSlidePanelOffset (line 344) | public void setSlidePanelOffset(int val) {
    method getCurrentParalaxOffset (line 352) | public int getCurrentParalaxOffset() {
    method getDirectionalSlideOffset (line 363) | protected float getDirectionalSlideOffset() {
    method setPanelSlideListener (line 372) | public void setPanelSlideListener(PanelSlideListener listener) {
    method setDragView (line 381) | public void setDragView(View dragView) {
    method getAnchorPoint (line 411) | public float getAnchorPoint() {
    method setAnchorPoint (line 421) | public void setAnchorPoint(float anchorPoint) {
    method isOverlayed (line 430) | public boolean isOverlayed() {
    method setOverlayed (line 439) | public void setOverlayed(boolean overlayed) {
    method dispatchOnPanelSlide (line 443) | void dispatchOnPanelSlide(View panel) {
    method dispatchOnPanelExpanded (line 449) | void dispatchOnPanelExpanded(View panel) {
    method dispatchOnPanelCollapsed (line 456) | void dispatchOnPanelCollapsed(View panel) {
    method dispatchOnPanelAnchored (line 463) | void dispatchOnPanelAnchored(View panel) {
    method dispatchOnPanelHidden (line 470) | void dispatchOnPanelHidden(View panel) {
    method updateObscuredViewVisibility (line 477) | void updateObscuredViewVisibility() {
    method setAllChildrenVisible (line 512) | void setAllChildrenVisible() {
    method onAttachedToWindow (line 521) | @Override
    method onDetachedFromWindow (line 527) | @Override
    method onMeasure (line 533) | @Override
    method onLayout (line 616) | @Override
    method onSizeChanged (line 675) | @Override
    method setEnableDragViewTouchEvents (line 690) | public void setEnableDragViewTouchEvents(boolean enabled) {
    method setEnabled (line 694) | @Override
    method onInterceptTouchEvent (line 702) | @Override
    method onTouchEvent (line 750) | @Override
    method isDragViewUnder (line 759) | private boolean isDragViewUnder(int x, int y) {
    method expandPanel (line 771) | private boolean expandPanel(View pane, int initialVelocity, float mSli...
    method collapsePanel (line 775) | private boolean collapsePanel(View pane, int initialVelocity) {
    method computePanelTopPosition (line 782) | private int computePanelTopPosition(float slideOffset) {
    method computeSlideOffset (line 794) | private float computeSlideOffset(int topPosition) {
    method collapsePanel (line 811) | public boolean collapsePanel() {
    method expandPanel (line 827) | public boolean expandPanel() {
    method anchorPanel (line 841) | public boolean anchorPanel() {
    method expandPanel (line 856) | public boolean expandPanel(float mSlideOffset) {
    method isPanelExpanded (line 867) | public boolean isPanelExpanded() {
    method isPanelAnchored (line 876) | public boolean isPanelAnchored() {
    method isPanelHidden (line 885) | public boolean isPanelHidden() {
    method showPanel (line 892) | public void showPanel() {
    method hidePanel (line 906) | public void hidePanel() {
    method onPanelDragged (line 916) | @SuppressLint("NewApi")
    method drawChild (line 945) | @Override
    method smoothSlideTo (line 984) | boolean smoothSlideTo(float slideOffset, int velocity) {
    method computeScroll (line 999) | @Override
    method draw (line 1011) | @Override
    method canScroll (line 1049) | protected boolean canScroll(View v, boolean checkV, int dx, int x, int...
    method generateDefaultLayoutParams (line 1069) | @Override
    method generateLayoutParams (line 1074) | @Override
    method checkLayoutParams (line 1081) | @Override
    method generateLayoutParams (line 1086) | @Override
    method onSaveInstanceState (line 1091) | @Override
    method onRestoreInstanceState (line 1101) | @Override
    type SlideState (line 1111) | private enum SlideState {
    type PanelSlideListener (line 1122) | public interface PanelSlideListener {
      method onPanelSlide (line 1129) | void onPanelSlide(View panel, float slideOffset);
      method onPanelCollapsed (line 1136) | void onPanelCollapsed(View panel);
      method onPanelExpanded (line 1143) | void onPanelExpanded(View panel);
      method onPanelAnchored (line 1150) | void onPanelAnchored(View panel);
      method onPanelHidden (line 1157) | void onPanelHidden(View panel);
    class SimplePanelSlideListener (line 1164) | public static class SimplePanelSlideListener implements PanelSlideList...
      method onPanelSlide (line 1165) | @Override
      method onPanelCollapsed (line 1169) | @Override
      method onPanelExpanded (line 1173) | @Override
      method onPanelAnchored (line 1177) | @Override
      method onPanelHidden (line 1181) | @Override
    class LayoutParams (line 1186) | public static class LayoutParams extends MarginLayoutParams {
      method LayoutParams (line 1191) | public LayoutParams() {
      method LayoutParams (line 1195) | public LayoutParams(int width, int height) {
      method LayoutParams (line 1199) | public LayoutParams(ViewGroup.LayoutParams source) {
      method LayoutParams (line 1203) | public LayoutParams(MarginLayoutParams source) {
      method LayoutParams (line 1207) | public LayoutParams(LayoutParams source) {
      method LayoutParams (line 1211) | public LayoutParams(Context c, AttributeSet attrs) {
    class SavedState (line 1220) | static class SavedState extends BaseSavedState {
      method createFromParcel (line 1223) | @Override
      method newArray (line 1228) | @Override
      method SavedState (line 1235) | SavedState(Parcelable superState) {
      method SavedState (line 1239) | private SavedState(Parcel in) {
      method writeToParcel (line 1248) | @Override
    class DragHelperCallback (line 1255) | private class DragHelperCallback extends ViewDragHelper.Callback {
      method tryCaptureView (line 1257) | @Override
      method onViewDragStateChanged (line 1266) | @Override
      method onViewCaptured (line 1294) | @Override
      method onViewPositionChanged (line 1299) | @Override
      method onViewReleased (line 1305) | @Override
      method getViewVerticalDragRange (line 1337) | @Override
      method clampViewPositionVertical (line 1342) | @Override

FILE: app/src/main/java/com/naman14/timber/slidinguppanel/ViewDragHelper.java
  class ViewDragHelper (line 39) | public class ViewDragHelper {
    method getInterpolation (line 99) | public float getInterpolation(float t) {
    method run (line 128) | public void run() {
    method ViewDragHelper (line 142) | private ViewDragHelper(Context context, ViewGroup forParent, Callback ...
    method create (line 170) | public static ViewDragHelper create(ViewGroup forParent, Callback cb) {
    method create (line 183) | public static ViewDragHelper create(ViewGroup forParent, float sensiti...
    method getMinVelocity (line 196) | public float getMinVelocity() {
    method setMinVelocity (line 206) | public void setMinVelocity(float minVel) {
    method getViewDragState (line 216) | public int getViewDragState() {
    method setEdgeTrackingEnabled (line 232) | public void setEdgeTrackingEnabled(int edgeFlags) {
    method getEdgeSize (line 243) | public int getEdgeSize() {
    method captureChildView (line 255) | public void captureChildView(View childView, int activePointerId) {
    method getCapturedView (line 270) | public View getCapturedView() {
    method getActivePointerId (line 278) | public int getActivePointerId() {
    method getTouchSlop (line 285) | public int getTouchSlop() {
    method cancel (line 293) | public void cancel() {
    method abort (line 307) | public void abort() {
    method smoothSlideViewTo (line 334) | public boolean smoothSlideViewTo(View child, int finalLeft, int finalT...
    method settleCapturedViewAt (line 352) | public boolean settleCapturedViewAt(int finalLeft, int finalTop) {
    method forceSettleCapturedViewAt (line 372) | private boolean forceSettleCapturedViewAt(int finalLeft, int finalTop,...
    method computeSettleDuration (line 392) | private int computeSettleDuration(View child, int dx, int dy, int xvel...
    method computeAxisDuration (line 413) | private int computeAxisDuration(int delta, int velocity, int motionRan...
    method clampMag (line 445) | private int clampMag(int value, int absMin, int absMax) {
    method clampMag (line 462) | private float clampMag(float value, float absMin, float absMax) {
    method distanceInfluenceForSnapDuration (line 469) | private float distanceInfluenceForSnapDuration(float f) {
    method flingCapturedView (line 485) | public void flingCapturedView(int minLeft, int minTop, int maxLeft, in...
    method continueSettling (line 510) | public boolean continueSettling(boolean deferCallbacks) {
    method dispatchViewReleased (line 554) | private void dispatchViewReleased(float xvel, float yvel) {
    method clearMotionHistory (line 565) | private void clearMotionHistory() {
    method clearMotionHistory (line 579) | private void clearMotionHistory(int pointerId) {
    method ensureMotionHistorySizeForId (line 593) | private void ensureMotionHistorySizeForId(int pointerId) {
    method saveInitialMotion (line 623) | private void saveInitialMotion(float x, float y, int pointerId) {
    method saveLastMotion (line 631) | private void saveLastMotion(MotionEvent ev) {
    method isPointerDown (line 655) | public boolean isPointerDown(int pointerId) {
    method setDragState (line 659) | void setDragState(int state) {
    method tryCaptureViewForDrag (line 678) | boolean tryCaptureViewForDrag(View toCapture, int pointerId) {
    method canScroll (line 703) | protected boolean canScroll(View v, boolean checkV, int dx, int dy, in...
    method shouldInterceptTouchEvent (line 734) | public boolean shouldInterceptTouchEvent(MotionEvent ev) {
    method processTouchEvent (line 841) | public void processTouchEvent(MotionEvent ev) {
    method reportNewEdgeDrags (line 992) | private void reportNewEdgeDrags(float dx, float dy, int pointerId) {
    method checkNewEdgeDrag (line 1013) | private boolean checkNewEdgeDrag(float delta, float odelta, int pointe...
    method checkTouchSlop (line 1040) | private boolean checkTouchSlop(View child, float dx, float dy) {
    method checkTouchSlop (line 1071) | public boolean checkTouchSlop(int directions) {
    method checkTouchSlop (line 1096) | public boolean checkTouchSlop(int directions, int pointerId) {
    method isEdgeTouched (line 1126) | public boolean isEdgeTouched(int edges) {
    method isEdgeTouched (line 1146) | public boolean isEdgeTouched(int edges, int pointerId) {
    method releaseViewForPointerUp (line 1150) | private void releaseViewForPointerUp() {
    method dragTo (line 1161) | private void dragTo(int left, int top, int dx, int dy) {
    method isCapturedViewUnder (line 1192) | public boolean isCapturedViewUnder(int x, int y) {
    method isViewUnder (line 1205) | public boolean isViewUnder(View view, int x, int y) {
    method findTopChildUnder (line 1223) | public View findTopChildUnder(int x, int y) {
    method getEdgesTouched (line 1235) | private int getEdgesTouched(int x, int y) {
    class Callback (line 1253) | public static abstract class Callback {
      method onViewDragStateChanged (line 1263) | public void onViewDragStateChanged(int state) {
      method onViewPositionChanged (line 1275) | public void onViewPositionChanged(View changedView, int left, int to...
      method onViewCaptured (line 1287) | public void onViewCaptured(View capturedChild, int activePointerId) {
      method onViewReleased (line 1308) | public void onViewReleased(View releasedChild, float xvel, float yve...
      method onEdgeTouched (line 1322) | public void onEdgeTouched(int edgeFlags, int pointerId) {
      method onEdgeLock (line 1334) | public boolean onEdgeLock(int edgeFlags) {
      method onEdgeDragStarted (line 1349) | public void onEdgeDragStarted(int edgeFlags, int pointerId) {
      method getOrderedChildIndex (line 1358) | public int getOrderedChildIndex(int index) {
      method getViewHorizontalDragRange (line 1369) | public int getViewHorizontalDragRange(View child) {
      method getViewVerticalDragRange (line 1380) | public int getViewVerticalDragRange(View child) {
      method tryCaptureView (line 1400) | public abstract boolean tryCaptureView(View child, int pointerId);
      method clampViewPositionHorizontal (line 1412) | public int clampViewPositionHorizontal(View child, int left, int dx) {
      method clampViewPositionVertical (line 1426) | public int clampViewPositionVertical(View child, int top, int dy) {

FILE: app/src/main/java/com/naman14/timber/subfragments/ArtistTagFragment.java
  class ArtistTagFragment (line 26) | public class ArtistTagFragment extends Fragment {
    method newInstance (line 30) | public static ArtistTagFragment newInstance(int pageNumber) {
    method onCreateView (line 38) | @Override

FILE: app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java
  class LyricsFragment (line 34) | public class LyricsFragment extends Fragment {
    method onCreateView (line 40) | @Nullable
    method loadLyrics (line 53) | private void loadLyrics() {
    method setupToolbar (line 99) | private void setupToolbar() {
    method onResume (line 110) | @Override
    method getRealPathFromURI (line 116) | private String getRealPathFromURI(Uri contentUri) {

FILE: app/src/main/java/com/naman14/timber/subfragments/PlaylistPagerFragment.java
  class PlaylistPagerFragment (line 50) | public class PlaylistPagerFragment extends Fragment {
    method newInstance (line 64) | public static PlaylistPagerFragment newInstance(int pageNumber) {
    method onCreateView (line 72) | @Override
    method onViewCreated (line 108) | @Override
    method setUpPlaylistDetails (line 113) | private void setUpPlaylistDetails() {
    method getPlaylistType (line 139) | private String getPlaylistType() {
    class loadPlaylistImage (line 155) | private class loadPlaylistImage extends AsyncTask<String, Void, String> {
      method doInBackground (line 157) | @Override
      method onPostExecute (line 222) | @Override
      method onPreExecute (line 237) | @Override

FILE: app/src/main/java/com/naman14/timber/subfragments/QuickControlsFragment.java
  class QuickControlsFragment (line 54) | public class QuickControlsFragment extends Fragment implements MusicStat...
    method run (line 73) | @Override
    method onClick (line 93) | @Override
    method onClick (line 115) | @Override
    method onCreateView (line 136) | @Override
    method onPause (line 229) | @Override
    method updateNowplayingCard (line 235) | public void updateNowplayingCard() {
    method onStart (line 277) | @Override
    method onStop (line 283) | @Override
    method onResume (line 289) | @Override
    method updateState (line 299) | public void updateState() {
    method restartLoader (line 321) | public void restartLoader() {
    method onPlaylistChanged (line 325) | public void onPlaylistChanged() {
    method onMetaChanged (line 329) | public void onMetaChanged() {
    class setBlurredAlbumArt (line 334) | private class setBlurredAlbumArt extends AsyncTask<Bitmap, Void, Drawa...
      method doInBackground (line 336) | @Override
      method onPostExecute (line 347) | @Override
      method onPreExecute (line 365) | @Override

FILE: app/src/main/java/com/naman14/timber/subfragments/StyleSelectorFragment.java
  class StyleSelectorFragment (line 32) | public class StyleSelectorFragment extends Fragment {
    method newInstance (line 40) | public static StyleSelectorFragment newInstance(String what) {
    method onCreate (line 48) | @Override
    method onCreateView (line 58) | @Override
    method updateCurrentStyle (line 92) | public void updateCurrentStyle() {
    method scrollToCurrentStyle (line 100) | public void scrollToCurrentStyle() {

FILE: app/src/main/java/com/naman14/timber/subfragments/SubStyleSelectorFragment.java
  class SubStyleSelectorFragment (line 39) | public class SubStyleSelectorFragment extends Fragment {
    method newInstance (line 49) | public static SubStyleSelectorFragment newInstance(int pageNumber, Str...
    method onCreateView (line 58) | @Override
    method isUnlocked (line 113) | private boolean isUnlocked() {
    method onResume (line 117) | @Override
    method updateLockedStatus (line 123) | private void updateLockedStatus() {
    method showPurchaseDialog (line 133) | private void showPurchaseDialog() {
    method setCurrentStyle (line 158) | public void setCurrentStyle() {
    method setPreferences (line 171) | private void setPreferences() {
    method getStyleForPageNumber (line 184) | private String getStyleForPageNumber() {

FILE: app/src/main/java/com/naman14/timber/timely/TimelyView.java
  class TimelyView (line 35) | public class TimelyView extends View {
    method get (line 38) | @Override
    method set (line 43) | @Override
    method TimelyView (line 54) | public TimelyView(Context context) {
    method TimelyView (line 59) | public TimelyView(Context context, AttributeSet attrs) {
    method TimelyView (line 66) | public TimelyView(Context context, AttributeSet attrs, int defStyleAtt...
    method getControlPoints (line 71) | public float[][] getControlPoints() {
    method setControlPoints (line 75) | public void setControlPoints(float[][] controlPoints) {
    method animate (line 80) | public ObjectAnimator animate(int start, int end) {
    method animate (line 87) | public ObjectAnimator animate(int end) {
    method onDraw (line 94) | @Override
    method onMeasure (line 116) | @Override
    method init (line 137) | private void init() {

FILE: app/src/main/java/com/naman14/timber/timely/animation/TimelyEvaluator.java
  class TimelyEvaluator (line 21) | public class TimelyEvaluator implements TypeEvaluator<float[][]> {
    method evaluate (line 24) | @Override
    method initCache (line 37) | private void initCache(int pointsCount) {

FILE: app/src/main/java/com/naman14/timber/timely/model/NumberUtils.java
  class NumberUtils (line 7) | public class NumberUtils {
    method getControlPointsFor (line 9) | public static float[][] getControlPointsFor(int start) {

FILE: app/src/main/java/com/naman14/timber/timely/model/core/Figure.java
  class Figure (line 22) | public abstract class Figure {
    method Figure (line 30) | protected Figure(float[][] controlPoints) {
    method getPointsCount (line 35) | public int getPointsCount() {
    method getControlPoints (line 39) | public float[][] getControlPoints() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Eight.java
  class Eight (line 5) | public class Eight extends Figure {
    method Eight (line 16) | protected Eight() {
    method getInstance (line 20) | public static Eight getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Five.java
  class Five (line 5) | public class Five extends Figure {
    method Five (line 16) | protected Five() {
    method getInstance (line 20) | public static Five getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Four.java
  class Four (line 5) | public class Four extends Figure {
    method Four (line 17) | protected Four() {
    method getInstance (line 21) | public static Four getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Nine.java
  class Nine (line 5) | public class Nine extends Figure {
    method Nine (line 16) | protected Nine() {
    method getInstance (line 20) | public static Nine getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Null.java
  class Null (line 6) | public class Null extends Figure {
    method Null (line 17) | protected Null() {
    method getInstance (line 21) | public static Null getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/One.java
  class One (line 5) | public class One extends Figure {
    method One (line 16) | protected One() {
    method getInstance (line 20) | public static One getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Seven.java
  class Seven (line 5) | public class Seven extends Figure {
    method Seven (line 16) | protected Seven() {
    method getInstance (line 20) | public static Seven getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Six.java
  class Six (line 5) | public class Six extends Figure {
    method Six (line 16) | protected Six() {
    method getInstance (line 20) | public static Six getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Three.java
  class Three (line 5) | public class Three extends Figure {
    method Three (line 16) | protected Three() {
    method getInstance (line 20) | public static Three getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Two.java
  class Two (line 5) | public class Two extends Figure {
    method Two (line 16) | protected Two() {
    method getInstance (line 20) | public static Two getInstance() {

FILE: app/src/main/java/com/naman14/timber/timely/model/number/Zero.java
  class Zero (line 5) | public class Zero extends Figure {
    method Zero (line 16) | protected Zero() {
    method getInstance (line 20) | public static Zero getInstance() {

FILE: app/src/main/java/com/naman14/timber/transition/PlayTransition.java
  class PlayTransition (line 47) | @TargetApi(21)
    method PlayTransition (line 59) | public PlayTransition() {
    method PlayTransition (line 62) | public PlayTransition(Context context, AttributeSet attrs) {
    method setColor (line 69) | public void setColor(int color) {
    method getColor (line 73) | public int getColor() {
    method getTransitionProperties (line 77) | @Override
    method captureValues (line 82) | private void captureValues(TransitionValues transitionValues) {
    method captureEndValues (line 92) | @Override
    method captureStartValues (line 101) | @Override
    method createAnimator (line 115) | @Override
    method addViewToOverlay (line 232) | private View addViewToOverlay(ViewGroup sceneRoot, int width, int heig...
    method createCircularReveal (line 243) | private Animator createCircularReveal(View view, float startRadius, fl...
    method calculateMaxRadius (line 252) | static float calculateMaxRadius(View view) {
    method calculateMinRadius (line 259) | static int calculateMinRadius(View view) {
    class NoPauseAnimator (line 263) | private static class NoPauseAnimator extends Animator {
      method NoPauseAnimator (line 268) | public NoPauseAnimator(Animator animator) {
      method addListener (line 272) | @Override
      method cancel (line 281) | @Override
      method end (line 286) | @Override
      method getDuration (line 291) | @Override
      method getInterpolator (line 296) | @Override
      method getListeners (line 301) | @Override
      method getStartDelay (line 306) | @Override
      method isPaused (line 311) | @Override
      method isRunning (line 316) | @Override
      method isStarted (line 321) | @Override
      method removeAllListeners (line 326) | @Override
      method removeListener (line 332) | @Override
      method setDuration (line 341) | @Override
      method setInterpolator (line 347) | @Override
      method setStartDelay (line 352) | @Override
      method setTarget (line 357) | @Override
      method setupEndValues (line 362) | @Override
      method setupStartValues (line 367) | @Override
      method start (line 372) | @Override
    class AnimatorListenerWrapper (line 378) | private static class AnimatorListenerWrapper implements Animator.Anima...
      method AnimatorListenerWrapper (line 382) | public AnimatorListenerWrapper(Animator animator, Animator.AnimatorL...
      method onAnimationStart (line 387) | @Override
      method onAnimationEnd (line 392) | @Override
      method onAnimationCancel (line 397) | @Override
      method onAnimationRepeat (line 402) | @Override
    class NoOverlapView (line 408) | private static class NoOverlapView extends View {
      method NoOverlapView (line 409) | public NoOverlapView(Context context) {
      method hasOverlappingRendering (line 413) | @Override

FILE: app/src/main/java/com/naman14/timber/utils/ATEUtils.java
  class ATEUtils (line 24) | public class ATEUtils {
    method setStatusBarColor (line 26) | public static void setStatusBarColor(Activity activity, String key, in...
    method applyTaskDescription (line 74) | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    method getStatusBarColor (line 88) | public static int getStatusBarColor(int primaryColor) {
    method setFabBackgroundTint (line 95) | public static void setFabBackgroundTint(FloatingActionButton fab, int ...

FILE: app/src/main/java/com/naman14/timber/utils/Constants.java
  class Constants (line 17) | public class Constants {

FILE: app/src/main/java/com/naman14/timber/utils/FabAnimationUtils.java
  class FabAnimationUtils (line 28) | public class FabAnimationUtils {
    method scaleIn (line 33) | public static void scaleIn(final View fab) {
    method scaleIn (line 37) | public static void scaleIn(final View fab, long duration, final ScaleC...
    method scaleOut (line 83) | public static void scaleOut(final View fab) {
    method scaleOut (line 87) | public static void scaleOut(final View fab, final ScaleCallback callba...
    method scaleOut (line 91) | public static void scaleOut(final View fab, long duration, final Scale...
    type ScaleCallback (line 135) | public interface ScaleCallback {
      method onAnimationStart (line 136) | void onAnimationStart();
      method onAnimationEnd (line 138) | void onAnimationEnd();

FILE: app/src/main/java/com/naman14/timber/utils/Helpers.java
  class Helpers (line 42) | public class Helpers {
    method showAbout (line 44) | public static void showAbout(AppCompatActivity activity) {
    method getATEKey (line 56) | public static String getATEKey(Context context) {
    class AboutDialog (line 61) | public static class AboutDialog extends DialogFragment {
      method AboutDialog (line 63) | public AboutDialog() {
      method onCreateDialog (line 66) | @Override

FILE: app/src/main/java/com/naman14/timber/utils/ImageUtils.java
  class ImageUtils (line 45) | public class ImageUtils {
    method loadAlbumArtIntoView (line 58) | public static void loadAlbumArtIntoView(final long albumId, final Imag...
    method loadAlbumArtIntoView (line 62) | public static void loadAlbumArtIntoView(final long albumId, final Imag...
    method loadAlbumArtFromDiskWithLastfmFallback (line 71) | private static void loadAlbumArtFromDiskWithLastfmFallback(final long ...
    method loadAlbumArtFromLastfm (line 92) | private static void loadAlbumArtFromLastfm(long albumId, final ImageVi...
    method createBlurredImageFromBitmap (line 122) | public static Drawable createBlurredImageFromBitmap(Bitmap bitmap, Con...

FILE: app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java
  class LyricsExtractor (line 14) | public class LyricsExtractor {
    method getLyrics (line 15) | public static String getLyrics(File file){
    method readOgg (line 34) | private static int readOgg(byte[] buf, InputStream in, int bytesinpage...
    method getLyricsVorbis (line 65) | private static String getLyricsVorbis(File file) throws Exception{
    method getLyricsMP4 (line 110) | private static String getLyricsMP4(File file) throws Exception{
    method getLyricsID3 (line 157) | private static String getLyricsID3(File file) throws Exception{
    method byteArrayToInt (line 219) | private static int byteArrayToInt(byte[] b) {
    method byteArrayToIntLE (line 223) | private static int byteArrayToIntLE(byte[] b) {

FILE: app/src/main/java/com/naman14/timber/utils/LyricsLoader.java
  class LyricsLoader (line 30) | public class LyricsLoader {
    method getInstance (line 36) | public static LyricsLoader getInstance(Context con) {
    method LyricsLoader (line 41) | private LyricsLoader(Context con){
    method getLyrics (line 95) | public void getLyrics(String artist, String title, Callback<String> ca...
    type LyricsRestService (line 99) | private interface LyricsRestService {
      method getLyrics (line 100) | @Headers("Cache-Control: public")

FILE: app/src/main/java/com/naman14/timber/utils/NavigationUtils.java
  class NavigationUtils (line 48) | public class NavigationUtils {
    method navigateToAlbum (line 50) | @TargetApi(21)
    method navigateToArtist (line 66) | @TargetApi(21)
    method goToArtist (line 82) | public static void goToArtist(Context context, long artistId) {
    method goToAlbum (line 89) | public static void goToAlbum(Context context, long albumId) {
    method goToLyrics (line 96) | public static void goToLyrics(Context context) {
    method navigateToNowplaying (line 102) | public static void navigateToNowplaying(Activity context, boolean with...
    method getNowPlayingIntent (line 108) | public static Intent getNowPlayingIntent(Context context) {
    method navigateToSettings (line 115) | public static void navigateToSettings(Activity context) {
    method navigateToSearch (line 121) | public static void navigateToSearch(Activity context) {
    method navigateToPlaylistDetail (line 129) | @TargetApi(21)
    method navigateToEqualizer (line 147) | public static void navigateToEqualizer(Activity context) {
    method getNavigateToStyleSelectorIntent (line 156) | public static Intent getNavigateToStyleSelectorIntent(Activity context...
    method getFragmentForNowplayingID (line 163) | public static Fragment getFragmentForNowplayingID(String fragmentID) {
    method getIntForCurrentNowplaying (line 183) | public static int getIntForCurrentNowplaying(String nowPlaying) {

FILE: app/src/main/java/com/naman14/timber/utils/PreferencesUtility.java
  class PreferencesUtility (line 30) | public final class PreferencesUtility {
    method PreferencesUtility (line 69) | public PreferencesUtility(final Context context) {
    method getInstance (line 74) | public static final PreferencesUtility getInstance(final Context conte...
    method setOnSharedPreferenceChangeListener (line 82) | public void setOnSharedPreferenceChangeListener(OnSharedPreferenceChan...
    method isArtistsInGrid (line 86) | public boolean isArtistsInGrid() {
    method setArtistsInGrid (line 90) | public void setArtistsInGrid(final boolean b) {
    method isAlbumsInGrid (line 96) | public boolean isAlbumsInGrid() {
    method setAlbumsInGrid (line 100) | public void setAlbumsInGrid(final boolean b) {
    method pauseEnabledOnDetach (line 106) | public boolean pauseEnabledOnDetach() {
    method getTheme (line 110) | public String getTheme() {
    method getStartPageIndex (line 114) | public int getStartPageIndex() {
    method setStartPageIndex (line 118) | public void setStartPageIndex(final int index) {
    method setLastOpenedAsStartPagePreference (line 124) | public void setLastOpenedAsStartPagePreference(boolean preference) {
    method lastOpenedIsStartPagePreference (line 130) | public boolean lastOpenedIsStartPagePreference() {
    method setSortOrder (line 134) | private void setSortOrder(final String key, final String value) {
    method getArtistSortOrder (line 140) | public final String getArtistSortOrder() {
    method setArtistSortOrder (line 144) | public void setArtistSortOrder(final String value) {
    method getArtistSongSortOrder (line 148) | public final String getArtistSongSortOrder() {
    method setArtistSongSortOrder (line 153) | public void setArtistSongSortOrder(final String value) {
    method getArtistAlbumSortOrder (line 157) | public final String getArtistAlbumSortOrder() {
    method setArtistAlbumSortOrder (line 162) | public void setArtistAlbumSortOrder(final String value) {
    method getAlbumSortOrder (line 166) | public final String getAlbumSortOrder() {
    method setAlbumSortOrder (line 170) | public void setAlbumSortOrder(final String value) {
    method getAlbumSongSortOrder (line 174) | public final String getAlbumSongSortOrder() {
    method setAlbumSongSortOrder (line 179) | public void setAlbumSongSortOrder(final String value) {
    method getSongSortOrder (line 183) | public final String getSongSortOrder() {
    method setSongSortOrder (line 187) | public void setSongSortOrder(final String value) {
    method didNowplayingThemeChanged (line 191) | public final boolean didNowplayingThemeChanged() {
    method setNowPlayingThemeChanged (line 195) | public void setNowPlayingThemeChanged(final boolean value) {
    method getXPosedTrackselectorEnabled (line 201) | public boolean getXPosedTrackselectorEnabled() {
    method getPlaylistView (line 205) | public int getPlaylistView() {
    method setPlaylistView (line 209) | public void setPlaylistView(final int i) {
    method showAutoPlaylist (line 215) | public boolean showAutoPlaylist() {
    method setToggleShowAutoPlaylist (line 219) | public void setToggleShowAutoPlaylist(final boolean b) {
    method setLastAddedCutoff (line 226) | public void setLastAddedCutoff(long lastAddedMillis) {
    method getLastAddedCutoff (line 230) | public long getLastAddedCutoff() {
    method isGesturesEnabled (line 234) | public boolean isGesturesEnabled() {
    method storeLastFolder (line 238) | public void storeLastFolder(String path) {
    method getLastFolder (line 244) | public String getLastFolder() {
    method fullUnlocked (line 248) | public boolean fullUnlocked() {
    method setFullUnlocked (line 252) | public void setFullUnlocked(final boolean b) {
    method getSetAlbumartLockscreen (line 258) | public boolean getSetAlbumartLockscreen() {
    method updateService (line 262) | public void updateService(Bundle extras) {
    method loadArtistAndAlbumImages (line 270) | public boolean loadArtistAndAlbumImages() {
    method alwaysLoadAlbumImagesFromLastfm (line 282) | public boolean alwaysLoadAlbumImagesFromLastfm() {

FILE: app/src/main/java/com/naman14/timber/utils/SlideTrackSwitcher.java
  class SlideTrackSwitcher (line 14) | public class SlideTrackSwitcher implements View.OnTouchListener {
    method SlideTrackSwitcher (line 23) | public SlideTrackSwitcher() {
    method attach (line 26) | public void attach(@NonNull View v) {
    method onTouch (line 32) | @Override
    class SwipeListener (line 37) | private class SwipeListener extends GestureDetector.SimpleOnGestureLis...
      method onFling (line 39) | @Override
      method onDown (line 70) | @Override
      method onDoubleTap (line 75) | @Override
      method onSingleTapConfirmed (line 81) | @Override
    method onSwipeRight (line 88) | public void onSwipeRight() {
    method onSwipeLeft (line 92) | public void onSwipeLeft() {
    method onSwipeTop (line 96) | public void onSwipeTop() {
    method onSwipeBottom (line 99) | public void onSwipeBottom() {
    method onClick (line 102) | public void onClick() {

FILE: app/src/main/java/com/naman14/timber/utils/SortOrder.java
  class SortOrder (line 23) | public final class SortOrder {
    method SortOrder (line 28) | public SortOrder() {
    type ArtistSortOrder (line 34) | public interface ArtistSortOrder {
    type AlbumSortOrder (line 53) | public interface AlbumSortOrder {
    type SongSortOrder (line 75) | public interface SongSortOrder {
    type AlbumSongSortOrder (line 104) | public interface AlbumSongSortOrder {
    type ArtistSongSortOrder (line 128) | public interface ArtistSongSortOrder {
    type ArtistAlbumSortOrder (line 154) | public interface ArtistAlbumSortOrder {

FILE: app/src/main/java/com/naman14/timber/utils/TimberUtils.java
  class TimberUtils (line 52) | public class TimberUtils {
    method isOreo (line 57) | public static boolean isOreo() {
    method isMarshmallow (line 61) | public static boolean isMarshmallow() {
    method isLollipop (line 65) | public static boolean isLollipop() {
    method isJellyBeanMR2 (line 70) | public static boolean isJellyBeanMR2() {
    method isJellyBean (line 74) | public static boolean isJellyBean() {
    method isJellyBeanMR1 (line 78) | public static boolean isJellyBeanMR1() {
    method getAlbumArtUri (line 82) | public static Uri getAlbumArtUri(long albumId) {
    method getAlbumArtForFile (line 85) | public static String getAlbumArtForFile(String filePath) {
    method makeCombinedString (line 92) | public static final String makeCombinedString(final Context context, f...
    method makeLabel (line 98) | public static final String makeLabel(final Context context, final int ...
    method makeShortTimeString (line 103) | public static final String makeShortTimeString(final Context context, ...
    method getActionBarHeight (line 116) | public static int getActionBarHeight(Context context) {
    method getSongCountForPlaylist (line 127) | public static final int getSongCountForPlaylist(final Context context,...
    method hasEffectsPanel (line 145) | public static boolean hasEffectsPanel(final Activity activity) {
    method createEffectsIntent (line 151) | public static Intent createEffectsIntent() {
    method getBlackWhiteColor (line 157) | public static int getBlackWhiteColor(int color) {
    type IdType (line 164) | public enum IdType {
      method IdType (line 172) | IdType(final int id) {
      method getTypeById (line 176) | public static IdType getTypeById(int id) {
    type PlaylistType (line 187) | public enum PlaylistType {
      method PlaylistType (line 195) | PlaylistType(long id, int titleId) {
      method getTypeById (line 200) | public static PlaylistType getTypeById(long id) {
    method removeFromPlaylist (line 211) | public static void removeFromPlaylist(final Context context, final lon...
    method clearTopTracks (line 220) | public static void clearTopTracks(Context context) {
    method clearRecent (line 224) | public static void clearRecent(Context context) {
    method clearLastAdded (line 228) | public static void clearLastAdded(Context context) {
    method showDeleteDialog (line 233) | public static void showDeleteDialog(final Context context, final Strin...
    method showDeleteDialog (line 258) | public static void showDeleteDialog(final Context context, final Strin...
    method deleteTracks (line 284) | public static void deleteTracks(final Context context, final long[] li...
    method shareTrack (line 345) | public static void shareTrack(final Context context, long id) {
    method getSongUri (line 357) | public static Uri getSongUri(Context context, long id) {
    method getIPAddress (line 387) | public static String getIPAddress(boolean useIPv4) {

FILE: app/src/main/java/com/naman14/timber/widgets/BaseRecyclerView.java
  class BaseRecyclerView (line 15) | public class BaseRecyclerView extends RecyclerView {
    method onChanged (line 21) | @Override
    method BaseRecyclerView (line 38) | public BaseRecyclerView(Context context) {
    method BaseRecyclerView (line 42) | public BaseRecyclerView(Context context, AttributeSet attrs) {
    method BaseRecyclerView (line 46) | public BaseRecyclerView(Context context, AttributeSet attrs, int defSt...
    method setAdapter (line 50) | @Override
    method setEmptyView (line 61) | public void setEmptyView(Context context, View emptyView, String text) {

FILE: app/src/main/java/com/naman14/timber/widgets/BubbleTextGetter.java
  type BubbleTextGetter (line 3) | public interface BubbleTextGetter {
    method getTextToShowInBubble (line 4) | String getTextToShowInBubble(int pos);

FILE: app/src/main/java/com/naman14/timber/widgets/CircleImageView.java
  class CircleImageView (line 26) | public class CircleImageView extends ImageView {
    method CircleImageView (line 61) | public CircleImageView(Context context) {
    method CircleImageView (line 67) | public CircleImageView(Context context, AttributeSet attrs) {
    method CircleImageView (line 71) | public CircleImageView(Context context, AttributeSet attrs, int defSty...
    method init (line 85) | private void init() {
    method getScaleType (line 95) | @Override
    method setScaleType (line 100) | @Override
    method setAdjustViewBounds (line 107) | @Override
    method onDraw (line 114) | @Override
    method onSizeChanged (line 126) | @Override
    method getBorderColor (line 132) | public int getBorderColor() {
    method setBorderColor (line 136) | public void setBorderColor(int borderColor) {
    method setBorderColorResource (line 146) | public void setBorderColorResource(@ColorRes int borderColorRes) {
    method getBorderWidth (line 150) | public int getBorderWidth() {
    method setBorderWidth (line 154) | public void setBorderWidth(int borderWidth) {
    method isBorderOverlay (line 163) | public boolean isBorderOverlay() {
    method setBorderOverlay (line 167) | public void setBorderOverlay(boolean borderOverlay) {
    method setImageBitmap (line 176) | @Override
    method setImageDrawable (line 183) | @Override
    method setImageResource (line 190) | @Override
    method setImageURI (line 197) | @Override
    method setColorFilter (line 204) | @Override
    method getBitmapFromDrawable (line 215) | private Bitmap getBitmapFromDrawable(Drawable drawable) {
    method setup (line 242) | private void setup() {
    method updateShaderMatrix (line 278) | private void updateShaderMatrix() {

FILE: app/src/main/java/com/naman14/timber/widgets/CircularSeekBar.java
  class CircularSeekBar (line 20) | public class CircularSeekBar extends View {
    method CircularSeekBar (line 330) | public CircularSeekBar(Context context) {
    method CircularSeekBar (line 335) | public CircularSeekBar(Context context, AttributeSet attrs) {
    method CircularSeekBar (line 340) | public CircularSeekBar(Context context, AttributeSet attrs, int defSty...
    method initAttributes (line 351) | private void initAttributes(TypedArray attrArray) {
    method initPaints (line 442) | private void initPaints() {
    method calculateTotalDegrees (line 495) | private void calculateTotalDegrees() {
    method calculateProgressDegrees (line 506) | private void calculateProgressDegrees() {
    method calculatePointerAngle (line 515) | private void calculatePointerAngle() {
    method calculatePointerXYPosition (line 521) | private void calculatePointerXYPosition() {
    method initPaths (line 533) | private void initPaths() {
    method initRects (line 544) | private void initRects() {
    method onDraw (line 548) | @Override
    method getProgress (line 572) | public int getProgress() {
    method setProgress (line 583) | public void setProgress(int progress) {
    method setProgressBasedOnAngle (line 595) | private void setProgressBasedOnAngle(float angle) {
    method recalculateAll (line 601) | private void recalculateAll() {
    method onMeasure (line 613) | @Override
    method isLockEnabled (line 649) | public boolean isLockEnabled() {
    method setLockEnabled (line 653) | public void setLockEnabled(boolean lockEnabled) {
    method onTouchEvent (line 657) | @Override
    method init (line 841) | private void init(AttributeSet attrs, int defStyle) {
    method onSaveInstanceState (line 851) | @Override
    method onRestoreInstanceState (line 871) | @Override
    method setOnSeekBarChangeListener (line 895) | public void setOnSeekBarChangeListener(OnCircularSeekBarChangeListener...
    method getCircleColor (line 904) | public int getCircleColor() {
    method setCircleColor (line 913) | public void setCircleColor(int color) {
    method getCircleProgressColor (line 924) | public int getCircleProgressColor() {
    method setCircleProgressColor (line 933) | public void setCircleProgressColor(int color) {
    method getPointerColor (line 944) | public int getPointerColor() {
    method setPointerColor (line 953) | public void setPointerColor(int color) {
    method getPointerHaloColor (line 964) | public int getPointerHaloColor() {
    method setPointerHaloColor (line 973) | public void setPointerHaloColor(int color) {
    method getPointerAlpha (line 984) | public int getPointerAlpha() {
    method setPointerAlpha (line 993) | public void setPointerAlpha(int alpha) {
    method getPointerAlphaOnTouch (line 1006) | public int getPointerAlphaOnTouch() {
    method setPointerAlphaOnTouch (line 1015) | public void setPointerAlphaOnTouch(int alpha) {
    method getCircleFillColor (line 1026) | public int getCircleFillColor() {
    method setCircleFillColor (line 1035) | public void setCircleFillColor(int color) {
    method getMax (line 1046) | public synchronized int getMax() {
    method setMax (line 1057) | public void setMax(int max) {
    type OnCircularSeekBarChangeListener (line 1075) | public interface OnCircularSeekBarChangeListener {
      method onProgressChanged (line 1077) | void onProgressChanged(CircularSeekBar circularSeekBar, int progress...
      method onStopTrackingTouch (line 1079) | void onStopTrackingTouch(CircularSeekBar seekBar);
      method onStartTrackingTouch (line 1081) | void onStartTrackingTouch(CircularSeekBar seekBar);

FILE: app/src/main/java/com/naman14/timber/widgets/DividerItemDecoration.java
  class DividerItemDecoration (line 16) | public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    method DividerItemDecoration (line 27) | public DividerItemDecoration(Context context, int orientation) {
    method DividerItemDecoration (line 37) | public DividerItemDecoration(Context context, int orientation, int res...
    method setOrientation (line 42) | public void setOrientation(int orientation) {
    method onDraw (line 49) | @Override
    method drawVertical (line 58) | public void drawVertical(Canvas c, RecyclerView parent) {
    method drawHorizontal (line 74) | public void drawHorizontal(Canvas c, RecyclerView parent) {
    method getItemOffsets (line 90) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/DragSortRecycler.java
  class DragSortRecycler (line 15) | public class DragSortRecycler extends RecyclerView.ItemDecoration implem...
    method onScrollStateChanged (line 28) | @Override
    method onScrolled (line 33) | @Override
    method debugLog (line 52) | private void debugLog(String log) {
    method getScrollListener (line 57) | public RecyclerView.OnScrollListener getScrollListener() {
    method setOnItemMovedListener (line 64) | public void setOnItemMovedListener(OnItemMovedListener swif) {
    method setViewHandleId (line 68) | public void setViewHandleId(int id) {
    method setLeftDragArea (line 72) | public void setLeftDragArea(int w) {
    method setFloatingAlpha (line 76) | public void setFloatingAlpha(float a) {
    method setFloatingBgColor (line 80) | public void setFloatingBgColor(int c) {
    method setAutoScrollWindow (line 88) | public void setAutoScrollWindow(float w) {
    method setAutoScrollSpeed (line 95) | public void setAutoScrollSpeed(float speed) {
    method getItemOffsets (line 99) | @Override
    method getNewPostion (line 168) | private int getNewPostion(RecyclerView rv) {
    method onInterceptTouchEvent (line 214) | @Override
    method onRequestDisallowInterceptTouchEvent (line 287) | @Override
    method onTouchEvent (line 292) | @Override
    method setIsDragging (line 340) | private void setIsDragging(final boolean dragging) {
    method setOnDragStateChangedListener (line 353) | public void setOnDragStateChangedListener(final OnDragStateChangedList...
    method onDrawOver (line 357) | @Override
    method canDragOver (line 371) | protected boolean canDragOver(int position) {
    method createFloatingBitmap (line 375) | private BitmapDrawable createFloatingBitmap(View v) {
    type OnItemMovedListener (line 390) | public interface OnItemMovedListener {
      method onItemMoved (line 391) | void onItemMoved(int from, int to);
    type OnDragStateChangedListener (line 395) | public interface OnDragStateChangedListener {
      method onDragStart (line 396) | void onDragStart();
      method onDragStop (line 398) | void onDragStop();

FILE: app/src/main/java/com/naman14/timber/widgets/FastScroller.java
  class FastScroller (line 22) | public class FastScroller extends LinearLayout {
    method FastScroller (line 33) | public FastScroller(final Context context, final AttributeSet attrs, f...
    method FastScroller (line 38) | public FastScroller(final Context context) {
    method FastScroller (line 43) | public FastScroller(final Context context, final AttributeSet attrs) {
    method initialise (line 48) | private void initialise(Context context) {
    method onSizeChanged (line 58) | @Override
    method onTouchEvent (line 64) | @Override
    method setRecyclerView (line 90) | public void setRecyclerView(RecyclerView recyclerView) {
    method setRecyclerViewPosition (line 95) | private void setRecyclerViewPosition(float y) {
    method getValueInRange (line 113) | private int getValueInRange(int min, int max, int value) {
    method setBubbleAndHandlePosition (line 118) | private void setBubbleAndHandlePosition(float y) {
    method showBubble (line 125) | private void showBubble() {
    method hideBubble (line 134) | private void hideBubble() {
    class ScrollListener (line 156) | private class ScrollListener extends OnScrollListener {
      method onScrolled (line 157) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/MultiViewPager.java
  class MultiViewPager (line 12) | public class MultiViewPager extends ViewPager {
    method MultiViewPager (line 33) | public MultiViewPager(Context context) {
    method MultiViewPager (line 39) | public MultiViewPager(Context context, AttributeSet attrs) {
    method constrainTo (line 46) | private static void constrainTo(Point size, Point maxSize) {
    method init (line 59) | private void init(Context context, AttributeSet attrs) {
    method onMeasure (line 68) | @Override
    method onMeasurePage (line 86) | protected void onMeasurePage(int widthMeasureSpec, int heightMeasureSp...
    method onSizeChanged (line 117) | @Override
    method setMatchChildWidth (line 129) | public void setMatchChildWidth(int matchChildWidthResId) {
    method setMaxWidth (line 141) | public void setMaxWidth(int width) {
    method setMaxHeight (line 150) | public void setMaxHeight(int height) {

FILE: app/src/main/java/com/naman14/timber/widgets/MusicVisualizer.java
  class MusicVisualizer (line 15) | public class MusicVisualizer extends View {
    method run (line 21) | @Override
    method MusicVisualizer (line 31) | public MusicVisualizer(Context context) {
    method MusicVisualizer (line 36) | public MusicVisualizer(Context context, AttributeSet attrs) {
    method onDraw (line 44) | @Override
    method setColor (line 56) | public void setColor(int color) {
    method getDimensionInPixel (line 62) | private int getDimensionInPixel(int dp) {
    method onWindowVisibilityChanged (line 66) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/PlayPauseButton.java
  class PlayPauseButton (line 16) | public class PlayPauseButton extends View {
    method onAnimationUpdate (line 73) | @Override
    method PlayPauseButton (line 85) | public PlayPauseButton(Context context) {
    method PlayPauseButton (line 93) | public PlayPauseButton(Context context, AttributeSet attrs) {
    method PlayPauseButton (line 102) | public PlayPauseButton(Context context, AttributeSet attrs, int defSty...
    method initView (line 112) | private void initView() {
    method setUpAnimator (line 122) | private void setUpAnimator() {
    method setUpPaint (line 141) | private void setUpPaint() {
    method setUpPath (line 151) | private void setUpPath() {
    method onDraw (line 160) | @Override
    method startAnimation (line 193) | public void startAnimation() {
    method setOnControlStatusChangeListener (line 217) | public void setOnControlStatusChangeListener(OnControlStatusChangeList...
    method onSaveInstanceState (line 242) | @Override
    method onRestoreInstanceState (line 255) | @Override
    method setBackground (line 268) | @Override
    method isPlayed (line 277) | public boolean isPlayed() {
    method setPlayed (line 286) | public void setPlayed(boolean played) {
    method setColor (line 298) | public void setColor(int color) {
    type OnControlStatusChangeListener (line 304) | public interface OnControlStatusChangeListener {
      method onStatusChange (line 305) | void onStatusChange(View view, boolean state);
    class SavedState (line 311) | static class SavedState extends BaseSavedState {
      method createFromParcel (line 315) | public SavedState createFromParcel(Parcel in) {
      method newArray (line 319) | public SavedState[] newArray(int size) {
      method SavedState (line 325) | SavedState(Parcelable superState) {
      method SavedState (line 329) | private SavedState(Parcel in) {
      method writeToParcel (line 334) | @Override
    class Point (line 347) | static class Point {
      method setWidth (line 353) | public void setWidth(int width) {
      method setHeight (line 357) | public void setHeight(int height) {
      method getX (line 361) | public float getX(float x) {
      method getY (line 365) | public float getY(float y) {
      method getX (line 369) | public float getX(double x) {
      method getY (line 373) | public float getY(double y) {

FILE: app/src/main/java/com/naman14/timber/widgets/PlayPauseDrawable.java
  class PlayPauseDrawable (line 48) | public class PlayPauseDrawable extends Drawable {
    method get (line 58) | @Override
    method set (line 63) | @Override
    method PlayPauseDrawable (line 72) | public PlayPauseDrawable() {
    method interpolate (line 81) | private static float interpolate(float a, float b, float t) {
    method draw (line 85) | @Override
    method transformToPause (line 152) | public void transformToPause(boolean animated) {
    method jumpToCurrentState (line 163) | @Override
    method transformToPlay (line 172) | public void transformToPlay(boolean animated) {
    method toggle (line 183) | private void toggle() {
    method getProgress (line 201) | private float getProgress() {
    method setProgress (line 205) | private void setProgress(float progress) {
    method setAlpha (line 210) | @Override
    method setColorFilter (line 216) | @Override
    method getOpacity (line 223) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/PopupImageView.java
  class PopupImageView (line 15) | public class PopupImageView extends ImageView {
    method PopupImageView (line 17) | public PopupImageView(Context context) {
    method PopupImageView (line 22) | public PopupImageView(Context context, AttributeSet attrs) {
    method PopupImageView (line 27) | public PopupImageView(Context context, AttributeSet attrs, int defStyl...
    method PopupImageView (line 32) | @TargetApi(21)
    method tint (line 38) | private void tint() {

FILE: app/src/main/java/com/naman14/timber/widgets/SquareImageView.java
  class SquareImageView (line 7) | public class SquareImageView extends ImageView {
    method SquareImageView (line 10) | public SquareImageView(Context context) {
    method SquareImageView (line 14) | public SquareImageView(Context context, AttributeSet attrs) {
    method SquareImageView (line 18) | public SquareImageView(Context context, AttributeSet attrs, int defSty...
    method onMeasure (line 22) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/TextDrawable.java
  class TextDrawable (line 17) | public class TextDrawable extends ShapeDrawable {
    method TextDrawable (line 31) | private TextDrawable(Builder builder) {
    method builder (line 68) | public static IShapeBuilder builder() {
    method getDarkerShade (line 72) | private int getDarkerShade(int color) {
    method draw (line 78) | @Override
    method drawBorder (line 103) | private void drawBorder(Canvas canvas) {
    method setAlpha (line 116) | @Override
    method setColorFilter (line 121) | @Override
    method getOpacity (line 126) | @Override
    method getIntrinsicWidth (line 131) | @Override
    method getIntrinsicHeight (line 136) | @Override
    type IConfigBuilder (line 141) | public interface IConfigBuilder {
      method width (line 142) | IConfigBuilder width(int width);
      method height (line 144) | IConfigBuilder height(int height);
      method textColor (line 146) | IConfigBuilder textColor(int color);
      method withBorder (line 148) | IConfigBuilder withBorder(int thickness);
      method useFont (line 150) | IConfigBuilder useFont(Typeface font);
      method fontSize (line 152) | IConfigBuilder fontSize(int size);
      method bold (line 154) | IConfigBuilder bold();
      method toUpperCase (line 156) | IConfigBuilder toUpperCase();
      method endConfig (line 158) | IShapeBuilder endConfig();
    type IBuilder (line 161) | public interface IBuilder {
      method build (line 163) | TextDrawable build(String text, int color);
    type IShapeBuilder (line 166) | public interface IShapeBuilder {
      method beginConfig (line 168) | IConfigBuilder beginConfig();
      method rect (line 170) | IBuilder rect();
      method round (line 172) | IBuilder round();
      method roundRect (line 174) | IBuilder roundRect(int radius);
      method buildRect (line 176) | TextDrawable buildRect(String text, int color);
      method buildRoundRect (line 178) | TextDrawable buildRoundRect(String text, int color, int radius);
      method buildRound (line 180) | TextDrawable buildRound(String text, int color);
    class Builder (line 183) | public static class Builder implements IConfigBuilder, IShapeBuilder, ...
      method Builder (line 198) | private Builder() {
      method width (line 212) | public IConfigBuilder width(int width) {
      method height (line 217) | public IConfigBuilder height(int height) {
      method textColor (line 222) | public IConfigBuilder textColor(int color) {
      method withBorder (line 227) | public IConfigBuilder withBorder(int thickness) {
      method useFont (line 232) | public IConfigBuilder useFont(Typeface font) {
      method fontSize (line 237) | public IConfigBuilder fontSize(int size) {
      method bold (line 242) | public IConfigBuilder bold() {
      method toUpperCase (line 247) | public IConfigBuilder toUpperCase() {
      method beginConfig (line 252) | @Override
      method endConfig (line 257) | @Override
      method rect (line 262) | @Override
      method round (line 268) | @Override
      method roundRect (line 274) | @Override
      method buildRect (line 282) | @Override
      method buildRoundRect (line 288) | @Override
      method buildRound (line 294) | @Override
      method build (line 300) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/ThemedPreferenceCategory.java
  class ThemedPreferenceCategory (line 15) | public class ThemedPreferenceCategory extends PreferenceCategory {
    method ThemedPreferenceCategory (line 19) | public ThemedPreferenceCategory(Context context) {
    method ThemedPreferenceCategory (line 24) | public ThemedPreferenceCategory(Context context, AttributeSet attrs) {
    method ThemedPreferenceCategory (line 29) | public ThemedPreferenceCategory(Context context, AttributeSet attrs,
    method onBindView (line 35) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/desktop/BaseWidget.java
  class BaseWidget (line 18) | public abstract class BaseWidget extends AppWidgetProvider {
    method onUpdate (line 24) | @Override
    method onUpdate (line 29) | private void onUpdate(Context context, AppWidgetManager appWidgetManag...
    method onReceive (line 40) | @Override
    method onViewsUpdate (line 53) | abstract void onViewsUpdate(Context context, RemoteViews remoteViews, ...
    method getLayoutRes (line 55) | abstract @LayoutRes int getLayoutRes();

FILE: app/src/main/java/com/naman14/timber/widgets/desktop/SmallWidget.java
  class SmallWidget (line 21) | public class SmallWidget extends BaseWidget {
    method getLayoutRes (line 23) | @Override
    method onViewsUpdate (line 28) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/desktop/StandardWidget.java
  class StandardWidget (line 22) | public class StandardWidget extends BaseWidget {
    method getLayoutRes (line 24) | @Override
    method onViewsUpdate (line 29) | @Override

FILE: app/src/main/java/com/naman14/timber/widgets/desktop/WhiteWidget.java
  class WhiteWidget (line 9) | public class WhiteWidget extends StandardWidget {
    method getLayoutRes (line 11) | @Override
Condensed preview — 320 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (1,440K chars).
[
  {
    "path": ".gitignore",
    "chars": 172,
    "preview": ".gradle\n/local.properties\n.idea\n.DS_Store\n/build\n/captures\n/*.iml\n\n/app/app-release.apk\napp/app.iml\napp/manifest-merger-"
  },
  {
    "path": ".travis.yml",
    "chars": 249,
    "preview": "language: android\njdk: oraclejdk8\n\nbranches:\n  only:\n    - master\n\nscript: \"./gradlew clean assembleDebug\"\n\nandroid:\n  c"
  },
  {
    "path": "Changelog.md",
    "chars": 1385,
    "preview": "#Changelog\n\nv0.21b-\n\n* Add Homescreen widget\n* View playlists in list, grid and default\n* Delete playlists, clear auto p"
  },
  {
    "path": "README.md",
    "chars": 3622,
    "preview": "# Timber\n[![Build Status](https://travis-ci.org/naman14/Timber.svg?branch=master)](https://travis-ci.org/naman14/Timber)"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 2620,
    "preview": "apply plugin: 'com.android.application'\napply plugin: 'com.google.gms.google-services'\napply plugin: 'com.google.firebas"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 1405,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
  },
  {
    "path": "app/src/androidTest/java/com/naman14/timber/ApplicationTest.java",
    "chars": 349,
    "preview": "package com.naman14.timber;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"h"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 6631,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/aidl/com/naman14/timber/ITimberService.aidl",
    "chars": 1544,
    "preview": "package com.naman14.timber;\n\nimport com.naman14.timber.helpers.MusicPlaybackTrack;\n\ninterface ITimberService\n{\n    void "
  },
  {
    "path": "app/src/main/aidl/com/naman14/timber/helpers/MusicPlaybackTrack.aidl",
    "chars": 67,
    "preview": "package com.naman14.timber.helpers;\n\nparcelable MusicPlaybackTrack;"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/MusicPlayer.java",
    "chars": 26338,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Copyright (C) 2015 Naman Dwivedi\n "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/MusicService.java",
    "chars": 99686,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Copyright (C) 2015 Naman Dwivedi\n "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/TimberApp.java",
    "chars": 4064,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/WearBrowserService.java",
    "chars": 13637,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/BaseActivity.java",
    "chars": 14254,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Copyright (C) 2015 Naman Dwivedi\n "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/BaseThemedActivity.java",
    "chars": 701,
    "preview": "package com.naman14.timber.activities;\n\nimport android.media.AudioManager;\nimport android.os.Bundle;\nimport androidx.ann"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/DonateActivity.java",
    "chars": 7731,
    "preview": "package com.naman14.timber.activities;\n\nimport android.content.Intent;\nimport android.os.AsyncTask;\nimport android.os.Bu"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/MainActivity.java",
    "chars": 19869,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/NowPlayingActivity.java",
    "chars": 2500,
    "preview": "package com.naman14.timber.activities;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/PlaylistDetailActivity.java",
    "chars": 14766,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/SearchActivity.java",
    "chars": 8178,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/activities/SettingsActivity.java",
    "chars": 4266,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/AlbumAdapter.java",
    "chars": 6960,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/AlbumSongsAdapter.java",
    "chars": 6978,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/ArtistAdapter.java",
    "chars": 9119,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/ArtistAlbumAdapter.java",
    "chars": 3278,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/ArtistSongAdapter.java",
    "chars": 10012,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/BaseQueueAdapter.java",
    "chars": 8134,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/BaseSongAdapter.java",
    "chars": 2211,
    "preview": "package com.naman14.timber.adapters;\n\nimport android.app.Activity;\n\nimport androidx.recyclerview.widget.RecyclerView;\n\ni"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/FolderAdapter.java",
    "chars": 8308,
    "preview": "package com.naman14.timber.adapters;\n\nimport android.app.Activity;\nimport android.graphics.Color;\nimport android.graphic"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/PlayingQueueAdapter.java",
    "chars": 7728,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/PlaylistAdapter.java",
    "chars": 11904,
    "preview": "package com.naman14.timber.adapters;\n\nimport android.app.Activity;\nimport android.graphics.Bitmap;\nimport androidx.palet"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/SearchAdapter.java",
    "chars": 12125,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/SlidingQueueAdapter.java",
    "chars": 4527,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/adapters/SongsListAdapter.java",
    "chars": 10988,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/cast/CastOptionsProvider.java",
    "chars": 1845,
    "preview": "package com.naman14.timber.cast;\n\nimport android.content.Context;\n\nimport com.google.android.gms.cast.framework.CastOpti"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/cast/ExpandedControlsActivity.java",
    "chars": 888,
    "preview": "package com.naman14.timber.cast;\n\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.View;\nimport a"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/cast/SimpleSessionManagerListener.java",
    "chars": 908,
    "preview": "package com.naman14.timber.cast;\n\nimport com.google.android.gms.cast.framework.Session;\nimport com.google.android.gms.ca"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/cast/TimberCastHelper.java",
    "chars": 2215,
    "preview": "package com.naman14.timber.cast;\n\nimport android.net.Uri;\nimport android.util.Log;\n\nimport com.google.android.gms.cast.M"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/cast/WebServer.java",
    "chars": 2385,
    "preview": "package com.naman14.timber.cast;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport com.naman14.timber.uti"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/AlbumLoader.java",
    "chars": 3036,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/AlbumSongLoader.java",
    "chars": 2805,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/ArtistAlbumLoader.java",
    "chars": 1354,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/ArtistLoader.java",
    "chars": 2983,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/ArtistSongLoader.java",
    "chars": 2442,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/FolderLoader.java",
    "chars": 3103,
    "preview": "package com.naman14.timber.dataloaders;\n\nimport android.text.TextUtils;\n\nimport java.io.File;\nimport java.io.FileFilter;"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/LastAddedLoader.java",
    "chars": 3058,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Copyright (C) 2015 Naman Dwivedi\n "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/NowPlayingCursor.java",
    "chars": 6759,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Licensed under the Apache License,"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/PlaylistLoader.java",
    "chars": 3689,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/PlaylistSongLoader.java",
    "chars": 7397,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/QueueLoader.java",
    "chars": 1891,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/SongLoader.java",
    "chars": 6780,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/SortedCursor.java",
    "chars": 5997,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dataloaders/TopTracksLoader.java",
    "chars": 4186,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dialogs/AddPlaylistDialog.java",
    "chars": 2128,
    "preview": "package com.naman14.timber.dialogs;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport androidx.annotation.Non"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dialogs/CreatePlaylistDialog.java",
    "chars": 2397,
    "preview": "package com.naman14.timber.dialogs;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport androidx.annotation.Non"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dialogs/LastFmLoginDialog.java",
    "chars": 2837,
    "preview": "package com.naman14.timber.dialogs;\n\nimport android.app.Dialog;\nimport android.app.DialogFragment;\nimport android.app.Pr"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/dialogs/StorageSelectDialog.java",
    "chars": 2260,
    "preview": "package com.naman14.timber.dialogs;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport andr"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/AlbumDetailFragment.java",
    "chars": 16825,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/AlbumFragment.java",
    "chars": 7561,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/ArtistBioFragment.java",
    "chars": 3100,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/ArtistDetailFragment.java",
    "chars": 10958,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/ArtistFragment.java",
    "chars": 7349,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/ArtistMusicFragment.java",
    "chars": 2980,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/FoldersFragment.java",
    "chars": 5122,
    "preview": "package com.naman14.timber.fragments;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.os.As"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/MainFragment.java",
    "chars": 4876,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/PlaylistFragment.java",
    "chars": 10719,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/QueueFragment.java",
    "chars": 4831,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/SettingsFragment.java",
    "chars": 11574,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/SimilarArtistFragment.java",
    "chars": 2445,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/fragments/SongsFragment.java",
    "chars": 5842,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/helpers/MediaButtonIntentReceiver.java",
    "chars": 9274,
    "preview": "/*\n * Copyright (C) 2007 The Android Open Source Project Licensed under the Apache\n * License, Version 2.0 (the \"License"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/helpers/MusicPlaybackTrack.java",
    "chars": 2753,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/LastFmClient.java",
    "chars": 10964,
    "preview": "/*\r\n * Copyright (C) 2015 Naman Dwivedi\r\n *\r\n * Licensed under the GNU General Public License v3\r\n *\r\n * This is free so"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/LastFmRestService.java",
    "chars": 1465,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/LastFmUserRestService.java",
    "chars": 940,
    "preview": "package com.naman14.timber.lastfmapi;\n\nimport com.naman14.timber.lastfmapi.models.ScrobbleInfo;\nimport com.naman14.timbe"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/RestServiceFactory.java",
    "chars": 2649,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/callbacks/AlbumInfoListener.java",
    "chars": 811,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/callbacks/ArtistInfoListener.java",
    "chars": 816,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/callbacks/UserListener.java",
    "chars": 183,
    "preview": "package com.naman14.timber.lastfmapi.callbacks;\n\n\n\n/**\n * Created by christoph on 17.07.16.\n */\npublic interface UserLis"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumBio.java",
    "chars": 661,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumInfo.java",
    "chars": 824,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumQuery.java",
    "chars": 1068,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/AlbumTracks.java",
    "chars": 664,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistBio.java",
    "chars": 1180,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistInfo.java",
    "chars": 830,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistQuery.java",
    "chars": 914,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ArtistTag.java",
    "chars": 814,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/Artwork.java",
    "chars": 909,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmAlbum.java",
    "chars": 945,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmArtist.java",
    "chars": 1659,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/LastfmUserSession.java",
    "chars": 1585,
    "preview": "package com.naman14.timber.lastfmapi.models;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\n"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ScrobbleInfo.java",
    "chars": 121,
    "preview": "package com.naman14.timber.lastfmapi.models;\n\n/**\n * Created by christoph on 17.07.16.\n */\npublic class ScrobbleInfo {\n}"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/ScrobbleQuery.java",
    "chars": 1535,
    "preview": "package com.naman14.timber.lastfmapi.models;\n\nimport com.google.gson.annotations.SerializedName;\nimport com.naman14.timb"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/UserLoginInfo.java",
    "chars": 348,
    "preview": "package com.naman14.timber.lastfmapi.models;\n\nimport com.google.gson.annotations.SerializedName;\nimport com.naman14.timb"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/lastfmapi/models/UserLoginQuery.java",
    "chars": 868,
    "preview": "package com.naman14.timber.lastfmapi.models;\n\nimport com.google.gson.annotations.SerializedName;\nimport com.naman14.timb"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/listeners/MusicStateListener.java",
    "chars": 1144,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/listeners/SimplelTransitionListener.java",
    "chars": 1164,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/models/Album.java",
    "chars": 1324,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/models/Artist.java",
    "chars": 1116,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/models/Playlist.java",
    "chars": 1002,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/models/Song.java",
    "chars": 1576,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/BaseNowplayingFragment.java",
    "chars": 27995,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber1.java",
    "chars": 2538,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber2.java",
    "chars": 5349,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber3.java",
    "chars": 1221,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber4.java",
    "chars": 6178,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber5.java",
    "chars": 5616,
    "preview": "package com.naman14.timber.nowplaying;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\nimport android.gr"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/nowplaying/Timber6.java",
    "chars": 4534,
    "preview": "package com.naman14.timber.nowplaying;\n\nimport android.graphics.Color;\nimport android.graphics.PorterDuff;\nimport androi"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/permissions/Nammu.java",
    "chars": 12718,
    "preview": "/*\n* The MIT License (MIT)\n\n* Copyright (c) 2015 Michal Tajchert\n\n* Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/permissions/PermissionCallback.java",
    "chars": 1266,
    "preview": "/*\n* The MIT License (MIT)\n\n* Copyright (c) 2015 Michal Tajchert\n\n* Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/permissions/PermissionListener.java",
    "chars": 1829,
    "preview": "/*\n* The MIT License (MIT)\n\n* Copyright (c) 2015 Michal Tajchert\n\n* Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/permissions/PermissionRequest.java",
    "chars": 2440,
    "preview": "/*\n* The MIT License (MIT)\n\n* Copyright (c) 2015 Michal Tajchert\n\n* Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/provider/MusicDB.java",
    "chars": 2539,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/provider/MusicPlaybackState.java",
    "chars": 7594,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/provider/RecentStore.java",
    "chars": 4890,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/provider/SearchHistory.java",
    "chars": 5136,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/provider/SongPlayCount.java",
    "chars": 17687,
    "preview": "/*\n* Copyright (C) 2014 The CyanogenMod Project\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* yo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/slidinguppanel/SlidingUpPanelLayout.java",
    "chars": 46000,
    "preview": "package com.naman14.timber.slidinguppanel;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimpo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/slidinguppanel/ViewDragHelper.java",
    "chars": 59794,
    "preview": "/*\n * Copyright (C) 2013 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/ArtistTagFragment.java",
    "chars": 1551,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/LyricsFragment.java",
    "chars": 4377,
    "preview": "package com.naman14.timber.subfragments;\n\nimport android.content.CursorLoader;\nimport android.database.Cursor;\nimport an"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/PlaylistPagerFragment.java",
    "chars": 10891,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/QuickControlsFragment.java",
    "chars": 13182,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/StyleSelectorFragment.java",
    "chars": 3550,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/subfragments/SubStyleSelectorFragment.java",
    "chars": 7906,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/TimelyView.java",
    "chars": 5014,
    "preview": "/*\n* Copyright 2014 Adnan A M.\n* Copyright 2015 Naman Dwivedi.\n\n* Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/animation/TimelyEvaluator.java",
    "chars": 1451,
    "preview": "/*\n* Copyright 2014 Adnan A M.\n\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/NumberUtils.java",
    "chars": 1284,
    "preview": "package com.naman14.timber.timely.model;\n\nimport com.naman14.timber.timely.model.number.*;\n\nimport java.security.Invalid"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/core/Figure.java",
    "chars": 1206,
    "preview": "/*\n* Copyright 2014 Adnan A M.\n\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Eight.java",
    "chars": 973,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Eight"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Five.java",
    "chars": 965,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Five "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Four.java",
    "chars": 969,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Four "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Nine.java",
    "chars": 969,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Nine "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Null.java",
    "chars": 611,
    "preview": "package com.naman14.timber.timely.model.number;\n\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Null"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/One.java",
    "chars": 835,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class One e"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Seven.java",
    "chars": 894,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Seven"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Six.java",
    "chars": 957,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Six e"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Three.java",
    "chars": 974,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Three"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Two.java",
    "chars": 964,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Two e"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/timely/model/number/Zero.java",
    "chars": 967,
    "preview": "package com.naman14.timber.timely.model.number;\n\nimport com.naman14.timber.timely.model.core.Figure;\n\npublic class Zero "
  },
  {
    "path": "app/src/main/java/com/naman14/timber/transition/PlayTransition.java",
    "chars": 15165,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/ATEUtils.java",
    "chars": 4388,
    "preview": "package com.naman14.timber.utils;\n\nimport android.annotation.TargetApi;\nimport android.app.Activity;\nimport android.app."
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/Constants.java",
    "chars": 3329,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/FabAnimationUtils.java",
    "chars": 5514,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/Helpers.java",
    "chars": 2987,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/ImageUtils.java",
    "chars": 7606,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/LyricsExtractor.java",
    "chars": 7887,
    "preview": "package com.naman14.timber.utils;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimpo"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/LyricsLoader.java",
    "chars": 3550,
    "preview": "package com.naman14.timber.utils;\n\nimport android.content.Context;\n\nimport com.squareup.okhttp.Cache;\nimport com.squareu"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/NavigationUtils.java",
    "chars": 8127,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/PreferencesUtility.java",
    "chars": 10811,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/SlideTrackSwitcher.java",
    "chars": 2795,
    "preview": "package com.naman14.timber.utils;\n\nimport androidx.annotation.NonNull;\nimport android.view.GestureDetector;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/SortOrder.java",
    "chars": 5344,
    "preview": "/*\n * Copyright (C) 2012 Andrew Neal\n * Copyright (C) 2014 The CyanogenMod Project\n * Licensed under the Apache License,"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/utils/TimberUtils.java",
    "chars": 15485,
    "preview": "/*\n * Copyright (C) 2015 Naman Dwivedi\n *\n * Licensed under the GNU General Public License v3\n *\n * This is free softwar"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/BaseRecyclerView.java",
    "chars": 2159,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\n\nimport androidx.recyclerview.widget.RecyclerView;\n"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/BubbleTextGetter.java",
    "chars": 117,
    "preview": "package com.naman14.timber.widgets;\n\npublic interface BubbleTextGetter {\n    String getTextToShowInBubble(int pos);\n}"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/CircleImageView.java",
    "chars": 8629,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/CircularSeekBar.java",
    "chars": 40991,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/DividerItemDecoration.java",
    "chars": 3751,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/DragSortRecycler.java",
    "chars": 13587,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.grap"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/FastScroller.java",
    "chars": 6853,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/MultiViewPager.java",
    "chars": 5040,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport andro"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/MusicVisualizer.java",
    "chars": 2396,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.grap"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/PlayPauseButton.java",
    "chars": 9913,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport andr"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/PlayPauseDrawable.java",
    "chars": 8328,
    "preview": "/**\n * This code was modified by me, Paul Woitaschek. All these changes are licensed under GPLv3. The\n * original source"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/PopupImageView.java",
    "chars": 1237,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/SquareImageView.java",
    "chars": 726,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.wi"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/TextDrawable.java",
    "chars": 8241,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graph"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/ThemedPreferenceCategory.java",
    "chars": 1167,
    "preview": "package com.naman14.timber.widgets;\n\nimport android.content.Context;\nimport android.preference.PreferenceCategory;\nimpor"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/desktop/BaseWidget.java",
    "chars": 2146,
    "preview": "package com.naman14.timber.widgets.desktop;\n\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidg"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/desktop/SmallWidget.java",
    "chars": 2795,
    "preview": "package com.naman14.timber.widgets.desktop;\n\nimport android.app.PendingIntent;\nimport android.content.ComponentName;\nimp"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/desktop/StandardWidget.java",
    "chars": 3376,
    "preview": "package com.naman14.timber.widgets.desktop;\n\nimport android.app.PendingIntent;\nimport android.content.ComponentName;\nimp"
  },
  {
    "path": "app/src/main/java/com/naman14/timber/widgets/desktop/WhiteWidget.java",
    "chars": 252,
    "preview": "package com.naman14.timber.widgets.desktop;\n\nimport com.naman14.timber.R;\n\n/**\n * Created by nv95 on 11.11.16.\n */\n\npubl"
  },
  {
    "path": "app/src/main/res/anim/activity_fade_in.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:dur"
  },
  {
    "path": "app/src/main/res/anim/activity_fade_out.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<alpha xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:dur"
  },
  {
    "path": "app/src/main/res/anim/design_fab_out.xml",
    "chars": 1010,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~\n  ~ Licensed unde"
  },
  {
    "path": "app/src/main/res/anim/scale.xml",
    "chars": 438,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:inter"
  },
  {
    "path": "app/src/main/res/anim/slide_in_from_bottom.xml",
    "chars": 938,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/anim/slide_in_from_left.xml",
    "chars": 939,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/anim/slide_in_from_right.xml",
    "chars": 938,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/anim/slide_out_to_bottom.xml",
    "chars": 938,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/anim/slide_out_to_left.xml",
    "chars": 1129,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/anim/slide_out_to_right.xml",
    "chars": 1128,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  Copyright (C) 2014 The Android Open Source Project\n\n  Licensed under the A"
  },
  {
    "path": "app/src/main/res/color/state_selector_black.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/color/state_selector_dark.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/color/state_selector_light.xml",
    "chars": 253,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item a"
  },
  {
    "path": "app/src/main/res/drawable/bg_gradient.xml",
    "chars": 329,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape android:shape=\"rectangle\"\n    xmlns:android=\"http://schemas.android.com/ap"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_music_dark.xml",
    "chars": 489,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "app/src/main/res/drawable/ic_folder_open_black_24dp.xml",
    "chars": 424,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\""
  },
  {
    "path": "app/src/main/res/drawable/ic_folder_open_white_24dp.xml",
    "chars": 445,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "app/src/main/res/drawable/ic_folder_parent_dark.xml",
    "chars": 422,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "app/src/main/res/drawable/ic_menu.xml",
    "chars": 330,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n  "
  },
  {
    "path": "app/src/main/res/drawable/ic_timer_wait.xml",
    "chars": 493,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:wi"
  },
  {
    "path": "app/src/main/res/drawable/item_divider_black.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/item_divider_white.xml",
    "chars": 226,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:sha"
  },
  {
    "path": "app/src/main/res/drawable/progress_drawable.xml",
    "chars": 498,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <ite"
  },
  {
    "path": "app/src/main/res/drawable/progress_drawable_black.xml",
    "chars": 498,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <ite"
  },
  {
    "path": "app/src/main/res/drawable/progress_drawable_dark.xml",
    "chars": 498,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <ite"
  },
  {
    "path": "app/src/main/res/drawable/progress_drawable_withbackground.xml",
    "chars": 481,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <ite"
  }
]

// ... and 120 more files (download for full content)

About this extraction

This page contains the full source code of the naman14/Timber GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 320 files (1.3 MB), approximately 301.2k tokens, and a symbol index with 1896 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!