Full Code of jinkg/Style for AI

master 05796d467dae cached
342 files
868.2 KB
198.9k tokens
1055 symbols
1 requests
Download .txt
Showing preview only (980K chars total). Download the full file or copy to clipboard to get everything.
Repository: jinkg/Style
Branch: master
Commit: 05796d467dae
Files: 342
Total size: 868.2 KB

Directory structure:
gitextract_vzylt4jg/

├── .gitignore
├── README.md
├── build.gradle
├── buildApk.bat
├── buildApk.sh
├── data/
│   ├── .gitignore
│   ├── CMakeLists.txt
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── data/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── cpp/
│       │   │   └── facet_id-lib.cpp
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── data/
│       │   │                   ├── SyncConfig.java
│       │   │                   ├── cache/
│       │   │                   │   ├── AdvanceWallpaperCache.kt
│       │   │                   │   ├── AdvanceWallpaperCacheImpl.kt
│       │   │                   │   ├── GalleryWallpaperCache.kt
│       │   │                   │   ├── SourcesCache.kt
│       │   │                   │   ├── SourcesCacheImpl.kt
│       │   │                   │   ├── WallpaperCache.java
│       │   │                   │   └── WallpaperCacheImpl.java
│       │   │                   ├── entity/
│       │   │                   │   ├── AdvanceWallpaperEntity.java
│       │   │                   │   ├── DeviceInfo.java
│       │   │                   │   ├── GalleryWallpaperEntity.kt
│       │   │                   │   ├── HttpRequestBody.java
│       │   │                   │   ├── SourceEntity.kt
│       │   │                   │   ├── WallpaperEntity.java
│       │   │                   │   └── mapper/
│       │   │                   │       ├── AdvanceWallpaperEntityMapper.java
│       │   │                   │       └── WallpaperEntityMapper.java
│       │   │                   ├── exception/
│       │   │                   │   ├── LikeException.java
│       │   │                   │   ├── NetworkConnectionException.java
│       │   │                   │   ├── NoContentException.java
│       │   │                   │   ├── RemoteServerException.java
│       │   │                   │   └── ReswitchException.java
│       │   │                   ├── executor/
│       │   │                   │   ├── JobExecutor.java
│       │   │                   │   └── SerialJobExecutor.java
│       │   │                   ├── extensions/
│       │   │                   │   └── DelegateExt.kt
│       │   │                   ├── lock/
│       │   │                   │   ├── LikeWallpaperLock.java
│       │   │                   │   ├── OpenInputStreamLock.java
│       │   │                   │   ├── ResourceLock.java
│       │   │                   │   └── SelectSourceLock.java
│       │   │                   ├── log/
│       │   │                   │   └── LogUtil.java
│       │   │                   ├── observable/
│       │   │                   │   ├── SourcesObservableImpl.kt
│       │   │                   │   └── WallpaperObservableImpl.kt
│       │   │                   ├── repository/
│       │   │                   │   ├── AdvanceWallpaperDataRepository.kt
│       │   │                   │   ├── GalleryWallpaperDataRepository.kt
│       │   │                   │   ├── SourcesDataRepository.kt
│       │   │                   │   ├── StyleWallpaperDataRepository.java
│       │   │                   │   └── datasource/
│       │   │                   │       ├── AdvanceWallpaperDataStore.kt
│       │   │                   │       ├── AdvanceWallpaperDataStoreFactory.kt
│       │   │                   │       ├── AdvanceWallpaperDataStoreImpl.kt
│       │   │                   │       ├── CacheWallpaperDataStore.java
│       │   │                   │       ├── DbWallpaperDataStore.java
│       │   │                   │       ├── GalleryWallpaperDataStore.kt
│       │   │                   │       ├── GalleryWallpaperDataStoreFactory.kt
│       │   │                   │       ├── RemoteAdvanceWallpaperDataStore.kt
│       │   │                   │       ├── SourcesDataStore.kt
│       │   │                   │       ├── SourcesDataStoreFactory.kt
│       │   │                   │       ├── SourcesDataStoreImpl.kt
│       │   │                   │       ├── StyleWallpaperDataStoreFactory.java
│       │   │                   │       ├── WallpaperDataStore.java
│       │   │                   │       ├── io/
│       │   │                   │       │   ├── AdvanceWallpaperHandler.kt
│       │   │                   │       │   ├── GalleryWallpapersHandler.kt
│       │   │                   │       │   ├── JSONHandler.java
│       │   │                   │       │   ├── RemoveGalleryWallpapersHandler.kt
│       │   │                   │       │   └── WallpapersHandler.java
│       │   │                   │       ├── net/
│       │   │                   │       │   ├── DataFetcher.java
│       │   │                   │       │   └── RemoteAdvanceWallpaperFetcher.java
│       │   │                   │       ├── provider/
│       │   │                   │       │   ├── StyleContract.java
│       │   │                   │       │   ├── StyleContractHelper.java
│       │   │                   │       │   ├── StyleDatabase.java
│       │   │                   │       │   ├── StyleProvider.java
│       │   │                   │       │   ├── StyleProviderUriMatcher.java
│       │   │                   │       │   └── StyleUriEnum.java
│       │   │                   │       └── sync/
│       │   │                   │           ├── RemoteStyleDataFetcher.java
│       │   │                   │           ├── StyleDataHandler.java
│       │   │                   │           ├── SyncAdapter.java
│       │   │                   │           ├── SyncHelper.java
│       │   │                   │           ├── SyncService.java
│       │   │                   │           ├── account/
│       │   │                   │           │   ├── Account.java
│       │   │                   │           │   ├── Authenticator.java
│       │   │                   │           │   └── AuthenticatorService.java
│       │   │                   │           └── gallery/
│       │   │                   │               └── GalleryScheduleService.kt
│       │   │                   └── utils/
│       │   │                       ├── ChecksumUtil.java
│       │   │                       ├── DeviceUtil.java
│       │   │                       ├── FacetIdUtil.java
│       │   │                       ├── HttpRequestUtil.java
│       │   │                       ├── NativeFileHelper.kt
│       │   │                       ├── NetworkUtil.java
│       │   │                       ├── SelectionBuilder.java
│       │   │                       ├── TimeUtil.java
│       │   │                       ├── UriUtil.kt
│       │   │                       ├── WallpaperFileHelper.java
│       │   │                       └── WallpaperUtil.kt
│       │   └── res/
│       │       ├── values/
│       │       │   └── strings.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── authenticator.xml
│       │           └── syncadapter.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── data/
│                           └── ExampleUnitTest.java
├── domain/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── domain/
│                               ├── AdvanceWallpaper.java
│                               ├── GalleryWallpaper.java
│                               ├── Source.java
│                               ├── Wallpaper.java
│                               ├── exception/
│                               │   ├── DefaultErrorBundle.java
│                               │   └── ErrorBundle.java
│                               ├── executor/
│                               │   ├── PostExecutionThread.java
│                               │   ├── SerialThreadExecutor.java
│                               │   └── ThreadExecutor.java
│                               ├── interactor/
│                               │   ├── AddGalleryWallpaper.java
│                               │   ├── DefaultObserver.java
│                               │   ├── DownloadAdvanceWallpaper.java
│                               │   ├── ForceNow.java
│                               │   ├── GetAdvanceWallpapers.java
│                               │   ├── GetGalleryUpdateInterval.java
│                               │   ├── GetGalleryWallpaper.java
│                               │   ├── GetSelectedAdvanceWallpaper.java
│                               │   ├── GetSelectedSource.java
│                               │   ├── GetSources.java
│                               │   ├── GetWallpaper.java
│                               │   ├── GetWallpaperCount.java
│                               │   ├── LikeWallpaper.java
│                               │   ├── LoadAdvanceWallpaper.java
│                               │   ├── ObserverSources.java
│                               │   ├── ObserverWallpaper.java
│                               │   ├── OpenWallpaperInputStream.java
│                               │   ├── ReadAdvanceAd.java
│                               │   ├── RemoveGalleryWallpaper.java
│                               │   ├── SelectAdvanceWallpaper.java
│                               │   ├── SelectSource.java
│                               │   ├── SetGalleryUpdateInterval.java
│                               │   ├── SwitchWallpaper.java
│                               │   └── UseCase.java
│                               ├── observable/
│                               │   ├── SourcesObservable.java
│                               │   └── WallpaperObservable.java
│                               └── repository/
│                                   ├── SourcesRepository.java
│                                   └── WallpaperRepository.java
├── engine/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── style/
│       │                   └── engine/
│       │                       └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   ├── com/
│       │   │   │   └── yalin/
│       │   │   │       └── style/
│       │   │   │           └── engine/
│       │   │   │               ├── GDXWallpaperServiceProxy.kt
│       │   │   │               ├── GLWallpaperServiceProxy.kt
│       │   │   │               ├── IProvider.java
│       │   │   │               ├── ProxyApi.java
│       │   │   │               ├── ProxyProvider.kt
│       │   │   │               ├── WallpaperActiveCallback.kt
│       │   │   │               ├── WallpaperServiceProxy.kt
│       │   │   │               ├── advance/
│       │   │   │               │   ├── AnimationWallpaper.java
│       │   │   │               │   ├── BokehRainbowCircle.java
│       │   │   │               │   └── BokehRainbowWallpaper.java
│       │   │   │               ├── component/
│       │   │   │               │   ├── ComponentContext.java
│       │   │   │               │   └── StyleClassLoader.kt
│       │   │   │               └── resource/
│       │   │   │                   ├── BrandUtil.java
│       │   │   │                   ├── CompatResources.java
│       │   │   │                   ├── ReflectUtil.java
│       │   │   │                   └── ResourcesManager.java
│       │   │   └── net/
│       │   │       └── rbgrn/
│       │   │           └── android/
│       │   │               └── glwallpaperservice/
│       │   │                   ├── BaseConfigChooser.java
│       │   │                   └── GLWallpaperService.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── engine/
│                               └── ExampleUnitTest.java
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── presentation/
│   ├── .gitignore
│   ├── build.gradle
│   ├── component-proguard.pro
│   ├── google-services.json
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── style/
│       │                   ├── ExampleInstrumentedTest.java
│       │                   ├── provider/
│       │                   │   └── DatabaseTest.java
│       │                   └── sync/
│       │                       └── SyncAdapterTest.java
│       ├── demo/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── util/
│       │   │                   └── AdUtil.kt
│       │   └── res/
│       │       └── values/
│       │           └── ad_strings.xml
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               ├── LockScreenVisibleReceiver.kt
│       │   │               ├── StyleApplication.kt
│       │   │               ├── StyleWallpaperService.kt
│       │   │               ├── StyleWallpaperServiceMirror.kt
│       │   │               ├── UIThread.kt
│       │   │               ├── WallpaperDetailViewport.kt
│       │   │               ├── analytics/
│       │   │               │   ├── Analytics.kt
│       │   │               │   ├── Event.kt
│       │   │               │   └── IAnalytics.kt
│       │   │               ├── engine/
│       │   │               │   └── StyleWallpaperProxy.kt
│       │   │               ├── event/
│       │   │               │   ├── MainContainerInsetsChangedEvent.java
│       │   │               │   ├── SeenTutorialEvent.java
│       │   │               │   ├── StyleWallpaperSizeChangedEvent.java
│       │   │               │   ├── SwitchWallpaperServiceEvent.java
│       │   │               │   ├── SwitchingPhotosStateChangedEvent.java
│       │   │               │   ├── SystemWallpaperSizeChangedEvent.java
│       │   │               │   ├── WallpaperActivateEvent.java
│       │   │               │   ├── WallpaperDetailOpenedEvent.java
│       │   │               │   └── WallpaperSwitchEvent.java
│       │   │               ├── exception/
│       │   │               │   └── ErrorMessageFactory.java
│       │   │               ├── extensions/
│       │   │               │   └── DelegatesExtensions.kt
│       │   │               ├── injection/
│       │   │               │   ├── HasComponent.kt
│       │   │               │   ├── PerActivity.kt
│       │   │               │   ├── component/
│       │   │               │   │   ├── ApplicationComponent.kt
│       │   │               │   │   ├── SourceComponent.kt
│       │   │               │   │   └── WallpaperComponent.kt
│       │   │               │   └── modules/
│       │   │               │       ├── ApplicationModule.kt
│       │   │               │       ├── SourceModule.kt
│       │   │               │       └── WallpaperModule.kt
│       │   │               ├── mapper/
│       │   │               │   ├── AdvanceWallpaperItemMapper.kt
│       │   │               │   └── WallpaperItemMapper.kt
│       │   │               ├── model/
│       │   │               │   ├── AdvanceWallpaperItem.java
│       │   │               │   ├── GalleryWallpaperItem.java
│       │   │               │   ├── SourceItem.kt
│       │   │               │   └── WallpaperItem.java
│       │   │               ├── presenter/
│       │   │               │   ├── AdvanceSettingPresenter.kt
│       │   │               │   ├── GallerySettingPresenter.kt
│       │   │               │   ├── Presenter.kt
│       │   │               │   ├── SettingsChooseSourcePresenter.kt
│       │   │               │   └── WallpaperDetailPresenter.kt
│       │   │               ├── render/
│       │   │               │   ├── BitmapRegionLoader.java
│       │   │               │   ├── DemoRenderController.kt
│       │   │               │   ├── GLColorOverlay.java
│       │   │               │   ├── GLPicture.java
│       │   │               │   ├── GLTextureView.java
│       │   │               │   ├── GLUtil.java
│       │   │               │   ├── ImageBlurrer.java
│       │   │               │   ├── ImageUtil.java
│       │   │               │   ├── RenderController.kt
│       │   │               │   ├── StyleBlurRenderer.java
│       │   │               │   └── TickingFloatAnimator.java
│       │   │               ├── settings/
│       │   │               │   └── Prefs.java
│       │   │               ├── util/
│       │   │               │   ├── ImageLoader.java
│       │   │               │   ├── MathUtil.java
│       │   │               │   ├── MultiSelectionController.kt
│       │   │               │   ├── ScrimUtil.java
│       │   │               │   ├── SettingsUtil.java
│       │   │               │   ├── ShareUtil.kt
│       │   │               │   ├── SvgPathParser.java
│       │   │               │   └── TypefaceUtil.java
│       │   │               └── view/
│       │   │                   ├── AdvanceSettingView.kt
│       │   │                   ├── GallerySettingView.kt
│       │   │                   ├── LoadingDataView.kt
│       │   │                   ├── SourceChooseView.kt
│       │   │                   ├── WallpaperDetailView.kt
│       │   │                   ├── activity/
│       │   │                   │   ├── AboutActivity.kt
│       │   │                   │   ├── AdvanceSettingActivity.kt
│       │   │                   │   ├── BaseActivity.kt
│       │   │                   │   ├── GallerySettingActivity.kt
│       │   │                   │   ├── SettingsActivity.kt
│       │   │                   │   └── StyleActivity.kt
│       │   │                   ├── component/
│       │   │                   │   ├── CircleProgressView.java
│       │   │                   │   ├── DownloadingDialog.kt
│       │   │                   │   ├── DrawInsetsFrameLayout.java
│       │   │                   │   ├── GalleryEmptyStateGraphicView.kt
│       │   │                   │   ├── ObservableHorizontalScrollView.kt
│       │   │                   │   ├── PanScaleProxyView.java
│       │   │                   │   ├── Scrollbar.kt
│       │   │                   │   ├── ShadowDipsTextView.kt
│       │   │                   │   ├── TintableImageButton.kt
│       │   │                   │   └── Zoomer.kt
│       │   │                   └── fragment/
│       │   │                       ├── AnimatedStyleLogoFragment.kt
│       │   │                       ├── BaseFragment.kt
│       │   │                       ├── SettingsAdvanceFragment.kt
│       │   │                       ├── SettingsChooseSourceFragment.kt
│       │   │                       ├── StyleRenderFragment.java
│       │   │                       ├── TutorialFragment.kt
│       │   │                       └── WallpaperDetailFragment.kt
│       │   └── res/
│       │       ├── anim/
│       │       │   └── image_fade_in.xml
│       │       ├── anim-v21/
│       │       │   └── tutorial_icon_emanate_interpolator.xml
│       │       ├── animator/
│       │       │   ├── fade_in.xml
│       │       │   ├── fade_out.xml
│       │       │   ├── tutorial_icon_emanate_wave1.xml
│       │       │   ├── tutorial_icon_emanate_wave1_path.xml
│       │       │   ├── tutorial_icon_emanate_wave2.xml
│       │       │   ├── tutorial_icon_emanate_wave2_path.xml
│       │       │   └── tutorial_icon_overlay_state_list.xml
│       │       ├── color/
│       │       │   └── selector_skip_tint.xml
│       │       ├── drawable/
│       │       │   ├── gallery_ic_add.xml
│       │       │   ├── gallery_ic_add_folder.xml
│       │       │   ├── gallery_ic_add_photo.xml
│       │       │   ├── gallery_ic_folder.xml
│       │       │   ├── grey_selectable_item_background_circle.xml
│       │       │   ├── intro_background_protection.xml
│       │       │   ├── popup_background.xml
│       │       │   ├── scrubber_control_selector.xml
│       │       │   ├── scrubber_progress_blur_amount.xml
│       │       │   ├── scrubber_progress_dim_amount.xml
│       │       │   ├── scrubber_progress_grey_amount.xml
│       │       │   ├── scrubber_progress_horizontal.xml
│       │       │   ├── settings_source_item_image_overlay.xml
│       │       │   ├── tutorial_icon_on_overlay.xml
│       │       │   └── white_circle_button.xml
│       │       ├── drawable-v21/
│       │       │   ├── avd_tutorial_icon_emanate.xml
│       │       │   ├── grey_selectable_item_background_circle.xml
│       │       │   ├── settings_source_item_image_overlay.xml
│       │       │   ├── tutorial_icon_emanate.xml
│       │       │   └── tutorial_icon_on_overlay.xml
│       │       ├── layout/
│       │       │   ├── activity_about.xml
│       │       │   ├── activity_advance_setting.xml
│       │       │   ├── activity_gallery_setting.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_settings.xml
│       │       │   ├── advance_chosen_wallpaper_item.xml
│       │       │   ├── animated_logo_fragment.xml
│       │       │   ├── dialog_downloading.xml
│       │       │   ├── gallery_chosen_photo_item.xml
│       │       │   ├── gallery_chosen_photo_tree_item.xml
│       │       │   ├── layout_include_about_content.xml
│       │       │   ├── layout_include_active.xml
│       │       │   ├── layout_include_settings_content.xml
│       │       │   ├── layout_include_tutorial_content.xml
│       │       │   ├── layout_include_wallpaper_detail.xml
│       │       │   ├── layout_include_wallpaper_tutorial.xml
│       │       │   ├── layout_settings_choose_source.xml
│       │       │   ├── layout_style_settings.xml
│       │       │   ├── layout_wallpaper_detail.xml
│       │       │   ├── settings_ab_spinner_list_item.xml
│       │       │   ├── settings_ab_spinner_list_item_dropdown.xml
│       │       │   └── settings_choose_source_item.xml
│       │       ├── menu/
│       │       │   ├── advance_activity.xml
│       │       │   ├── gallery_activity.xml
│       │       │   ├── gallery_selection.xml
│       │       │   ├── menu_settings.xml
│       │       │   ├── menu_settings_advanced.xml
│       │       │   └── style_overflow.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── ids.xml
│       │       │   ├── integers.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       ├── values-v19/
│       │       │   └── styles.xml
│       │       ├── values-v21/
│       │       │   └── styles.xml
│       │       ├── values-w820dp/
│       │       │   └── dimens.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── shortcuts.xml
│       │           └── wallpaper.xml
│       ├── production/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── util/
│       │   │                   └── AdUtil.kt
│       │   └── res/
│       │       └── values/
│       │           └── ad_strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── ExampleUnitTest.java
├── settings.gradle
└── switch.properties

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

================================================
FILE: .gitignore
================================================
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild


================================================
FILE: README.md
================================================
# Deprecated, Not maintain anymore.

# Style Live Wallpaper

A live wallpaper project for Android
====================
<a href="https://play.google.com/store/apps/details?id=com.kinglloy.album" target="_blank">
<img src="https://play.google.com/intl/en_us/badges/images/generic/en-play-badge.png" alt="Get it on Google Play" height="90"/></a>

For developer
=========

Style offers a sdk that allows you to build your own live wallpaper.

**[Develop Doc](https://github.com/jinkg/style-develop-sdk)**&nbsp;&nbsp;•&nbsp;&nbsp;**[For more examples](https://github.com/jinkg/style-sdk)**

![bezier](https://github.com/jinkg/Screenshots/blob/master/Style/bezier.gif)
![boids](https://github.com/jinkg/Screenshots/blob/master/Style/boids.gif)
![botz](https://github.com/jinkg/Screenshots/blob/master/Style/botz.gif)
![flower](https://github.com/jinkg/Screenshots/blob/master/Style/flower.gif)
![rainbow](https://github.com/jinkg/Screenshots/blob/master/Style/rainbow.gif)
![shark](https://github.com/jinkg/Screenshots/blob/master/Style/shark.gif)
![stride](https://github.com/jinkg/Screenshots/blob/master/Style/stride.gif)
![yinyang](https://github.com/jinkg/Screenshots/blob/master/Style/yinyang.gif)


================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.1'
        classpath 'com.google.gms:google-services:3.0.0'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


================================================
FILE: buildApk.bat
================================================
@echo off
echo Start Build Apk

call gradlew clean
call gradlew assembleProductionRelease -Dchannel=kinglloy
call gradlew assembleProductionRelease -Dchannel=yingyongbao
call gradlew assembleProductionRelease -Dchannel=360 -Dapp_name=Style艺术壁纸
call gradlew assembleProductionRelease -Dchannel=vivo
call gradlew assembleProductionRelease -Dchannel=flyme
call gradlew assembleProductionRelease -Dchannel=wandoujia
call gradlew assembleProductionRelease -Dchannel=baidu -Dapp_name=Style艺术壁纸
call gradlew assembleProductionRelease -Dchannel=google
call gradlew assembleProductionRelease -Dchannel=huawei -Dapp_name=Style艺术壁纸

echo Build Apk Complete

================================================
FILE: buildApk.sh
================================================
#!/usr/bin/env bash
echo "Start Build Apk"

./gradlew clean
./gradlew assembleProductionRelease -Dchannel=kinglloy
./gradlew assembleProductionRelease -Dchannel=yingyongbao
./gradlew assembleProductionRelease -Dchannel=360 -Dapp_name=Style艺术壁纸
./gradlew assembleProductionRelease -Dchannel=vivo
./gradlew assembleProductionRelease -Dchannel=flyme
./gradlew assembleProductionRelease -Dchannel=wandoujia
./gradlew assembleProductionRelease -Dchannel=baidu -Dapp_name=Style艺术壁纸
./gradlew assembleProductionRelease -Dchannel=google
./gradlew assembleProductionRelease -Dchannel=huawei -Dapp_name=Style艺术壁纸

echo "Build Apk Complete"


================================================
FILE: data/.gitignore
================================================
/build


================================================
FILE: data/CMakeLists.txt
================================================
# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds it for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             facet_id-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             # Associated headers in the same location as their source
             # file are automatically included.
             src/main/cpp/facet_id-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because system libraries are included in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in the
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       facet_id-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )


================================================
FILE: data/build.gradle
================================================
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.3'
    }
}

apply plugin: 'com.android.library'
apply plugin: 'me.tatarka.retrolambda'
apply plugin: 'kotlin-android'

Properties properties = new Properties()
properties.load(project.rootProject.file('switch.properties').newDataInputStream())

def ENABLE_EXTERNAL_LOG = properties.get('ENABLE_EXTERNAL_LOG')
def LOG_ENABLE = properties.get('LOG_ENABLE')

def CHANNEL = System.getProperty("channel", "default")

android {
    compileSdkVersion COMPILE_SDK_VERSION as int
    buildToolsVersion BUILD_TOOLS_VERSION as String

    defaultConfig {
        minSdkVersion MIN_SDK_VERSION as int
        targetSdkVersion TARGET_SDK_VERSION as int
        versionCode APP_VERSION_CODE as int
        versionName APP_VERSION_NAME as String

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
        }
        buildConfigField("boolean", "LOG_ENABLE", "${LOG_ENABLE}")
        buildConfigField("String", "CHANNEL", "\"${CHANNEL}\"")
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    publishNonDefault true
    productFlavors {
        demo {
            buildConfigField("boolean", "DEMO_MODE", "true")
            buildConfigField("boolean", "ENABLE_EXTERNAL_LOG", "true")
            buildConfigField("String", "SERVER_WALLPAPER_ENDPOINT", "\"${DEMO_API_WALLPAPER_ENDPOINT}\"")
        }
        production {
            buildConfigField("boolean", "DEMO_MODE", "false")
            buildConfigField("boolean", "ENABLE_EXTERNAL_LOG", "${ENABLE_EXTERNAL_LOG}")
            buildConfigField("String", "SERVER_WALLPAPER_ENDPOINT", "\"${PRODUCTION_API_WALLPAPER_ENDPOINT}\"")
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "com.android.support:appcompat-v7:${SUPPORT_LIBRARY_VERSION}"
    compile "com.android.support:exifinterface:${SUPPORT_LIBRARY_VERSION}"
    compile "org.jetbrains.kotlin:kotlin-stdlib:${KOTLIN_VERSION}"
    compile "org.jetbrains.anko:anko-common:${ANKO_VESION}"
    compile "org.jetbrains.anko:anko-sqlite:${ANKO_VESION}"
    compile "com.google.code.gson:gson:${GSON_VERSION}"
    compile "com.squareup.okhttp3:okhttp:${OK_HTTP_VERSION}"
    compile project(':domain')

    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'

}


================================================
FILE: data/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/jinyalin/Library/Android/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 liked 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 *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you liked the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile


================================================
FILE: data/src/androidTest/java/com/yalin/data/ExampleInstrumentedTest.java
================================================
package com.yalin.data;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
 * Instrumentation test, which will execute on an Android device.
 *
 * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
 */
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
    @Test
    public void useAppContext() throws Exception {
        // Context of the app under test.
        Context appContext = InstrumentationRegistry.getTargetContext();

        assertEquals("com.yalin.data.test", appContext.getPackageName());
    }
}


================================================
FILE: data/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.yalin.style.data">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.READ_SYNC_STATS" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:supportsRtl="true">

        <service
            android:name=".repository.datasource.sync.SyncService"
            android:exported="false">
            <intent-filter>
                <action android:name="android.content.SyncAdapter" />
            </intent-filter>
            <meta-data
                android:name="android.content.SyncAdapter"
                android:resource="@xml/syncadapter" />
        </service>

        <service
            android:name=".repository.datasource.sync.account.AuthenticatorService"
            android:exported="false">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator" />
            </intent-filter>

            <meta-data
                android:name="android.accounts.AccountAuthenticator"
                android:resource="@xml/authenticator" />
        </service>

        <service
            android:name=".repository.datasource.sync.gallery.GalleryScheduleService"
            android:exported="false">
            <intent-filter>
                <action android:name="com.yalin.style.ACTION_START_UP" />
                <action android:name="com.yalin.style.ACTION_SHUT_DOWN" />
                <action android:name="com.yalin.style.ACTION_SCHEDULE" />
                <action android:name="com.yalin.style.ACTION_SET_INTERVAL" />
            </intent-filter>

        </service>

        <provider
            android:name=".repository.datasource.provider.StyleProvider"
            android:authorities="com.yalin.style"
            android:exported="false"
            android:syncable="true" />

    </application>

</manifest>


================================================
FILE: data/src/main/cpp/facet_id-lib.cpp
================================================
#include <jni.h>
#include <string>
#include <android/log.h>

#define LOG_TAG ("facet_id_check")
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)

int LOG_ENABLE = 0;
const char *LOG = "LOG";

int check_facet_id(JNIEnv *, jstring);

jstring get_facet_id(JNIEnv *, jobject, jint);

void printLog(const char *);

extern "C"
jboolean
Java_com_yalin_style_data_utils_FacetIdUtil_checkCurrentFacetId__Landroid_content_Context_2I(
        JNIEnv *env, jclass, jobject context, jint uId) {
    jstring facet_id = get_facet_id(env, context, uId);;
    int check_result = check_facet_id(env, facet_id);
    bool result = check_result == 0;
    return (jboolean) result;
}

extern "C"
jstring
Java_com_yalin_style_data_utils_FacetIdUtil_getFacetId__Landroid_content_Context_2I(
        JNIEnv *env, jclass, jobject context, jint uId) {
    return get_facet_id(env, context, uId);
}

jstring get_facet_id(JNIEnv *env, jobject context, jint uId) {

    jclass contextClazz = env->FindClass("android/content/Context");
    jmethodID getPackageManagerMethodId = env->GetMethodID(contextClazz, "getPackageManager",
                                                           "()Landroid/content/pm/PackageManager;");
    jobject packageManager = env->CallObjectMethod(context, getPackageManagerMethodId);

    printLog("PackageManager obtained.");

    jclass packageManagerClazz = env->FindClass("android/content/pm/PackageManager");
    jmethodID getPackageForUidMethodId = env->GetMethodID(packageManagerClazz, "getPackagesForUid",
                                                          "(I)[Ljava/lang/String;");

    jobjectArray packageNames = (jobjectArray) (jarray) env->CallObjectMethod(packageManager,
                                                                              getPackageForUidMethodId,
                                                                              uId);
    jstring packageName = (jstring) env->GetObjectArrayElement(packageNames, 0);

    printLog("packageName obtained.");

    jmethodID getPackageInfoMethodId = env->GetMethodID(packageManagerClazz, "getPackageInfo",
                                                        "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
    jfieldID flag = env->GetStaticFieldID(packageManagerClazz, "GET_SIGNATURES", "I");

    jint signaturesFlag = env->GetStaticIntField(packageManagerClazz, flag);

    jobject packageInfo = env->CallObjectMethod(packageManager, getPackageInfoMethodId,
                                                packageName, signaturesFlag);

    printLog("packageInfo obtained.");

    jclass packageInfoClazz = env->FindClass("android/content/pm/PackageInfo");

    jfieldID signatureFieldId = env->GetFieldID(packageInfoClazz, "signatures",
                                                "[Landroid/content/pm/Signature;");
    jobjectArray signatures = (jobjectArray) env->GetObjectField(packageInfo, signatureFieldId);

    printLog("signatures obtained.");

    jclass signatureClazz = env->FindClass("android/content/pm/Signature");
    jmethodID toByteArrayMethodId = env->GetMethodID(signatureClazz, "toByteArray", "()[B");

    jbyteArray cert = (jbyteArray) env->CallObjectMethod(env->GetObjectArrayElement(signatures, 0),
                                                         toByteArrayMethodId);

    printLog("cert obtained.");

    jclass inputStreamClazz = env->FindClass("java/io/ByteArrayInputStream");
    jmethodID inputStreamConstructorMethodId = env->GetMethodID(inputStreamClazz, "<init>",
                                                                "([B)V");
    jobject inputStream = env->NewObject(inputStreamClazz, inputStreamConstructorMethodId, cert);

    printLog("inputStream obtained.");

    jclass certificateFactoryClazz = env->FindClass("java/security/cert/CertificateFactory");
    jmethodID certificateFactoryGetInstanceMethodId = env->GetStaticMethodID(
            certificateFactoryClazz,
            "getInstance",
            "(Ljava/lang/String;)Ljava/security/cert/CertificateFactory;");
    jstring x509String = env->NewStringUTF("X509");
    jobject certificateFactory = env->CallStaticObjectMethod(certificateFactoryClazz,
                                                             certificateFactoryGetInstanceMethodId,
                                                             x509String);

    printLog("certificateFactory obtained.");

    jmethodID generateCertificateMethodId = env->GetMethodID(certificateFactoryClazz,
                                                             "generateCertificate",
                                                             "(Ljava/io/InputStream;)Ljava/security/cert/Certificate;");
    jclass x509CertificateClazz = env->FindClass("java/security/cert/X509Certificate");

    jobject x509Certificate = env->CallObjectMethod(certificateFactory, generateCertificateMethodId,
                                                    inputStream);

    printLog("x509Certificate obtained.");

    jclass messageDigestClazz = env->FindClass("java/security/MessageDigest");
    jmethodID messageDigestInstanceMethodId = env->GetStaticMethodID(messageDigestClazz,
                                                                     "getInstance",
                                                                     "(Ljava/lang/String;)Ljava/security/MessageDigest;");

    jstring sha1 = env->NewStringUTF("SHA1");
    jobject messageDigest = env->CallStaticObjectMethod(messageDigestClazz,
                                                        messageDigestInstanceMethodId, sha1);

    printLog("messageDigest obtained.");

    jmethodID certificateEncodeMethodId = env->GetMethodID(x509CertificateClazz, "getEncoded",
                                                           "()[B");
    jbyteArray certEncode = (jbyteArray) env->CallObjectMethod(x509Certificate,
                                                               certificateEncodeMethodId);

    printLog("certEncode obtained.");

    jmethodID messageDigestMethodId = env->GetMethodID(messageDigestClazz, "digest", "([B)[B");
    jbyteArray digestArray = (jbyteArray) env->CallObjectMethod(messageDigest,
                                                                messageDigestMethodId,
                                                                certEncode);

    printLog("digestArray obtained.");

    jclass base64Clazz = env->FindClass("android/util/Base64");
    jmethodID encodeToStringMethodId = env->GetStaticMethodID(base64Clazz, "encodeToString",
                                                              "([BI)Ljava/lang/String;");

    jfieldID base64FlagFiledId = env->GetStaticFieldID(base64Clazz, "DEFAULT",
                                                       "I");
    jint base64DefaultFlag = env->GetStaticIntField(base64Clazz, base64FlagFiledId);

    jstring result = (jstring) env->CallStaticObjectMethod(base64Clazz, encodeToStringMethodId,
                                                           digestArray, base64DefaultFlag);

    printLog("result obtained.");

    env->DeleteLocalRef(packageManager);
    env->DeleteLocalRef(packageNames);
    env->DeleteLocalRef(packageInfo);
    env->DeleteLocalRef(signatures);
    env->DeleteLocalRef(cert);
    env->DeleteLocalRef(inputStream);
    env->DeleteLocalRef(certificateFactory);
    env->DeleteLocalRef(x509Certificate);
    env->DeleteLocalRef(messageDigest);
    env->DeleteLocalRef(certEncode);
    env->DeleteLocalRef(digestArray);

    return result;
}

int check_facet_id(JNIEnv *env, jstring facet_id) {
    // modify to your app's facet wallpaperId
    jstring valid_facet_id_string = env->NewStringUTF("unkown");

    const char *valid_facet_id = env->GetStringUTFChars(valid_facet_id_string, 0);
    char *target_facet_id = (char *) env->GetStringUTFChars(facet_id, 0);

//    target_facet_id[strcspn(target_facet_id, "\r\n")] = '\0';

    printLog(target_facet_id);
    printLog(valid_facet_id);

    int result = strcmp(target_facet_id, valid_facet_id);

    char tmp[128];
    sprintf(tmp, "check complete: result=%d", result);
    printLog(tmp);

    env->DeleteLocalRef(valid_facet_id_string);
    return result;
}

void printLog(const char *str) {
    if (LOG_ENABLE == 0) {
        return;
    }

    LOGI(str, LOG);
}

================================================
FILE: data/src/main/java/com/yalin/style/data/SyncConfig.java
================================================
package com.yalin.style.data;

import java.util.concurrent.TimeUnit;

/**
 * YaLin 2017/1/3.
 */

public class SyncConfig {

  public static final int DEFAULT_DOWNLOAD_TIMEOUT = 120; // in seconds
  public static final int DEFAULT_READ_TIMEOUT = 30; // in seconds
  public static final int DEFAULT_CONNECT_TIMEOUT = 15; // in seconds


  public static final long DEBUG_AUTO_SYNC_INTERVAL_LONG =
      TimeUnit.MILLISECONDS.convert(5L, TimeUnit.MINUTES);

  public static final long AUTO_SYNC_INTERVAL_LONG =
      TimeUnit.MILLISECONDS.convert(16L, TimeUnit.HOURS);
}


================================================
FILE: data/src/main/java/com/yalin/style/data/cache/AdvanceWallpaperCache.kt
================================================
package com.yalin.style.data.cache

import com.yalin.style.data.entity.AdvanceWallpaperEntity

/**
 * @author jinyalin
 * @since 2017/8/4.
 */
interface AdvanceWallpaperCache {
    fun put(wallpapers: List<AdvanceWallpaperEntity>)

    fun getSelectedWallpaper(): AdvanceWallpaperEntity?

    fun selectWallpaper(wallpaperId: String)

    fun getWallpapers(): List<AdvanceWallpaperEntity>

    fun getWallpaper(wallpaperId: String): AdvanceWallpaperEntity?

    fun readAd(wallpaperId: String)

    fun evictAll()

    fun isCached(wallpaperId: String): Boolean

    fun isDirty(): Boolean

    fun makeDirty()
}

================================================
FILE: data/src/main/java/com/yalin/style/data/cache/AdvanceWallpaperCacheImpl.kt
================================================
package com.yalin.style.data.cache

import android.text.TextUtils
import com.yalin.style.data.entity.AdvanceWallpaperEntity
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/8/4.
 */
@Singleton
class AdvanceWallpaperCacheImpl @Inject constructor() : AdvanceWallpaperCache {
    private var wallpapers: List<AdvanceWallpaperEntity>? = null

    @Synchronized override fun put(wallpapers: List<AdvanceWallpaperEntity>) {
        this.wallpapers = wallpapers
    }

    override fun getSelectedWallpaper(): AdvanceWallpaperEntity? {
        if (isDirty()) {
            return null
        }
        return wallpapers!!.firstOrNull { it.isSelected }
    }

    override fun selectWallpaper(wallpaperId: String) {
        if (isDirty()) {
            throw IllegalStateException("Cache is dirty.")
        }
        for (wallpaper in wallpapers!!) {
            wallpaper.isSelected = TextUtils.equals(wallpaperId, wallpaper.wallpaperId)
        }
    }

    override fun getWallpapers(): List<AdvanceWallpaperEntity> {
        if (isDirty()) {
            throw IllegalStateException("Cache is dirty.")
        }
        return ArrayList(wallpapers!!)
    }

    override fun getWallpaper(wallpaperId: String): AdvanceWallpaperEntity? {
        if (!isCached(wallpaperId)) {
            throw IllegalStateException("WallpaperId $wallpaperId is not cached.")
        }
        return wallpapers!!.firstOrNull { TextUtils.equals(wallpaperId, it.wallpaperId) }
    }

    override fun readAd(wallpaperId: String) {
        if (isCached(wallpaperId)) {
            getWallpaper(wallpaperId)?.needAd = false
        }
    }

    @Synchronized override fun evictAll() {
        wallpapers = null
    }

    override fun isCached(wallpaperId: String): Boolean {
        if (isDirty()) {
            return false
        }
        return wallpapers!!.any { TextUtils.equals(wallpaperId, it.wallpaperId) }
    }

    override fun isDirty(): Boolean {
        return wallpapers == null || wallpapers!!.isEmpty()
    }

    override fun makeDirty() {
        evictAll()
    }

}

================================================
FILE: data/src/main/java/com/yalin/style/data/cache/GalleryWallpaperCache.kt
================================================
package com.yalin.style.data.cache

import com.yalin.style.data.entity.GalleryWallpaperEntity
import javax.inject.Inject
import javax.inject.Singleton


/**
 * @author jinyalin
 * @since 2017/5/26.
 */
@Singleton
class GalleryWallpaperCache @Inject constructor() {
    private var wallpaperEntities: List<GalleryWallpaperEntity>? = null

    fun put(wallpaperEntities: List<GalleryWallpaperEntity>) {
        this.wallpaperEntities = wallpaperEntities
    }

    fun get() = wallpaperEntities

    fun isCached() = wallpaperEntities != null && wallpaperEntities!!.isNotEmpty()

    fun isDirty() = wallpaperEntities == null || wallpaperEntities!!.isEmpty()

    fun evictAll() {
        wallpaperEntities = null
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/cache/SourcesCache.kt
================================================
package com.yalin.style.data.cache

import android.content.Context
import com.yalin.style.data.entity.SourceEntity
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/5/22.
 */
interface SourcesCache {
    fun getSources(ctx: Context): Observable<List<SourceEntity>>

    fun selectSource(selectSourceId: Int, tempSelect: Boolean): Boolean

    fun getUsedSourceId(): Int
}

================================================
FILE: data/src/main/java/com/yalin/style/data/cache/SourcesCacheImpl.kt
================================================
package com.yalin.style.data.cache

import android.content.Context
import android.graphics.Color
import com.yalin.style.data.R
import com.yalin.style.data.entity.SourceEntity
import com.yalin.style.data.extensions.DelegateExt
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.repository.datasource.sync.gallery.GalleryScheduleService
import com.yalin.style.domain.repository.SourcesRepository.*
import io.reactivex.Observable
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/22.
 */
@Singleton
class SourcesCacheImpl @Inject
constructor(val ctx: Context) : SourcesCache {
    var selectedId: Int by DelegateExt.preferences(ctx, "selected_source_id", SOURCE_ID_STYLE)

    val advanceSource: SourceEntity
    val featureSource: SourceEntity
    val gallerySource: SourceEntity

    init {
        advanceSource = SourceEntity(SOURCE_ID_ADVANCE).apply {
            title = ctx.getString(R.string.advance_source_title)
            iconId = R.drawable.style_ic_source
            description = ctx.getString(R.string.advance_source_description)
            color = Color.WHITE
            isSelected = selectedId == id
            isHasSetting = true
        }
        featureSource = SourceEntity(SOURCE_ID_STYLE).apply {
            title = ctx.getString(R.string.featuredart_source_title)
            iconId = R.drawable.style_ic_source
            description = ctx.getString(R.string.featuredart_source_description)
            color = Color.WHITE
            isSelected = selectedId == id
            isHasSetting = false
        }

        gallerySource = SourceEntity(SOURCE_ID_CUSTOM).apply {
            title = ctx.getString(R.string.gallery_title)
            iconId = R.drawable.gallery_ic_source
            description = ctx.getString(R.string.gallery_description)
            color = 0x4db6ac
            isSelected = selectedId == id
            isHasSetting = true
        }

        if (getUsedSourceId() == SOURCE_ID_CUSTOM) {
            GalleryScheduleService.startUp(ctx)
        }
    }

    override fun getSources(ctx: Context): Observable<List<SourceEntity>> {
        return Observable.create { emitter ->
            val sources = ArrayList<SourceEntity>()
            sources.add(advanceSource)
            sources.add(featureSource)
            sources.add(gallerySource)
            emitter.onNext(sources)
            emitter.onComplete()
        }
    }

    override fun selectSource(selectSourceId: Int, tempSelect: Boolean): Boolean {
        var success = false
        if (featureSource.id == selectSourceId) {
            featureSource.isSelected = true
            gallerySource.isSelected = false
            advanceSource.isSelected = false
            success = true

            GalleryScheduleService.shutDown(ctx)
        } else if (gallerySource.id == selectSourceId) {
            featureSource.isSelected = false
            gallerySource.isSelected = true
            advanceSource.isSelected = false
            success = true

            GalleryScheduleService.startUp(ctx)
        } else if (advanceSource.id == selectSourceId) {
            featureSource.isSelected = false
            gallerySource.isSelected = false
            advanceSource.isSelected = true

            success = true

            GalleryScheduleService.shutDown(ctx)
        }
        selectedId = selectSourceId
        if (success) {
            notifyChanged()
        }
        return success
    }

    override fun getUsedSourceId(): Int {
        return selectedId
    }

    private fun notifyChanged() {
        ctx.contentResolver.notifyChange(StyleContract.Source.CONTENT_URI, null)
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/cache/WallpaperCache.java
================================================
package com.yalin.style.data.cache;

import com.yalin.style.data.entity.WallpaperEntity;

import java.util.Queue;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/20.
 */

public interface WallpaperCache {

  /**
   * return the first
   *
   * @return wallpaperEntity
   */
  Observable<WallpaperEntity> get();

  Observable<WallpaperEntity> getNext();

  Observable<Integer> getWallpaperCount();

  void likeWallpaper(String wallpaperId);

  void put(Queue<WallpaperEntity> wallpaperEntities);

  boolean isCached();

  boolean isCached(String wallpaperId);

  boolean isDirty();

  void evictAll();
}


================================================
FILE: data/src/main/java/com/yalin/style/data/cache/WallpaperCacheImpl.java
================================================
package com.yalin.style.data.cache;

import android.text.TextUtils;

import com.fernandocejas.arrow.checks.Preconditions;
import com.yalin.style.data.entity.WallpaperEntity;

import java.util.Queue;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/20.
 */
@Singleton
public class WallpaperCacheImpl implements WallpaperCache {

    private Queue<WallpaperEntity> wallpaperEntities;

    @Inject
    public WallpaperCacheImpl() {
    }

    @Override
    public Observable<WallpaperEntity> get() {
        Preconditions.checkNotNull(wallpaperEntities, "There is not cached wallpaper.");
        Preconditions.checkArgument(!wallpaperEntities.isEmpty(), "There is not cached wallpaper.");
        return Observable.create(emitter -> {
            emitter.onNext(wallpaperEntities.peek());
            emitter.onComplete();
        });
    }

    @Override
    public Observable<WallpaperEntity> getNext() {
        Preconditions.checkNotNull(wallpaperEntities, "There is not cached wallpaper.");
        Preconditions.checkArgument(!wallpaperEntities.isEmpty(), "There is not cached wallpaper.");
        return Observable.create(emitter -> {
            WallpaperEntity entity = wallpaperEntities.poll();
            wallpaperEntities.offer(entity);
            emitter.onNext(wallpaperEntities.peek());
            emitter.onComplete();
        });
    }

    @Override
    public Observable<Integer> getWallpaperCount() {
        Preconditions.checkNotNull(wallpaperEntities, "There is not cached wallpaper.");
        return Observable.create(emitter -> {
            emitter.onNext(wallpaperEntities.size());
            emitter.onComplete();
        });
    }

    @Override
    public void likeWallpaper(String wallpaperId) {
        Preconditions.checkNotNull(wallpaperId, "There is not cached wallpaper.");
        if (isCached(wallpaperId)) {
            WallpaperEntity entity = get(wallpaperId);
            if (entity != null) {
                entity.liked = !entity.liked;
            }
        }
    }

    @Override
    public synchronized void put(Queue<WallpaperEntity> wallpaperEntities) {
        this.wallpaperEntities = wallpaperEntities;
    }

    @Override
    public boolean isCached() {
        return wallpaperEntities != null && !wallpaperEntities.isEmpty();
    }

    @Override
    public boolean isCached(String wallpaperId) {
        if (isDirty()) {
            return false;
        }
        for (WallpaperEntity entity : wallpaperEntities) {
            if (TextUtils.equals(entity.wallpaperId, wallpaperId)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isDirty() {
        return wallpaperEntities == null;
    }

    @Override
    public synchronized void evictAll() {
        if (wallpaperEntities != null) {
            wallpaperEntities.clear();
        }
        wallpaperEntities = null;
    }

    private WallpaperEntity get(String wallpaperId) {
        for (WallpaperEntity entity : wallpaperEntities) {
            if (TextUtils.equals(entity.wallpaperId, wallpaperId)) {
                return entity;
            }
        }
        return null;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/AdvanceWallpaperEntity.java
================================================
package com.yalin.style.data.entity;

import android.database.Cursor;
import android.text.TextUtils;

import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jinyalin
 * @since 2017/7/28.
 */

public class AdvanceWallpaperEntity {
    private static final String TAG = "AdvanceWallpaperEntity";

    public int id;
    public String wallpaperId;
    public String link;
    public String name;
    public String author;
    public String iconUrl;
    public String downloadUrl;
    public String providerName;

    public boolean lazyDownload;
    public boolean needAd;

    public String storePath;
    public String checkSum;

    public boolean isDefault = false;

    public boolean isSelected = false;

    public static List<AdvanceWallpaperEntity> readCursor(Cursor cursor) {
        List<AdvanceWallpaperEntity> validWallpapers = new ArrayList<>();
        while (cursor != null && cursor.moveToNext()) {
            AdvanceWallpaperEntity wallpaperEntity = readEntityFromCursor(cursor);
            try {
                if (!wallpaperEntity.lazyDownload
                        && !new File(wallpaperEntity.storePath).exists()) {
                    throw new FileNotFoundException("Component not found.");
                }
                validWallpapers.add(wallpaperEntity);
            } catch (Exception e) {
                LogUtil.D(TAG, "File not found with wallpaper wallpaperId : "
                        + wallpaperEntity.wallpaperId);
            }
        }
        return validWallpapers;
    }

    public static AdvanceWallpaperEntity readEntityFromCursor(Cursor cursor) {
        AdvanceWallpaperEntity wallpaperEntity = new AdvanceWallpaperEntity();

        wallpaperEntity.id = cursor.getInt(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper._ID));
        wallpaperEntity.name = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_NAME));
        wallpaperEntity.wallpaperId = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_WALLPAPER_ID));
        wallpaperEntity.iconUrl = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_ICON_URL));
        wallpaperEntity.link = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_LINK));
        wallpaperEntity.author = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_AUTHOR));
        wallpaperEntity.downloadUrl = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_DOWNLOAD_URL));
        wallpaperEntity.checkSum = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_CHECKSUM));
        wallpaperEntity.storePath = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_STORE_PATH));
        wallpaperEntity.providerName = cursor.getString(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_PROVIDER_NAME));
        wallpaperEntity.isSelected = cursor.getInt(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_SELECTED)) == 1;
        wallpaperEntity.lazyDownload = cursor.getInt(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_LAZY_DOWNLOAD)) == 1;
        wallpaperEntity.needAd = cursor.getInt(cursor.getColumnIndex(
                StyleContract.AdvanceWallpaper.COLUMN_NAME_NEED_AD)) == 1;

        return wallpaperEntity;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof AdvanceWallpaperEntity) {
            if (TextUtils.equals(((AdvanceWallpaperEntity) obj).name, name)
                    && TextUtils.equals(((AdvanceWallpaperEntity) obj).checkSum, checkSum)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = 0;
        result = 31 * result + name.hashCode();
        result = 31 * result + checkSum.hashCode();
        return result;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/DeviceInfo.java
================================================
package com.yalin.style.data.entity;

import com.yalin.style.data.BuildConfig;

/**
 * @author jinyalin
 * @since 2017/4/25.
 */

public class DeviceInfo {
    private int sdkVersion;
    private String androidId;
    private String manufacturer;
    private String brand;
    private String model;
    private String type;
    private String versionName;
    private int versionCode;
    private String channel;

    public DeviceInfo(int sdkVersion, String androidId, String manufacturer,
                      String brand, String model) {
        this.sdkVersion = sdkVersion;
        this.androidId = androidId;
        this.manufacturer = manufacturer;
        this.brand = brand;
        this.model = model;
        type = "Android";
        versionName = BuildConfig.VERSION_NAME;
        versionCode = BuildConfig.VERSION_CODE;
        channel = BuildConfig.CHANNEL;
    }

    public int getSdkVersion() {
        return sdkVersion;
    }

    public String getAndroidId() {
        return androidId;
    }

    public String getManufacturer() {
        return manufacturer;
    }

    public String getModel() {
        return model;
    }

    public String getType() {
        return type;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/GalleryWallpaperEntity.kt
================================================
package com.yalin.style.data.entity

import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.utils.getCacheFileForUri
import com.yalin.style.data.utils.getImagesFromTreeUri
import java.io.InputStream
import java.util.ArrayList

/**
 * @author jinyalin
 * @since 2017/5/24.
 */
class GalleryWallpaperEntity {
    var id: Long = 0
    var uri: String? = null
    var isTreeUri: Boolean = false
    var dateTime: Long = 0
    var location: String? = null
    var hasMetadata: Boolean = false

    companion object {
        private val TAG = "GalleryWallpaperEntity"

        fun readCursor(context: Context, cursor: Cursor?): ArrayList<GalleryWallpaperEntity> {
            val validWallpapers = ArrayList<GalleryWallpaperEntity>(5)
            while (cursor != null && cursor.moveToNext()) {
                val entity = readEntityFromCursor(cursor)
                var inputStream: InputStream? = null
                try {
                    // valid input stream
                    if (!entity.isTreeUri) {
                        inputStream = context.contentResolver.openInputStream(
                                Uri.parse(entity.uri))
                    }
                    validWallpapers.add(entity)
                } catch (e: Exception) {
                    LogUtil.D(TAG, "Cannot open inputStream for uri : "
                            + entity.uri)
                    val cacheFile = getCacheFileForUri(context, entity.uri!!)
                    if ((cacheFile != null && cacheFile.exists())) {
                        // has cache file
                        validWallpapers.add(entity)
                    }
                } finally {
                    inputStream?.close()
                }
            }
            return validWallpapers;
        }

        fun readEntityFromCursor(cursor: Cursor): GalleryWallpaperEntity {
            val entity = GalleryWallpaperEntity()

            entity.id = cursor.getLong(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper._ID))
            entity.uri = cursor.getString(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI))
            entity.isTreeUri = cursor.getInt(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper.COLUMN_NAME_IS_TREE_URI)) == 1
            entity.dateTime = cursor.getLong(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper.COLUMN_NAME_DATE_TIME))
            entity.location = cursor.getString(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper.COLUMN_NAME_LOCATION))
            entity.hasMetadata = cursor.getInt(cursor.getColumnIndex(
                    StyleContract.GalleryWallpaper.COLUMN_NAME_HAS_METADATA)) == 1
            return entity
        }
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/entity/HttpRequestBody.java
================================================
package com.yalin.style.data.entity;

import android.content.Context;

import com.yalin.style.data.utils.FacetIdUtil;

/**
 * @author jinyalin
 * @since 2017/4/25.
 */

public class HttpRequestBody {
    private DeviceInfo deviceInfo;
    private String facetId;

    public HttpRequestBody(Context context, DeviceInfo deviceInfo) {
        this.deviceInfo = deviceInfo;
        this.facetId = FacetIdUtil.getFacetId(context);
    }

    public DeviceInfo getDeviceInfo() {
        return deviceInfo;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/SourceEntity.kt
================================================
package com.yalin.style.data.entity


/**
 * @author jinyalin
 * *
 * @since 2017/5/23.
 */

class SourceEntity(var id: Int) {
    var title: String? = null
    var description: String? = null
    var iconId: Int = 0
    var isSelected: Boolean = false
    var isHasSetting: Boolean = false
    var color: Int = 0
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/WallpaperEntity.java
================================================
package com.yalin.style.data.entity;

import android.content.Context;
import android.database.Cursor;
import android.text.TextUtils;

import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract;
import com.yalin.style.data.repository.datasource.provider.StyleContract.Wallpaper;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */

public class WallpaperEntity {

    private static final String TAG = "WallpaperEntity";

    public int id;
    public String wallpaperId;
    public String imageUri;
    public String title;
    public String byline;
    public String attribution;

    public boolean canLike;
    public boolean liked;
    public boolean isDefault;

    public String checksum;

    public WallpaperEntity() {
    }

    public static List<WallpaperEntity> readCursor(Context context, Cursor cursor) {
        List<WallpaperEntity> validWallpapers = new ArrayList<>(5);
        while (cursor != null && cursor.moveToNext()) {
            WallpaperEntity wallpaperEntity = WallpaperEntity.readEntityFromCursor(cursor);
            try {
                // valid input stream
                InputStream is = context.getContentResolver().openInputStream(
                        StyleContract.Wallpaper.buildWallpaperUri(
                                wallpaperEntity.wallpaperId));
                validWallpapers.add(wallpaperEntity);
                if (is != null) {
                    is.close();
                }
            } catch (Exception e) {
                LogUtil.D(TAG, "File not found with wallpaper wallpaperId : "
                        + wallpaperEntity.wallpaperId);
            }
        }
        return validWallpapers;
    }

    public static WallpaperEntity readEntityFromCursor(Cursor cursor) {
        WallpaperEntity wallpaperEntity = new WallpaperEntity();

        wallpaperEntity.id = cursor.getInt(cursor.getColumnIndex(
                Wallpaper._ID));
        wallpaperEntity.title = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_TITLE));
        wallpaperEntity.wallpaperId = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_WALLPAPER_ID));
        wallpaperEntity.imageUri = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_IMAGE_URI));
        wallpaperEntity.byline = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_BYLINE));
        wallpaperEntity.attribution = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_ATTRIBUTION));
        wallpaperEntity.liked = cursor.getInt(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_LIKED)) == 1;
        wallpaperEntity.checksum = cursor.getString(cursor.getColumnIndex(
                Wallpaper.COLUMN_NAME_CHECKSUM));

        return wallpaperEntity;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof WallpaperEntity) {
            if (TextUtils.equals(((WallpaperEntity) obj).title, title)
                    && TextUtils.equals(((WallpaperEntity) obj).checksum, checksum)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int hashCode() {
        int result = 0;
        result = 31 * result + title.hashCode();
        result = 31 * result + checksum.hashCode();
        return result;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/mapper/AdvanceWallpaperEntityMapper.java
================================================
package com.yalin.style.data.entity.mapper;

import com.fernandocejas.arrow.checks.Preconditions;
import com.yalin.style.data.entity.AdvanceWallpaperEntity;
import com.yalin.style.domain.AdvanceWallpaper;
import com.yalin.style.domain.Wallpaper;

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

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * @author jinyalin
 * @since 2017/7/28.
 */
@Singleton
public class AdvanceWallpaperEntityMapper {
    @Inject
    public AdvanceWallpaperEntityMapper() {

    }

    public AdvanceWallpaper transform(AdvanceWallpaperEntity wallpaperEntity) {
        Preconditions.checkNotNull(wallpaperEntity, "Wallpaper can not be null.");
        AdvanceWallpaper wallpaper = new AdvanceWallpaper();
        wallpaper.id = wallpaperEntity.id;
        wallpaper.wallpaperId = wallpaperEntity.wallpaperId;
        wallpaper.link = wallpaperEntity.link;
        wallpaper.name = wallpaperEntity.name;
        wallpaper.author = wallpaperEntity.author;
        wallpaper.iconUrl = wallpaperEntity.iconUrl;
        wallpaper.downloadUrl = wallpaperEntity.downloadUrl;
        wallpaper.providerName = wallpaperEntity.providerName;
        wallpaper.storePath = wallpaperEntity.storePath;
        wallpaper.isDefault = wallpaperEntity.isDefault;
        wallpaper.isSelected = wallpaperEntity.isSelected;
        wallpaper.lazyDownload = wallpaperEntity.lazyDownload;
        wallpaper.needAd = wallpaperEntity.needAd;

        return wallpaper;
    }

    public List<AdvanceWallpaper> transformList(List<AdvanceWallpaperEntity> wallpaperEntities) {
        Preconditions.checkNotNull(wallpaperEntities, "SourceEntity can not be null.");
        List<AdvanceWallpaper> sources = new ArrayList<>();
        for (AdvanceWallpaperEntity entity : wallpaperEntities) {
            sources.add(transform(entity));
        }
        return sources;
    }

    public Wallpaper mapToWallpaper(AdvanceWallpaperEntity wallpaperEntity) {
        Preconditions.checkNotNull(wallpaperEntity, "Wallpaper can not be null.");
        Wallpaper wallpaper = new Wallpaper();
        wallpaper.wallpaperId = wallpaperEntity.wallpaperId;
        wallpaper.byline = wallpaperEntity.author;
        wallpaper.title = wallpaperEntity.name;
        wallpaper.attribution = wallpaperEntity.link;
        wallpaper.canLike = false;
        return wallpaper;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/entity/mapper/WallpaperEntityMapper.java
================================================
package com.yalin.style.data.entity.mapper;

import com.fernandocejas.arrow.checks.Preconditions;
import com.yalin.style.data.entity.GalleryWallpaperEntity;
import com.yalin.style.data.entity.SourceEntity;
import com.yalin.style.data.entity.WallpaperEntity;
import com.yalin.style.domain.GalleryWallpaper;
import com.yalin.style.domain.Source;
import com.yalin.style.domain.Wallpaper;

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

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */
@Singleton
public class WallpaperEntityMapper {

    @Inject
    public WallpaperEntityMapper() {
    }

    public Wallpaper transform(WallpaperEntity wallpaperEntity) {
        Preconditions.checkNotNull(wallpaperEntity, "Wallpaper can not be null.");
        Wallpaper wallpaper = new Wallpaper();
        wallpaper.title = wallpaperEntity.title;
        wallpaper.attribution = wallpaperEntity.attribution;
        wallpaper.byline = wallpaperEntity.byline;
        wallpaper.imageUri = wallpaperEntity.imageUri;
        wallpaper.wallpaperId = wallpaperEntity.wallpaperId;
        wallpaper.liked = wallpaperEntity.liked;
        wallpaper.isDefault = wallpaperEntity.isDefault;
        wallpaper.canLike = wallpaperEntity.canLike;
        return wallpaper;
    }

    public List<Source> transformSources(List<SourceEntity> sourceEntities) {
        Preconditions.checkNotNull(sourceEntities, "SourceEntity can not be null.");
        List<Source> sources = new ArrayList<>();
        for (SourceEntity entity : sourceEntities) {
            sources.add(transformSource(entity));
        }
        return sources;
    }

    public Source transformSource(SourceEntity sourceEntity) {
        Preconditions.checkNotNull(sourceEntity, "SourceEntity can not be null.");
        Source source = new Source();
        source.id = sourceEntity.getId();
        source.title = sourceEntity.getTitle();
        source.description = sourceEntity.getDescription();
        source.iconId = sourceEntity.getIconId();
        source.selected = sourceEntity.isSelected();
        source.hasSetting = sourceEntity.isHasSetting();
        source.color = sourceEntity.getColor();
        return source;
    }

    public List<GalleryWallpaper> transformGalleryWallpaper(
            List<GalleryWallpaperEntity> galleryWallpaperEntities) {
        Preconditions.checkNotNull(galleryWallpaperEntities,
                "GalleryWallpaperEntity can not be null.");
        List<GalleryWallpaper> entities = new ArrayList<>();
        for (GalleryWallpaperEntity entity : galleryWallpaperEntities) {
            entities.add(transformGalleryWallpaper(entity));
        }
        return entities;
    }

    public GalleryWallpaper transformGalleryWallpaper(
            GalleryWallpaperEntity galleryWallpaperEntity) {
        Preconditions.checkNotNull(galleryWallpaperEntity,
                "GalleryWallpaperEntity can not be null.");
        GalleryWallpaper galleryWallpaper = new GalleryWallpaper();
        galleryWallpaper.id = galleryWallpaperEntity.getId();
        galleryWallpaper.isTreeUri = galleryWallpaperEntity.isTreeUri();
        galleryWallpaper.uri = galleryWallpaperEntity.getUri();
        galleryWallpaper.dateTime = galleryWallpaperEntity.getDateTime();
        galleryWallpaper.location = galleryWallpaperEntity.getLocation();
        galleryWallpaper.hasMetadata = galleryWallpaperEntity.getHasMetadata();
        return galleryWallpaper;
    }

}


================================================
FILE: data/src/main/java/com/yalin/style/data/exception/LikeException.java
================================================
package com.yalin.style.data.exception;

/**
 * @author jinyalin
 * @since 2017/4/29.
 */

public class LikeException extends Exception {
    public LikeException() {
        super();
    }

    public LikeException(final Throwable cause) {
        super(cause);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/exception/NetworkConnectionException.java
================================================
package com.yalin.style.data.exception;

/**
 * @author jinyalin
 * @since 2017/4/29.
 */

public class NetworkConnectionException extends Exception {
    public NetworkConnectionException() {
        super();
    }

    public NetworkConnectionException(final Throwable cause) {
        super(cause);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/exception/NoContentException.java
================================================
package com.yalin.style.data.exception;

/**
 * @author jinyalin
 * @since 2017/7/31.
 */

public class NoContentException extends Exception {
}


================================================
FILE: data/src/main/java/com/yalin/style/data/exception/RemoteServerException.java
================================================
package com.yalin.style.data.exception;

/**
 * @author jinyalin
 * @since 2017/8/4.
 */

public class RemoteServerException extends Exception {
}


================================================
FILE: data/src/main/java/com/yalin/style/data/exception/ReswitchException.java
================================================
package com.yalin.style.data.exception;

/**
 * @author jinyalin
 * @since 2017/4/29.
 */

public class ReswitchException extends Exception {
    public ReswitchException() {
        super();
    }

    public ReswitchException(final Throwable cause) {
        super(cause);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/executor/JobExecutor.java
================================================
package com.yalin.style.data.executor;

import android.support.annotation.NonNull;

import com.yalin.style.domain.executor.ThreadExecutor;

import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */
@Singleton
public class JobExecutor implements ThreadExecutor {
    protected final ThreadPoolExecutor threadPoolExecutor;

    @Inject
    JobExecutor() {
        threadPoolExecutor = new ThreadPoolExecutor(3, 5, 10, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(), new JobThreadFactory());
    }

    @Override
    public void execute(@NonNull Runnable command) {
        threadPoolExecutor.execute(command);
    }

    private static class JobThreadFactory implements ThreadFactory {
        private int counter = 0;

        @Override
        public Thread newThread(@NonNull Runnable runnable) {
            return new Thread(runnable, "android_" + counter);
        }
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/executor/SerialJobExecutor.java
================================================
package com.yalin.style.data.executor;

import android.support.annotation.NonNull;


import com.yalin.style.domain.executor.SerialThreadExecutor;

import java.util.ArrayDeque;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */
@Singleton
public class SerialJobExecutor extends JobExecutor implements SerialThreadExecutor {
    final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();
    Runnable mActive;

    @Inject
    SerialJobExecutor() {
        super();
    }

    @Override
    public synchronized void execute(@NonNull Runnable command) {
        mTasks.offer(() -> {
            try {
                command.run();
            } finally {
                scheduleNext();
            }
        });
        if (mActive == null) {
            scheduleNext();
        }
    }

    protected synchronized void scheduleNext() {
        if ((mActive = mTasks.poll()) != null) {
            threadPoolExecutor.execute(mActive);
        }
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/extensions/DelegateExt.kt
================================================
package com.yalin.style.data.extensions

import android.content.Context
import android.content.SharedPreferences
import java.lang.IllegalArgumentException
import kotlin.reflect.KProperty

/**
 * @author jinyalin
 * @since 2017/5/22.
 */
object DelegateExt {
    fun <T> preferences(context: Context, name: String, default: T) =
            Preferences(context, name, default)
}

class Preferences<T>(val context: Context, val name: String, val default: T) {
    companion object {
        val PREFERENCE_NAME = "style_preference"
    }

    val prefs: SharedPreferences by lazy {
        context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE)
    }

    operator fun getValue(thisRef: Any?, property: KProperty<*>): T = findPreference(name, default)

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) =
            putPreference(name, value)

    @Suppress("UNCHECKED_CAST")
    private fun findPreference(name: String, default: T): T = with(prefs) {
        val res: Any = when (default) {
            is Long -> getLong(name, default)
            is String -> getString(name, default)
            is Int -> getInt(name, default)
            is Boolean -> getBoolean(name, default)
            is Float -> getFloat(name, default)
            else -> throw IllegalArgumentException("This type can not be saved into Preferences")
        }

        res as T
    }

    private fun putPreference(name: String, value: T) = with(prefs.edit()) {
        when (value) {
            is Long -> putLong(name, value)
            is String -> putString(name, value)
            is Int -> putInt(name, value)
            is Boolean -> putBoolean(name, value)
            is Float -> putFloat(name, value)
            else -> throw IllegalArgumentException("This type can't be saved into Preferences")
        }.apply()
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/lock/LikeWallpaperLock.java
================================================
package com.yalin.style.data.lock;

import com.yalin.style.domain.executor.ThreadExecutor;
import com.yalin.style.domain.interactor.DefaultObserver;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;

/**
 * YaLin
 * On 2017/4/30.
 */
@Singleton
public class LikeWallpaperLock extends ResourceLock {

    @Inject
    public LikeWallpaperLock(ThreadExecutor threadExecutor) {
        super(threadExecutor);
    }

    @Override
    protected Observable<Void> appendDelay(Observable<Void> observable) {
        return observable.delaySubscription(500, TimeUnit.MILLISECONDS);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/lock/OpenInputStreamLock.java
================================================
package com.yalin.style.data.lock;

import com.yalin.style.domain.executor.ThreadExecutor;

import io.reactivex.Observable;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * YaLin
 * On 2017/4/30.
 */
@Singleton
public class OpenInputStreamLock extends ResourceLock {

    @Inject
    public OpenInputStreamLock(ThreadExecutor threadExecutor) {
        super(threadExecutor);
    }

    @Override
    protected Observable<Void> appendDelay(Observable<Void> observable) {
        return observable.delaySubscription(1, TimeUnit.SECONDS);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/lock/ResourceLock.java
================================================
package com.yalin.style.data.lock;

import com.yalin.style.domain.executor.ThreadExecutor;
import com.yalin.style.domain.interactor.DefaultObserver;

import java.util.concurrent.atomic.AtomicBoolean;

import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;

/**
 * YaLin
 * On 2017/4/30.
 */

public abstract class ResourceLock {
    private AtomicBoolean lock = new AtomicBoolean(false);

    private final ThreadExecutor threadExecutor;

    private DefaultObserver<Void> releaseObserver;

    public ResourceLock(ThreadExecutor threadExecutor) {
        this.threadExecutor = threadExecutor;
    }

    public synchronized boolean obtain() {
        if (lock.get()) {
            return false;
        } else {
            lock.set(true);
            return true;
        }
    }

    public synchronized void release() {
        if (releaseObserver != null) {
            releaseObserver.dispose();
        }
        releaseObserver = new DefaultObserver<>();
        Observable<Void> observable = Observable.create(e -> {
            lock.set(false);
            e.onComplete();
        });
        observable = appendDelay(observable);
        observable.subscribeOn(Schedulers.from(threadExecutor))
                .subscribeWith(releaseObserver);
    }

    protected Observable<Void> appendDelay(Observable<Void> observable) {
        return observable;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/lock/SelectSourceLock.java
================================================
package com.yalin.style.data.lock;

import com.yalin.style.domain.executor.ThreadExecutor;

import java.util.concurrent.TimeUnit;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.reactivex.Observable;

/**
 * YaLin
 * On 2017/4/30.
 */
@Singleton
public class SelectSourceLock extends ResourceLock {

    @Inject
    public SelectSourceLock(ThreadExecutor threadExecutor) {
        super(threadExecutor);
    }

    @Override
    protected Observable<Void> appendDelay(Observable<Void> observable) {
        return observable.delaySubscription(1, TimeUnit.SECONDS);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/log/LogUtil.java
================================================
package com.yalin.style.data.log;

import android.os.Environment;
import android.os.Process;
import android.util.Log;

import com.yalin.style.data.BuildConfig;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Calendar;
import java.util.Locale;

/**
 * YaLin 2016/11/23.
 */

public class LogUtil {

    private static final String FILE_NAME = "Style/stat_log.txt";

    public static final boolean LOG_ENABLE = BuildConfig.DEMO_MODE || BuildConfig.LOG_ENABLE;

    public static synchronized boolean isExternalLogEnabled() {
        //noinspection SimplifiableIfStatement
        if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
            return false;
        }
        return LOG_ENABLE && BuildConfig.ENABLE_EXTERNAL_LOG;
    }

    public static void F(String tag, String msg, Throwable throwable) {
        if (!LOG_ENABLE) {
            return;
        }
        String stackTraces = Log.getStackTraceString(throwable);
        if (msg == null) {
            msg = "";
        }
        F(tag, msg + " :\n " + stackTraces);
    }

    public static void F(String tag, String msg) {
        if (!LOG_ENABLE) {
            return;
        }
        String procInfo = getProcessInfo();

        Log.e(tag, procInfo + msg);

        if (!isExternalLogEnabled()) {
            return;
        }
        tag = tag + ":debug";
        writeLog(tag, procInfo + msg);
    }

    public static void E(String tag, String msg, Throwable throwable) {
        if (!LOG_ENABLE) {
            return;
        }
        String stackTraces = Log.getStackTraceString(throwable);
        if (msg == null) {
            msg = "";
        }
        E(tag, msg + " :\n " + stackTraces);
    }

    public static void E(String tag, String msg) {
        if (!LOG_ENABLE) {
            return;
        }
        String procInfo = getProcessInfo();

        Log.e(tag, procInfo + msg);
    }

    public static void D(String tag, String msg) {
        if (!LOG_ENABLE) {
            return;
        }
        String procInfo = getProcessInfo();

        Log.d(tag, procInfo + msg);
    }

    private static String getProcessInfo() {
        return "Process wallpaperId: " + Process.myPid()
                + " Thread wallpaperId: " + Thread.currentThread().getId() + " ";
    }

    private static synchronized void writeLog(String tag, String msg) {
        internalWriteLog(FILE_NAME, tag, msg);
    }

    private static synchronized void internalWriteLog(String filename, String tag, String msg) {
        try {
            if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
                return;
            }

            File file = new File(Environment.getExternalStorageDirectory(), filename);

            //noinspection ResultOfMethodCallIgnored
            file.getParentFile().mkdirs();

            BufferedWriter bw = new BufferedWriter(
                    new OutputStreamWriter(new FileOutputStream(file, true)));

            String time = getCurrentTime();
            bw.write(time + " " + tag + " \t" + msg + "\r\n");

            bw.close();
        } catch (Exception e) {
            // ignore
        }
    }

    private static String getCurrentTime() {
        Calendar c = Calendar.getInstance();
        return String.format(Locale.getDefault(), "%d-%02d-%02d %02d:%02d:%02d.%03d",
                c.get(Calendar.YEAR), c.get(Calendar.MONTH) + 1, c.get(Calendar.DAY_OF_MONTH),
                c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND),
                c.get(Calendar.MILLISECOND));
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/observable/SourcesObservableImpl.kt
================================================
package com.yalin.style.data.observable

import android.content.Context
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import com.yalin.style.data.cache.SourcesCache
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.domain.interactor.DefaultObserver
import com.yalin.style.domain.observable.SourcesObservable
import java.util.HashSet
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
@Singleton
class SourcesObservableImpl @Inject
constructor(val context: Context,
            val sourcesCache: SourcesCache) : SourcesObservable {

    companion object {
        val TAG = "WallpaperObservableImpl"
    }

    private val mObserverSet = HashSet<DefaultObserver<Void>>()
    private val mContentObserver = object : ContentObserver(Handler()) {
        override fun onChange(selfChange: Boolean, uri: Uri) {
            LogUtil.D(TAG, "Source changed notify observer to reload.")
            notifyObserver()
        }
    }

    private var observerRegistered = false

    override fun registerObserver(observer: DefaultObserver<Void>) {
        synchronized(mObserverSet) {
            mObserverSet.add(observer)
            if (!observerRegistered) {
                context.contentResolver
                        .registerContentObserver(StyleContract.Source.CONTENT_URI,
                                true, mContentObserver)
                observerRegistered = true
            }
        }
    }

    override fun unregisterObserver(observer: DefaultObserver<Void>) {
        synchronized(mObserverSet) {
            mObserverSet.remove(observer)
            if (mObserverSet.isEmpty()) {
                context.contentResolver.unregisterContentObserver(mContentObserver)
                observerRegistered = false
            }
        }
    }


    private fun notifyObserver() {
        for (observer in mObserverSet) {
            observer.onNext(null)
            observer.onComplete()
        }
    }

}

================================================
FILE: data/src/main/java/com/yalin/style/data/observable/WallpaperObservableImpl.kt
================================================
package com.yalin.style.data.observable

import android.content.Context
import android.database.ContentObserver
import android.net.Uri
import android.os.Handler
import android.text.TextUtils
import com.yalin.style.data.cache.SourcesCache
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.AdvanceWallpaperDataStoreFactory
import com.yalin.style.data.repository.datasource.StyleWallpaperDataStoreFactory
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.domain.interactor.DefaultObserver
import com.yalin.style.domain.observable.SourcesObservable
import com.yalin.style.domain.observable.WallpaperObservable
import com.yalin.style.domain.repository.SourcesRepository.SOURCE_ID_CUSTOM
import com.yalin.style.domain.repository.SourcesRepository.SOURCE_ID_STYLE
import com.yalin.style.domain.repository.SourcesRepository.SOURCE_ID_ADVANCE
import java.util.HashSet
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
@Singleton
class WallpaperObservableImpl @Inject
constructor(val context: Context,
            val sourcesCache: SourcesCache,
            val styleWallpaperDataStoreFactory: StyleWallpaperDataStoreFactory,
            val advanceWallpaperDataStoreFactory: AdvanceWallpaperDataStoreFactory,
            val sourcesObservable: SourcesObservable) :
        WallpaperObservable {

    companion object {
        val TAG = "WallpaperObservableImpl"
    }

    private val mObserverSet = HashSet<DefaultObserver<Void>>()
    private val mWallpaperObserver = object : ContentObserver(Handler()) {
        override fun onChange(selfChange: Boolean, uri: Uri) {
            LogUtil.D(TAG, "Wallpaper data changed notify observer to reload.")
            if (sourcesCache.getUsedSourceId() == SOURCE_ID_CUSTOM
                    && TextUtils.equals(uri.toString(),
                    StyleContract.GalleryWallpaper.CONTENT_URI.toString())) {
                notifyObserver()
            } else if (sourcesCache.getUsedSourceId() == SOURCE_ID_STYLE
                    && TextUtils.equals(uri.toString(),
                    StyleContract.Wallpaper.CONTENT_URI.toString())) {
                notifyObserver()
            } else if (sourcesCache.getUsedSourceId() == SOURCE_ID_ADVANCE
                    && TextUtils.equals(uri.toString(),
                    StyleContract.AdvanceWallpaper.CONTENT_URI.toString())) {
                notifyObserver()
            }
            styleWallpaperDataStoreFactory.onDataRefresh()
            advanceWallpaperDataStoreFactory.onDataRefresh()
        }
    }

    private val sourceObserver = object : DefaultObserver<Void>() {
        override fun onComplete() {
            notifyObserver()
        }
    }

    init {
        context.contentResolver
                .registerContentObserver(StyleContract.Wallpaper.CONTENT_URI,
                        true, mWallpaperObserver)
        context.contentResolver
                .registerContentObserver(StyleContract.GalleryWallpaper.CONTENT_URI,
                        true, mWallpaperObserver)
        context.contentResolver
                .registerContentObserver(StyleContract.AdvanceWallpaper.CONTENT_URI,
                        true, mWallpaperObserver)

        sourcesObservable.registerObserver(sourceObserver)
    }

    override fun registerObserver(observer: DefaultObserver<Void>) {
        synchronized(mObserverSet) {
            mObserverSet.add(observer)
        }
    }

    override fun unregisterObserver(observer: DefaultObserver<Void>) {
        synchronized(mObserverSet) {
            mObserverSet.remove(observer)
        }
    }


    private fun notifyObserver() {
        for (observer in mObserverSet) {
            observer.onNext(null)
            observer.onComplete()
        }
    }

}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/AdvanceWallpaperDataRepository.kt
================================================
package com.yalin.style.data.repository

import android.content.Context
import com.yalin.style.data.entity.mapper.AdvanceWallpaperEntityMapper
import com.yalin.style.data.extensions.DelegateExt
import com.yalin.style.data.repository.datasource.AdvanceWallpaperDataStoreFactory
import com.yalin.style.domain.AdvanceWallpaper
import com.yalin.style.domain.GalleryWallpaper
import com.yalin.style.domain.Wallpaper
import com.yalin.style.domain.repository.WallpaperRepository
import io.reactivex.Observable
import java.io.InputStream
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/7/27.
 */
@Singleton
class AdvanceWallpaperDataRepository
@Inject constructor(val context: Context,
                    val factory: AdvanceWallpaperDataStoreFactory,
                    val wallpaperMapper: AdvanceWallpaperEntityMapper,
                    val styleRepository: StyleWallpaperDataRepository)
    : WallpaperRepository {
    var needRollback: Boolean by DelegateExt.preferences(context, "is_need_rollback",
            false)

    override fun getWallpaper(): Observable<Wallpaper> {
        return Observable.create<Wallpaper> { emitter ->
            emitter.onNext(wallpaperMapper.mapToWallpaper(factory.create().getWallpaperEntity()))
            emitter.onComplete()
        }
    }

    override fun switchWallpaper(): Observable<Wallpaper> {
        return Observable.create<Wallpaper> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun openInputStream(wallpaperId: String?): Observable<InputStream> {
        var id: String? = null
        styleRepository.wallpaper.subscribe(
                { wallpaper -> id = wallpaper.wallpaperId })

        return styleRepository.openInputStream(id)
    }

    override fun getWallpaperCount(): Observable<Int> {
        return Observable.create<Int> { emitter ->
            emitter.onNext(1)
            emitter.onComplete()
        }
    }

    override fun likeWallpaper(wallpaperId: String?): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun addGalleryWallpaperUris(uris: MutableList<GalleryWallpaper>?): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun removeGalleryWallpaperUris(uris: MutableList<GalleryWallpaper>?): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun getGalleryWallpapers(): Observable<List<GalleryWallpaper>> {
        return Observable.create<List<GalleryWallpaper>> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun getAdvanceWallpapers(): Observable<List<AdvanceWallpaper>> {
        return factory.create().getAdvanceWallpapers().map(wallpaperMapper::transformList)
    }

    override fun loadAdvanceWallpapers(): Observable<List<AdvanceWallpaper>> {
        return factory.createRemoteDataStore().getAdvanceWallpapers()
                .map(wallpaperMapper::transformList)
    }

    override fun downloadAdvanceWallpaper(wallpaperId: String): Observable<Long> {
        return factory.createRemoteDataStore().downloadWallpaper(wallpaperId)
    }

    override fun selectAdvanceWallpaper(wallpaperId: String, tempSelect: Boolean):
            Observable<Boolean> {
        return factory.create().selectWallpaper(wallpaperId, tempSelect)
    }

    override fun getAdvanceWallpaper(): AdvanceWallpaper {
        return wallpaperMapper.transform(factory.create().getWallpaperEntity())
    }

    override fun readAdvanceAd(wallpaperId: String): Observable<Boolean> {
        return factory.create().readAd(wallpaperId)
    }

    override fun foreNow(wallpaperUri: String?): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun setGalleryUpdateInterval(intervalMin: Int): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    override fun getGalleryUpdateInterval(): Observable<Int> {
        return Observable.create<Int> { emitter ->
            emitter.onError(IllegalStateException(
                    "StyleWallpaperRepository have not gallery wallpapers."))
        }
    }

    fun markRollback() {
        needRollback = true
    }

    fun maybeRollback() {
        if (needRollback) {
            factory.create().rollback()
        }
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/GalleryWallpaperDataRepository.kt
================================================
package com.yalin.style.data.repository

import com.yalin.style.data.entity.mapper.WallpaperEntityMapper
import com.yalin.style.data.repository.datasource.GalleryWallpaperDataStoreFactory
import com.yalin.style.domain.AdvanceWallpaper
import com.yalin.style.domain.GalleryWallpaper
import com.yalin.style.domain.Wallpaper
import com.yalin.style.domain.repository.WallpaperRepository
import io.reactivex.Observable
import java.io.InputStream
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/24.
 */
@Singleton
class GalleryWallpaperDataRepository @Inject
constructor(val galleryWallpaperDataStoreFactory: GalleryWallpaperDataStoreFactory,
            val wallpaperEntityMapper: WallpaperEntityMapper) :
        WallpaperRepository {

    override fun getWallpaper(): Observable<Wallpaper> =
            galleryWallpaperDataStoreFactory.create()
                    .wallPaperEntity.map(wallpaperEntityMapper::transform)

    override fun switchWallpaper(): Observable<Wallpaper> =
            galleryWallpaperDataStoreFactory.create()
                    .switchWallPaperEntity().map(wallpaperEntityMapper::transform)

    override fun openInputStream(wallpaperId: String?): Observable<InputStream> =
            galleryWallpaperDataStoreFactory.create()
                    .openInputStream(wallpaperId)

    override fun getWallpaperCount(): Observable<Int> =
            galleryWallpaperDataStoreFactory.create()
                    .wallpaperCount

    override fun likeWallpaper(wallpaperId: String): Observable<Boolean> =
            galleryWallpaperDataStoreFactory.create()
                    .likeWallpaper(wallpaperId)

    override fun addGalleryWallpaperUris(uris: List<GalleryWallpaper>): Observable<Boolean> =
            galleryWallpaperDataStoreFactory.create()
                    .addGalleryWallpaperUris(uris)

    override fun removeGalleryWallpaperUris(uris: List<GalleryWallpaper>): Observable<Boolean> =
            galleryWallpaperDataStoreFactory.create()
                    .removeGalleryWallpaperUris(uris)

    override fun getGalleryWallpapers(): Observable<List<GalleryWallpaper>> =
            galleryWallpaperDataStoreFactory.create()
                    .getGalleryWallpaperUris().map(wallpaperEntityMapper::transformGalleryWallpaper)

    override fun getAdvanceWallpapers(): Observable<List<AdvanceWallpaper>> {
        return Observable.create<List<AdvanceWallpaper>> { emitter ->
            emitter.onError(IllegalStateException(
                    "GalleryWallpaperDataRepository have not advance wallpapers."))
        }
    }

    override fun loadAdvanceWallpapers(): Observable<List<AdvanceWallpaper>> {
        return Observable.create<List<AdvanceWallpaper>> { emitter ->
            emitter.onError(IllegalStateException(
                    "GalleryWallpaperDataRepository cannot load advance wallpapers."))
        }
    }

    override fun downloadAdvanceWallpaper(wallpaperId: String): Observable<Long> {
        return Observable.create<Long> { emitter ->
            emitter.onError(IllegalStateException(
                    "GalleryWallpaperDataRepository cannot download advance wallpapers."))
        }
    }

    override fun selectAdvanceWallpaper(wallpaperId: String, tempSelect: Boolean):
            Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            emitter.onError(IllegalStateException(
                    "GalleryWallpaperDataRepository cannot select advance wallpapers."))
        }
    }

    override fun getAdvanceWallpaper(): AdvanceWallpaper {
        throw IllegalStateException(
                "GalleryWallpaperDataRepository cannot get advance wallpapers.")
    }

    override fun readAdvanceAd(wallpaperId: String?): Observable<Boolean> {
        throw IllegalStateException(
                "GalleryWallpaperDataRepository cannot read advance ad.")
    }

    override fun foreNow(wallpaperUri: String): Observable<Boolean> =
            galleryWallpaperDataStoreFactory.create().forceNow(wallpaperUri)

    override fun setGalleryUpdateInterval(intervalMin: Int): Observable<Boolean> =
            galleryWallpaperDataStoreFactory.create().setUpdateIntervalMin(intervalMin)

    override fun getGalleryUpdateInterval(): Observable<Int> =
            galleryWallpaperDataStoreFactory.create().getUpdateIntervalMin()
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/SourcesDataRepository.kt
================================================
package com.yalin.style.data.repository

import android.content.Context
import com.yalin.style.data.entity.mapper.WallpaperEntityMapper
import com.yalin.style.data.repository.datasource.SourcesDataStoreFactory
import com.yalin.style.domain.Source
import com.yalin.style.domain.repository.SourcesRepository
import com.yalin.style.domain.repository.SourcesRepository.SOURCE_ID_ADVANCE
import com.yalin.style.domain.repository.SourcesRepository.SOURCE_ID_CUSTOM
import com.yalin.style.domain.repository.WallpaperRepository
import io.reactivex.Observable
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
@Singleton
class SourcesDataRepository @Inject
constructor(val context: Context,
            val sourcesDataStoreFactory: SourcesDataStoreFactory,
            val wallpaperEntityMapper: WallpaperEntityMapper,
            var styleWallpaperDataRepository: StyleWallpaperDataRepository,
            var customWallpaperDataRepository: GalleryWallpaperDataRepository,
            var advanceWallpaperDataRepository: AdvanceWallpaperDataRepository) : SourcesRepository {
    override fun getSources(): Observable<List<Source>> {
        val sourcesDataStore = sourcesDataStoreFactory.create()
        return sourcesDataStore.getSources().map(wallpaperEntityMapper::transformSources)
    }

    override fun selectSource(sourceId: Int, tempSelect: Boolean): Observable<Boolean> {
        val sourcesDataStore = sourcesDataStoreFactory.create()
        return sourcesDataStore.selectSource(sourceId, tempSelect)
    }

    override fun getWallpaperRepository(): WallpaperRepository {
        val sourcesDataStore = sourcesDataStoreFactory.create()

        when (sourcesDataStore.getUsedSourceId()) {
            SOURCE_ID_CUSTOM -> return customWallpaperDataRepository
            SOURCE_ID_ADVANCE -> return advanceWallpaperDataRepository
            else -> return styleWallpaperDataRepository
        }
    }

    override fun getSelectedSource(): Int {
        val sourcesDataStore = sourcesDataStoreFactory.create()
        return sourcesDataStore.getUsedSourceId()
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/StyleWallpaperDataRepository.java
================================================
package com.yalin.style.data.repository;

import android.content.Context;
import android.text.TextUtils;

import com.fernandocejas.arrow.checks.Preconditions;
import com.yalin.style.data.entity.mapper.WallpaperEntityMapper;
import com.yalin.style.data.repository.datasource.WallpaperDataStore;
import com.yalin.style.data.repository.datasource.StyleWallpaperDataStoreFactory;
import com.yalin.style.data.repository.datasource.sync.SyncHelper;
import com.yalin.style.data.repository.datasource.sync.account.Account;
import com.yalin.style.domain.AdvanceWallpaper;
import com.yalin.style.domain.GalleryWallpaper;
import com.yalin.style.domain.Wallpaper;
import com.yalin.style.domain.repository.WallpaperRepository;


import java.io.InputStream;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Singleton;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */
@Singleton
public class StyleWallpaperDataRepository implements WallpaperRepository {

    private final Context context;
    private final StyleWallpaperDataStoreFactory styleWallpaperDataStoreFactory;
    private final WallpaperEntityMapper wallpaperEntityMapper;

    @Inject
    StyleWallpaperDataRepository(Context context,
                                 StyleWallpaperDataStoreFactory styleWallpaperDataStoreFactory,
                                 WallpaperEntityMapper wallpaperEntityMapper) {
        this.context = context;
        this.styleWallpaperDataStoreFactory = styleWallpaperDataStoreFactory;
        this.wallpaperEntityMapper = wallpaperEntityMapper;

        Account.createSyncAccount(context);
        SyncHelper.updateSyncInterval(context);
    }

    @Override
    public Observable<Wallpaper> getWallpaper() {
        final WallpaperDataStore dataStore = styleWallpaperDataStoreFactory.create();
        return dataStore.getWallPaperEntity().map(wallpaperEntityMapper::transform);
    }

    @Override
    public Observable<Wallpaper> switchWallpaper() {
        final WallpaperDataStore dataStore = styleWallpaperDataStoreFactory.create();
        return dataStore.switchWallPaperEntity().map(wallpaperEntityMapper::transform);
    }

    @Override
    public Observable<InputStream> openInputStream(String wallpaperId) {
        Preconditions.checkArgument(!TextUtils.isEmpty(wallpaperId), "WallpaperId cannot be null");
        final WallpaperDataStore dataStore = styleWallpaperDataStoreFactory.createDbDataStore();
        return dataStore.openInputStream(wallpaperId);
    }

    @Override
    public Observable<Integer> getWallpaperCount() {
        final WallpaperDataStore dataStore = styleWallpaperDataStoreFactory.create();
        return dataStore.getWallpaperCount();
    }

    @Override
    public Observable<Boolean> likeWallpaper(String wallpaperId) {
        Preconditions.checkArgument(!TextUtils.isEmpty(wallpaperId), "WallpaperId cannot be null");
        final WallpaperDataStore dataStore = styleWallpaperDataStoreFactory.createDbDataStore();
        return dataStore.likeWallpaper(wallpaperId);
    }

    @Override
    public Observable<Boolean> addGalleryWallpaperUris(List<GalleryWallpaper> uris) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository can not add gallery wallpaper."))
        );
    }

    @Override
    public Observable<Boolean> removeGalleryWallpaperUris(List<GalleryWallpaper> uris) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository can not remove gallery wallpaper."))
        );
    }

    @Override
    public Observable<List<GalleryWallpaper>> getGalleryWallpapers() {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository have not gallery wallpapers."))
        );
    }

    @Override
    public Observable<List<AdvanceWallpaper>> getAdvanceWallpapers() {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository cannot get advance wallpapers."))
        );
    }

    @Override
    public Observable<List<AdvanceWallpaper>> loadAdvanceWallpapers() {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository cannot load advance wallpapers."))
        );
    }

    @Override
    public Observable<Long> downloadAdvanceWallpaper(String wallpaperId) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository cannot download advance wallpapers."))
        );
    }

    @Override
    public Observable<Boolean> selectAdvanceWallpaper(String wallpaperId, boolean tempSelect) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository cannot select advance wallpapers."))
        );
    }

    public AdvanceWallpaper getAdvanceWallpaper() {
        throw new IllegalStateException(
                "StyleWallpaperRepository cannot get advance wallpapers.");
    }

    @Override
    public Observable<Boolean> readAdvanceAd(String wallpaperId) {
        throw new IllegalStateException(
                "StyleWallpaperRepository cannot read advance ad.");
    }

    @Override
    public Observable<Boolean> foreNow(String wallpaperUri) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository can not foreNow gallery wallpaper."))
        );
    }

    @Override
    public Observable<Boolean> setGalleryUpdateInterval(int intervalMin) {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository can not setGalleryUpdateInterval gallery wallpaper."))
        );
    }

    @Override
    public Observable<Integer> getGalleryUpdateInterval() {
        return Observable.create(emitter ->
                emitter.onError(new IllegalStateException(
                        "StyleWallpaperRepository can not getGalleryUpdateInterval gallery wallpaper."))
        );
    }

}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStore.kt
================================================
package com.yalin.style.data.repository.datasource

import com.yalin.style.data.entity.AdvanceWallpaperEntity
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/7/28.
 */
interface AdvanceWallpaperDataStore {

    fun getWallpaperEntity(): AdvanceWallpaperEntity

    fun getAdvanceWallpapers(): Observable<List<AdvanceWallpaperEntity>>

    fun selectWallpaper(wallpaperId: String, tempSelect: Boolean): Observable<Boolean>

    fun downloadWallpaper(wallpaperId: String): Observable<Long>

    fun readAd(wallpaperId: String): Observable<Boolean>

    fun rollback()
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStoreFactory.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.Context
import com.yalin.style.data.cache.AdvanceWallpaperCache
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/7/28.
 */
@Singleton
class AdvanceWallpaperDataStoreFactory @Inject
constructor(val context: Context,
            val advanceWallpaperCache: AdvanceWallpaperCache) {

    fun create(): AdvanceWallpaperDataStore {
        return AdvanceWallpaperDataStoreImpl(context, advanceWallpaperCache)
    }

    fun createRemoteDataStore(): AdvanceWallpaperDataStore {
        return RemoteAdvanceWallpaperDataStore(context,
                AdvanceWallpaperDataStoreImpl(context, advanceWallpaperCache))
    }

    fun onDataRefresh() {
        advanceWallpaperCache.evictAll()
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStoreImpl.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import com.yalin.style.data.cache.AdvanceWallpaperCache
import com.yalin.style.data.entity.AdvanceWallpaperEntity
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.utils.notifyChange
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/7/28.
 */
class AdvanceWallpaperDataStoreImpl(val context: Context,
                                    val advanceWallpaperCache: AdvanceWallpaperCache)
    : AdvanceWallpaperDataStore {
    companion object {
        val TAG = "AdvanceDataStore"

        val DEFAULT_WALLPAPER_ID = "-1"
    }

    @Synchronized override fun getWallpaperEntity(): AdvanceWallpaperEntity {
        if (!advanceWallpaperCache.isDirty()) {
            val selected = advanceWallpaperCache.getSelectedWallpaper()
            if (selected != null) {
                return selected
            }
        }
        var cursor: Cursor? = null
        var entity: AdvanceWallpaperEntity? = null
        try {
            val contentResolver = context.contentResolver
            cursor = contentResolver.query(StyleContract.AdvanceWallpaper.CONTENT_SELECTED_URI,
                    null, null, null, null)
            if (cursor != null && cursor.moveToFirst()) {
                entity = AdvanceWallpaperEntity.readEntityFromCursor(cursor)
            }
        } finally {
            if (cursor != null) {
                cursor.close()
            }
        }
        if (entity == null) {
            entity = buildDefaultWallpaper()
        }
        return entity
    }

    override fun getAdvanceWallpapers(): Observable<List<AdvanceWallpaperEntity>> {
        return createAdvanceWallpapersFromDB().doOnNext(advanceWallpaperCache::put)
    }

    override fun selectWallpaper(wallpaperId: String, tempSelect: Boolean):
            Observable<Boolean> {
        return Observable.create { emitter ->
            val selectValue = ContentValues()
            selectValue.put(StyleContract.AdvanceWallpaper.COLUMN_NAME_SELECTED, 1)
            val unselectedValue = ContentValues()
            unselectedValue.put(StyleContract.AdvanceWallpaper.COLUMN_NAME_SELECTED, 0)
            // unselected old
            context.contentResolver.update(
                    StyleContract.AdvanceWallpaper.CONTENT_SELECTED_URI,
                    unselectedValue, null, null)
            // select new
            val uri = StyleContract.AdvanceWallpaper.buildWallpaperUri(wallpaperId)
            val selectedCount = context.contentResolver.update(uri, selectValue, null, null)
            if (selectedCount > 0) {
                emitter.onNext(true)
            } else {
                emitter.onNext(false)
            }
            synchronized(advanceWallpaperCache) {
                if (!advanceWallpaperCache.isDirty()) {
                    advanceWallpaperCache.selectWallpaper(wallpaperId)
                }
            }

            emitter.onComplete()
            notifyChange(context, StyleContract.AdvanceWallpaper.CONTENT_URI)
        }
    }

    override fun downloadWallpaper(wallpaperId: String): Observable<Long> {
        throw UnsupportedOperationException("Local data store not support download wallpaper.")
    }

    fun loadWallpaperEntity(wallpaperId: String): AdvanceWallpaperEntity {
        var entity: AdvanceWallpaperEntity? = null
        synchronized(advanceWallpaperCache) {
            if (!advanceWallpaperCache.isDirty()
                    && advanceWallpaperCache.isCached(wallpaperId)) {
                entity = advanceWallpaperCache.getWallpaper(wallpaperId)
            } else {
                entity = loadWallpaperEntityFromDB(wallpaperId)
            }
            if (entity == null) {
                entity = loadWallpaperEntityFromDB(wallpaperId)
            }
        }
        return entity!!
    }

    override fun readAd(wallpaperId: String): Observable<Boolean> {
        return Observable.create { emitter ->
            if (advanceWallpaperCache.isCached(wallpaperId)) {
                advanceWallpaperCache.readAd(wallpaperId)
            }

            val uri = StyleContract.AdvanceWallpaper.buildWallpaperUri(wallpaperId)
            val contentValues = ContentValues()
            contentValues.put(StyleContract.AdvanceWallpaper.COLUMN_NAME_NEED_AD, 0)
            context.contentResolver.update(uri, contentValues, null, null)
            emitter.onNext(true)
            emitter.onComplete()
        }
    }

    override fun rollback() {
        advanceWallpaperCache.evictAll()

        val unselectedValue = ContentValues()
        unselectedValue.put(StyleContract.AdvanceWallpaper.COLUMN_NAME_SELECTED, 0)
        // unselected all
        context.contentResolver.update(
                StyleContract.AdvanceWallpaper.CONTENT_SELECTED_URI,
                unselectedValue, null, null)
    }

    private fun loadWallpaperEntityFromDB(wallpaperId: String): AdvanceWallpaperEntity? {
        var cursor: Cursor? = null
        try {
            val contentResolver = context.contentResolver
            cursor = contentResolver.query(StyleContract.AdvanceWallpaper
                    .buildWallpaperUri(wallpaperId),
                    null, null, null, null)
            if (cursor != null && cursor.moveToFirst()) {
                val entity = AdvanceWallpaperEntity.readEntityFromCursor(cursor)
                return entity
            }
            return null
        } finally {
            cursor?.close()
        }
    }

    private fun createAdvanceWallpapersFromDB(): Observable<List<AdvanceWallpaperEntity>> {
        return Observable.create { emitter ->
            var cursor: Cursor? = null
            val validWallpapers = ArrayList<AdvanceWallpaperEntity>()
            try {
                val contentResolver = context.contentResolver
                cursor = contentResolver.query(StyleContract.AdvanceWallpaper.CONTENT_URI,
                        null, null, null, null)
                validWallpapers.addAll(AdvanceWallpaperEntity.readCursor(cursor))
            } finally {
                cursor?.close()
            }

            emitter.onNext(validWallpapers)
            emitter.onComplete()
        }
    }

    private fun buildDefaultWallpaper(): AdvanceWallpaperEntity {
        val entity = AdvanceWallpaperEntity()
        entity.isDefault = true
        entity.id = -1
        entity.wallpaperId = DEFAULT_WALLPAPER_ID
        entity.author = "Yalin"
        entity.link = "kinglloy.com"
        entity.name = "Rainbow"

        return entity
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/CacheWallpaperDataStore.java
================================================
package com.yalin.style.data.repository.datasource;

import com.yalin.style.data.cache.WallpaperCache;
import com.yalin.style.data.entity.WallpaperEntity;

import com.yalin.style.data.exception.ReswitchException;
import com.yalin.style.data.lock.OpenInputStreamLock;

import java.io.InputStream;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/20.
 */

public class CacheWallpaperDataStore implements WallpaperDataStore {

    private final WallpaperCache wallpaperCache;
    private final OpenInputStreamLock openInputStreamLock;

    public CacheWallpaperDataStore(WallpaperCache wallpaperCache,
                                   OpenInputStreamLock openInputStreamLock) {
        this.wallpaperCache = wallpaperCache;
        this.openInputStreamLock = openInputStreamLock;
    }

    @Override
    public Observable<WallpaperEntity> getWallPaperEntity() {
        return wallpaperCache.get();
    }

    @Override
    public Observable<WallpaperEntity> switchWallPaperEntity() {
        if (openInputStreamLock.obtain()) {
            openInputStreamLock.release();
            return wallpaperCache.getNext();
        } else {
            return Observable.create(emitter ->
                    emitter.onError(new ReswitchException()));
        }
    }

    @Override
    public Observable<InputStream> openInputStream(String wallpaperId) {
        throw new UnsupportedOperationException("Cache data store not support open input stream.");
    }

    @Override
    public Observable<Integer> getWallpaperCount() {
        return wallpaperCache.getWallpaperCount();
    }

    @Override
    public Observable<Boolean> likeWallpaper(String wallpaperId) {
        throw new UnsupportedOperationException("Cache data store not support open input stream.");
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/DbWallpaperDataStore.java
================================================
package com.yalin.style.data.repository.datasource;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;

import com.yalin.style.data.cache.WallpaperCache;
import com.yalin.style.data.entity.WallpaperEntity;
import com.yalin.style.data.exception.LikeException;
import com.yalin.style.data.lock.LikeWallpaperLock;
import com.yalin.style.data.lock.OpenInputStreamLock;
import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract;

import com.yalin.style.data.repository.datasource.provider.StyleContract.Wallpaper;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Queue;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */

public class DbWallpaperDataStore implements WallpaperDataStore {

    private static final String TAG = "DbWallpaperDataStore";

    public static final String DEFAULT_WALLPAPER_ID = "-1";

    private final Context context;

    private final WallpaperCache wallpaperCache;
    private final OpenInputStreamLock openInputStreamLock;
    private final LikeWallpaperLock likeWallpaperLock;

    public DbWallpaperDataStore(Context context, WallpaperCache wallpaperCache,
                                OpenInputStreamLock openInputStreamLock,
                                LikeWallpaperLock likeWallpaperLock) {
        this.context = context;
        this.wallpaperCache = wallpaperCache;
        this.openInputStreamLock = openInputStreamLock;
        this.likeWallpaperLock = likeWallpaperLock;
    }

    @Override
    public Observable<WallpaperEntity> getWallPaperEntity() {
        return createEntitiesObservable().doOnNext(wallpaperCache::put).map(Queue::peek);
    }

    @Override
    public Observable<WallpaperEntity> switchWallPaperEntity() {
        return getWallPaperEntity();
    }

    @Override
    public Observable<InputStream> openInputStream(String wallpaperId) {
        return Observable.create(emitter -> {
            try {
                openInputStreamLock.obtain();
                InputStream inputStream;
                if (DEFAULT_WALLPAPER_ID.equals(wallpaperId)) {
                    inputStream = context.getAssets().open("painterly-architectonic.jpg");
                } else {
                    inputStream = context.getContentResolver().openInputStream(
                            StyleContract.Wallpaper.buildWallpaperUri(wallpaperId));
                }
                emitter.onNext(inputStream);
                emitter.onComplete();
            } catch (IOException e) {
                LogUtil.D(TAG, "Open input stream failed for wallpaperId : " + wallpaperId);
                emitter.onError(e);
            } finally {
                openInputStreamLock.release();
            }
        });
    }

    @Override
    public Observable<Integer> getWallpaperCount() {
        return Observable.create(emitter -> {
            Cursor cursor = null;
            int count = 0;
            ContentResolver contentResolver = context.getContentResolver();
            cursor = contentResolver.query(StyleContract.Wallpaper.CONTENT_URI,
                    null, null, null, null);
            if (cursor != null) {
                // contain default
                count = cursor.getCount() + 1;
                cursor.close();
            }
            emitter.onNext(count);
            emitter.onComplete();
        });
    }

    @Override
    public Observable<Boolean> likeWallpaper(String wallpaperId) {
        if (!likeWallpaperLock.obtain()) {
            return Observable.create(emitter -> emitter.onError(new LikeException()));
        }
        wallpaperCache.likeWallpaper(wallpaperId);
        return Observable.create(emitter -> {
            Cursor cursor = null;
            try {
                ContentResolver contentResolver = context.getContentResolver();
                cursor = contentResolver.query(StyleContract.Wallpaper.buildWallpaperUri(wallpaperId),
                        null, null, null, null);
                if (cursor != null && cursor.moveToFirst()) {
                    WallpaperEntity entity = WallpaperEntity.readEntityFromCursor(cursor);
                    entity.liked = !entity.liked;
                    int columnCount = contentResolver
                            .update(StyleContract.Wallpaper.buildWallpaperLikeUri(wallpaperId),
                                    buildKeepContentValue(entity), null, null);
                    if (columnCount > 0) {
                        emitter.onNext(entity.liked);
                    } else {
                        throw new LikeException();
                    }
                } else {
                    throw new LikeException();
                }
            } catch (Exception e) {
                emitter.onError(e);
            } finally {
                likeWallpaperLock.release();
                if (cursor != null) {
                    cursor.close();
                }
            }
        });
    }

    private Observable<Queue<WallpaperEntity>> createEntitiesObservable() {
        return Observable.create(emitter -> {
            Cursor cursor = null;
            Queue<WallpaperEntity> validWallpapers = new LinkedList<>();
            try {
                ContentResolver contentResolver = context.getContentResolver();
                cursor = contentResolver.query(Wallpaper.CONTENT_URI,
                        null, null, null, null);
                validWallpapers.addAll(WallpaperEntity.readCursor(context, cursor));
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }
            // from db all wallpaper can be liked
            for (WallpaperEntity entity : validWallpapers) {
                entity.canLike = true;
            }

            validWallpapers.add(buildDefaultWallpaper());

            emitter.onNext(validWallpapers);
            emitter.onComplete();
        });
    }


    public static WallpaperEntity buildDefaultWallpaper() {
        WallpaperEntity wallpaperEntity = new WallpaperEntity();
        wallpaperEntity.id = -1;
        wallpaperEntity.attribution = "kinglloy.com";
        wallpaperEntity.byline = "Lyubov Popova, 1918";
        wallpaperEntity.imageUri = "imageUri";
        wallpaperEntity.title = "Painterly Architectonic";
        wallpaperEntity.wallpaperId = DEFAULT_WALLPAPER_ID;
        wallpaperEntity.liked = false;
        wallpaperEntity.isDefault = true;
        wallpaperEntity.canLike = false;
        return wallpaperEntity;
    }

    private ContentValues buildKeepContentValue(WallpaperEntity entity) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(Wallpaper.COLUMN_NAME_LIKED, entity.liked ? 1 : 0);
        return contentValues;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/GalleryWallpaperDataStore.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.ContentProviderOperation
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.text.TextUtils
import android.text.format.DateUtils
import com.fernandocejas.arrow.checks.Preconditions
import com.yalin.style.data.R
import com.yalin.style.data.cache.GalleryWallpaperCache
import com.yalin.style.data.entity.GalleryWallpaperEntity
import com.yalin.style.data.entity.WallpaperEntity
import com.yalin.style.data.exception.ReswitchException
import com.yalin.style.data.extensions.DelegateExt
import com.yalin.style.data.lock.OpenInputStreamLock
import com.yalin.style.data.repository.datasource.io.GalleryWallpapersHandler
import com.yalin.style.data.repository.datasource.io.RemoveGalleryWallpapersHandler
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.repository.datasource.sync.gallery.GalleryScheduleService
import com.yalin.style.data.utils.getCacheFileForUri
import com.yalin.style.data.utils.getImagesFromTreeUri
import com.yalin.style.data.utils.notifyChange
import com.yalin.style.domain.GalleryWallpaper
import io.reactivex.Observable
import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.util.*
import kotlin.collections.ArrayList

/**
 * @author jinyalin
 * @since 2017/5/22.
 */
class GalleryWallpaperDataStore(val context: Context,
                                val openInputStreamLock: OpenInputStreamLock,
                                val galleryWallpaperCache: GalleryWallpaperCache) :
        WallpaperDataStore {

    var currentGalleryWallpaperId: Long by DelegateExt.preferences(context,
            GalleryScheduleService.PREF_CURRENT_SHOW_WALLPAPER_ID, -1)

    var rotateIntervalMin: Int by DelegateExt.preferences(context,
            GalleryScheduleService.PREF_ROTATE_INTERVAL_MIN,
            GalleryScheduleService.DEFAULT_ROTATE_INTERVAL_MIN)

    override fun getWallPaperEntity(): Observable<WallpaperEntity> {
        if (galleryWallpaperCache.isCached()) {
            val entities = galleryWallpaperCache.get()!!
            return Observable.create { emitter ->
                emitter.onNext(peekValid(entities))
                emitter.onComplete()
            }
        } else {
            return createEntitiesObservable().doOnNext(galleryWallpaperCache::put).map { entities ->
                return@map peekValid(entities)
            }
        }
    }

    override fun switchWallPaperEntity(): Observable<WallpaperEntity> {
        if (openInputStreamLock.obtain()) {
            openInputStreamLock.release()
            return doSwitch()
        } else {
            return Observable.create<WallpaperEntity> {
                emitter ->
                emitter.onError(ReswitchException())
            }
        }
    }

    override fun openInputStream(wallpaperId: String?): Observable<InputStream> {
        Preconditions.checkArgument(!TextUtils.isEmpty(wallpaperId))
        return Observable.create<InputStream> { emitter ->
            var cursor: Cursor? = null
            try {
                openInputStreamLock.obtain()
                var inputStream: InputStream? = null
                if (DbWallpaperDataStore.DEFAULT_WALLPAPER_ID == wallpaperId) {
                    inputStream = context.assets.open("painterly-architectonic.jpg")
                } else {
                    cursor = context.contentResolver.query(
                            StyleContract.GalleryWallpaper.buildGalleryWallpaperUri(
                                    wallpaperId!!.toLong()), null, null, null, null)
                    if (cursor != null && cursor.moveToFirst()) {
                        val uriString = cursor.getString(cursor.getColumnIndex(
                                StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI))
                        val isTreeUri = cursor.getInt(cursor.getColumnIndex(
                                StyleContract.GalleryWallpaper.COLUMN_NAME_IS_TREE_URI)) == 1

                        if (isTreeUri && Build.VERSION.SDK_INT >= 21) {
                            val images = getImagesFromTreeUri(context, Uri.parse(uriString),
                                    Int.MAX_VALUE)
                            inputStream = context.contentResolver.openInputStream(
                                    images[Random().nextInt(images.size)])
                        } else {
                            try {
                                inputStream = context.contentResolver.openInputStream(
                                        Uri.parse(uriString))
                            } catch (e: Exception) {
                                // if cached file exist then use cached file
                                val cacheFile = getCacheFileForUri(context, uriString)
                                if ((cacheFile != null && cacheFile.exists())) {
                                    inputStream = FileInputStream(cacheFile)
                                } else {
                                    throw IOException("Cannot open gallery uri : " + uriString)
                                }
                            }
                        }
                    }
                }
                emitter.onNext(inputStream!!)
                emitter.onComplete()
            } catch (e: IOException) {
                emitter.onError(e)
            } finally {
                cursor?.close()
                openInputStreamLock.release()
            }
        }
    }

    override fun getWallpaperCount(): Observable<Int> {
        return Observable.create { emitter ->
            var totalCount: Int = 0
            if (galleryWallpaperCache.isCached()) {
                totalCount = galleryWallpaperCache.get()!!.size
            } else {
                var cursor: Cursor? = null
                try {
                    cursor = context.contentResolver.query(StyleContract.GalleryWallpaper.CONTENT_URI,
                            null, null, null, null)
                    if (cursor != null) {
                        totalCount = cursor.count
                    }
                } finally {
                    cursor?.close()
                }
            }

            emitter.onNext(totalCount)
            emitter.onComplete()
        }
    }

    override fun likeWallpaper(wallpaperId: String?): Observable<Boolean> {
        throw UnsupportedOperationException("Gallery data store not support like.")
    }

    fun addGalleryWallpaperUris(uris: List<GalleryWallpaper>): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            galleryWallpaperCache.evictAll()
            var success = true
            try {
                val wallpaperHandler = GalleryWallpapersHandler(context, uris)
                val contentOperators = ArrayList<ContentProviderOperation>()
                wallpaperHandler.makeContentProviderOperations(contentOperators)
                if (contentOperators.size > 0) {
                    context.contentResolver.applyBatch(StyleContract.AUTHORITY, contentOperators)
                }
            } catch (e: Exception) {
                success = false
                emitter.onError(e)
            }
            if (success) {
                emitter.onNext(true)
                emitter.onComplete()
                GalleryScheduleService.publish(context)
            }
        }
    }

    fun removeGalleryWallpaperUris(uris: List<GalleryWallpaper>): Observable<Boolean> {
        return Observable.create<Boolean> { emitter ->
            galleryWallpaperCache.evictAll()
            var success = true
            try {
                val removeHandler = RemoveGalleryWallpapersHandler(context, uris)
                val contentOperators = ArrayList<ContentProviderOperation>()
                removeHandler.makeContentProviderOperations(contentOperators)
                if (contentOperators.size > 0) {
                    context.contentResolver.applyBatch(StyleContract.AUTHORITY, contentOperators)
                }
            } catch (e: Exception) {
                success = false
                emitter.onError(e)
            }
            if (success) {
                emitter.onNext(true)
                emitter.onComplete()
                GalleryScheduleService.publish(context)
            }
        }
    }

    fun getGalleryWallpaperUris(): Observable<List<GalleryWallpaperEntity>> {
        return createEntitiesObservable().doOnNext(galleryWallpaperCache::put)
    }

    fun forceNow(wallpaperUri: String): Observable<Boolean> {
        return Observable.create { emitter ->
            if (galleryWallpaperCache.isCached()) {
                for (entity in galleryWallpaperCache.get()!!) {
                    if (TextUtils.equals(entity.uri, wallpaperUri)) {
                        currentGalleryWallpaperId = entity.id
                        break
                    }
                }
            } else {
                var cursor: Cursor? = null
                try {
                    cursor = context.contentResolver.query(StyleContract.GalleryWallpaper.CONTENT_URI,
                            arrayOf(StyleContract.GalleryWallpaper._ID),
                            StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI + " = ? ",
                            arrayOf(wallpaperUri), null)
                    if (cursor != null && cursor.moveToFirst()) {
                        currentGalleryWallpaperId = cursor.getLong(0)
                    }
                } finally {
                    cursor?.close()
                }
            }
            emitter.onNext(true)
            emitter.onComplete()
            notifyChange(context, StyleContract.GalleryWallpaper.CONTENT_URI)
        }
    }

    fun setUpdateIntervalMin(intervalMin: Int): Observable<Boolean> {
        return Observable.create { emitter ->
            GalleryScheduleService.setInterval(context, intervalMin)
            emitter.onNext(true)
            emitter.onComplete()
        }
    }

    fun getUpdateIntervalMin(): Observable<Int> {
        return Observable.create { emitter ->
            emitter.onNext(rotateIntervalMin)
            emitter.onComplete()
        }
    }

    private fun createEntitiesObservable(): Observable<List<GalleryWallpaperEntity>> {
        return Observable.create<List<GalleryWallpaperEntity>> { emitter ->
            var cursor: Cursor? = null
            val validWallpapers = ArrayList<GalleryWallpaperEntity>()
            try {
                val contentResolver = context.contentResolver
                cursor = contentResolver.query(StyleContract.GalleryWallpaper.CONTENT_URI,
                        null, null, null, null)
                validWallpapers.addAll(GalleryWallpaperEntity.readCursor(context, cursor))
            } finally {
                cursor?.close()
            }

            emitter.onNext(validWallpapers)
            emitter.onComplete()
        }
    }

    private fun peekValid(entities: List<GalleryWallpaperEntity>): WallpaperEntity {
        if (entities.isNotEmpty()) {
            if (currentGalleryWallpaperId == -1L) {
                val selectedEntity: GalleryWallpaperEntity
                if (entities.size == 1) {
                    selectedEntity = entities[0]
                    currentGalleryWallpaperId = selectedEntity.id
                } else {
                    val random = Random()
                    selectedEntity = entities[random.nextInt(entities.size)]
                    currentGalleryWallpaperId = selectedEntity.id
                }
                return switchToWallpaperEntity(selectedEntity)
            } else {
                entities.filter { it.id == currentGalleryWallpaperId }
                        .forEach { return switchToWallpaperEntity(it) }
            }
        }
        return DbWallpaperDataStore.buildDefaultWallpaper()
    }

    private fun switchToWallpaperEntity(galleryWallpaperEntity: GalleryWallpaperEntity)
            : WallpaperEntity {
        val wallpaperEntity = WallpaperEntity()
        wallpaperEntity.isDefault = false
        wallpaperEntity.canLike = false
        wallpaperEntity.title = getTitle(galleryWallpaperEntity.dateTime)
        wallpaperEntity.byline = getByline(galleryWallpaperEntity.location)
        wallpaperEntity.attribution = "kinglloy.com"
        wallpaperEntity.imageUri = galleryWallpaperEntity.uri
        wallpaperEntity.wallpaperId = galleryWallpaperEntity.id.toString()

        return wallpaperEntity
    }

    private fun getTitle(dateTime: Long): String {
        if (dateTime > 0)
            return DateUtils.formatDateTime(context, dateTime,
                    DateUtils.FORMAT_SHOW_DATE
                            or DateUtils.FORMAT_SHOW_YEAR
                            or DateUtils.FORMAT_SHOW_WEEKDAY)
        else return context.getString(R.string.gallery_from_gallery)
    }

    private fun getByline(location: String?): String {
        if (location.isNullOrEmpty())
            return context.getString(R.string.gallery_touch_to_view)
        else return location!!
    }

    private fun doSwitch(): Observable<WallpaperEntity> {
        if (galleryWallpaperCache.isCached()) {
            return Observable.create<WallpaperEntity> { emitter ->
                val entities = galleryWallpaperCache.get()
                emitter.onNext(peekOne(entities!!))
                emitter.onComplete()
            }
        } else {
            return createEntitiesObservable().doOnNext(galleryWallpaperCache::put)
                    .map { entities ->
                        return@map peekOne(entities)
                    }
        }
    }

    private fun peekOne(entities: List<GalleryWallpaperEntity>): WallpaperEntity {
        var selectedEntity: GalleryWallpaperEntity? = null
        if (entities.size > 1) {
            val random = Random()
            while (true) {
                selectedEntity = entities[random.nextInt(entities.size)]
                if (selectedEntity.id != currentGalleryWallpaperId) {
                    currentGalleryWallpaperId = selectedEntity.id
                    break
                }
            }
        } else if (entities.size == 1) {
            if (currentGalleryWallpaperId != entities[0].id) {
                currentGalleryWallpaperId = entities[0].id
            }
            selectedEntity = entities[0]
        } else {
            if (currentGalleryWallpaperId != -1L) {
                currentGalleryWallpaperId = -1
            }
        }
        if (selectedEntity != null) {
            return switchToWallpaperEntity(selectedEntity)
        }
        return DbWallpaperDataStore.buildDefaultWallpaper()
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/GalleryWallpaperDataStoreFactory.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.Context
import com.yalin.style.data.cache.GalleryWallpaperCache
import com.yalin.style.data.lock.OpenInputStreamLock
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/24.
 */
@Singleton
class GalleryWallpaperDataStoreFactory @Inject
constructor(val context: Context,
            val openInputStreamLock: OpenInputStreamLock,
            val galleryWallpaperCache: GalleryWallpaperCache) {

    fun create(): GalleryWallpaperDataStore {
        return GalleryWallpaperDataStore(context, openInputStreamLock, galleryWallpaperCache)
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/RemoteAdvanceWallpaperDataStore.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.ContentProviderOperation
import android.content.ContentResolver
import android.content.Context
import android.content.OperationApplicationException
import android.database.Cursor
import android.os.RemoteException
import com.google.gson.JsonParser
import com.yalin.style.data.R
import com.yalin.style.data.entity.AdvanceWallpaperEntity
import com.yalin.style.data.exception.NoContentException
import com.yalin.style.data.exception.RemoteServerException
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.io.AdvanceWallpaperHandler
import com.yalin.style.data.repository.datasource.net.RemoteAdvanceWallpaperFetcher
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.repository.datasource.sync.account.Account
import com.yalin.style.domain.interactor.DefaultObserver
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/7/31.
 */
class RemoteAdvanceWallpaperDataStore(val context: Context,
                                      val localDataStore: AdvanceWallpaperDataStoreImpl)
    : AdvanceWallpaperDataStore {
    companion object {
        val TAG = "RemoteAdvanceWallpaper"
    }

    val wallpaperHandler = AdvanceWallpaperHandler(context)

    override fun getWallpaperEntity(): AdvanceWallpaperEntity {
        throw UnsupportedOperationException("Remote data store not support get wallpaper.")
    }

    override fun getAdvanceWallpapers(): Observable<List<AdvanceWallpaperEntity>> {
        return Observable.create { emitter ->
            val account = Account.getAccount()
            val authority = context.getString(R.string.authority)
            ContentResolver.cancelSync(account, authority)

            val batch = ArrayList<ContentProviderOperation>()
            try {
                val wallpapers = RemoteAdvanceWallpaperFetcher(context).fetchDataIfNewer()
                val parser = JsonParser()
                val handler = AdvanceWallpaperHandler(context)
                handler.process(parser.parse(wallpapers))
                handler.makeContentProviderOperations(batch)
            } catch (e: Exception) {
                emitter.onError(RemoteServerException())
                return@create
            }

            try {
                val operations = batch.size
                if (operations > 0) {
                    context.contentResolver.applyBatch(StyleContract.AUTHORITY, batch)
                }
            } catch (ex: RemoteException) {
                LogUtil.D(TAG, "RemoteException while applying content provider operations.")
                throw RuntimeException("Error executing content provider batch operation", ex)
            } catch (ex: OperationApplicationException) {
                LogUtil.D(TAG, "OperationApplicationException while applying content provider operations.")
                throw RuntimeException("Error executing content provider batch operation", ex)
            }

            var cursor: Cursor? = null
            val validWallpapers = ArrayList<AdvanceWallpaperEntity>()
            try {
                val contentResolver = context.contentResolver
                cursor = contentResolver.query(StyleContract.AdvanceWallpaper.CONTENT_URI,
                        null, null, null, null)
                validWallpapers.addAll(AdvanceWallpaperEntity.readCursor(cursor))
            } finally {
                if (cursor != null) {
                    cursor.close()
                }
            }

            if (validWallpapers.isEmpty()) {
                emitter.onError(NoContentException())
            } else {
                emitter.onNext(validWallpapers)
            }
            emitter.onComplete()
        }
    }

    override fun selectWallpaper(wallpaperId: String, tempSelect: Boolean): Observable<Boolean> {
        throw UnsupportedOperationException("Remote data store not support select wallpaper.")
    }

    override fun downloadWallpaper(wallpaperId: String): Observable<Long> {
        return Observable.create { emitter ->
            val entity = localDataStore.loadWallpaperEntity(wallpaperId)
            wallpaperHandler.downloadWallpaperComponent(entity, object : DefaultObserver<Long>() {
                override fun onNext(downloadedLength: Long) {
                    emitter.onNext(downloadedLength)
                }

                override fun onComplete() {
                    emitter.onComplete()
                }

                override fun onError(exception: Throwable) {
                    emitter.onError(exception)
                }

            })
        }
    }

    override fun readAd(wallpaperId: String): Observable<Boolean> {
        throw UnsupportedOperationException("Remote data store not support read wallpaper ad.")

    }

    override fun rollback() {
        // do nothing
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStore.kt
================================================
package com.yalin.style.data.repository.datasource

import com.yalin.style.data.entity.SourceEntity
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
interface SourcesDataStore {

    fun getSources(): Observable<List<SourceEntity>>

    fun selectSource(sourceId: Int, tempSelect: Boolean): Observable<Boolean>

    fun getUsedSourceId(): Int
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStoreFactory.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.Context
import com.yalin.style.data.cache.SourcesCache
import com.yalin.style.data.lock.SelectSourceLock
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
@Singleton
class SourcesDataStoreFactory @Inject
constructor(val context: Context,
            val sourcesCache: SourcesCache,
            val selectSourceLock: SelectSourceLock) {

    fun create(): SourcesDataStore {
        return SourcesDataStoreImpl(context, sourcesCache, selectSourceLock)
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStoreImpl.kt
================================================
package com.yalin.style.data.repository.datasource

import android.content.Context
import com.yalin.style.data.cache.SourcesCache
import com.yalin.style.data.entity.SourceEntity
import com.yalin.style.data.lock.SelectSourceLock
import io.reactivex.Observable

/**
 * @author jinyalin
 * @since 2017/5/23.
 */
class SourcesDataStoreImpl(val context: Context,
                           val sourcesCache: SourcesCache,
                           val selectSourceLock: SelectSourceLock) : SourcesDataStore {

    override fun selectSource(sourceId: Int, tempSelect: Boolean): Observable<Boolean> {
        return Observable.create { emitter ->
            try {
                if ((!tempSelect && selectSourceLock.obtain()) || tempSelect) {
                    emitter.onNext(sourcesCache.selectSource(sourceId, tempSelect))
                } else {
                    emitter.onNext(false)
                }
                emitter.onComplete()
            } finally {
                selectSourceLock.release()
            }
        }
    }

    override fun getSources(): Observable<List<SourceEntity>> {
        return sourcesCache.getSources(context)
    }

    override fun getUsedSourceId() = sourcesCache.getUsedSourceId()

}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/StyleWallpaperDataStoreFactory.java
================================================
package com.yalin.style.data.repository.datasource;


import android.content.Context;

import com.yalin.style.data.cache.WallpaperCache;

import com.yalin.style.data.lock.LikeWallpaperLock;
import com.yalin.style.data.lock.OpenInputStreamLock;

import javax.inject.Inject;
import javax.inject.Singleton;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */

@Singleton
public class StyleWallpaperDataStoreFactory {

    private final Context context;
    private final WallpaperCache wallpaperCache;
    private final OpenInputStreamLock openInputStreamLock;
    private final LikeWallpaperLock likeWallpaperLock;

    @Inject
    StyleWallpaperDataStoreFactory(Context context, WallpaperCache wallpaperCache,
                                   OpenInputStreamLock openInputStreamLock,
                                   LikeWallpaperLock likeWallpaperLock) {
        this.context = context;
        this.wallpaperCache = wallpaperCache;
        this.openInputStreamLock = openInputStreamLock;
        this.likeWallpaperLock = likeWallpaperLock;
    }

    public WallpaperDataStore create() {
        WallpaperDataStore wallpaperDataStore;
        if (!wallpaperCache.isDirty() && wallpaperCache.isCached()) {
            wallpaperDataStore = new CacheWallpaperDataStore(wallpaperCache, openInputStreamLock);
        } else {
            wallpaperDataStore = createDbDataStore();
        }
        return wallpaperDataStore;
    }

    public WallpaperDataStore createDbDataStore() {
        return new DbWallpaperDataStore(context, wallpaperCache,
                openInputStreamLock, likeWallpaperLock);
    }

    public void onDataRefresh() {
        wallpaperCache.evictAll();
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/WallpaperDataStore.java
================================================
package com.yalin.style.data.repository.datasource;

import com.yalin.style.data.entity.WallpaperEntity;

import java.io.InputStream;

import io.reactivex.Observable;

/**
 * @author jinyalin
 * @since 2017/4/18.
 */

public interface WallpaperDataStore {

    Observable<WallpaperEntity> getWallPaperEntity();

    Observable<WallpaperEntity> switchWallPaperEntity();

    Observable<InputStream> openInputStream(String wallpaperId);

    Observable<Integer> getWallpaperCount();

    Observable<Boolean> likeWallpaper(String wallpaperId);
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/AdvanceWallpaperHandler.kt
================================================
package com.yalin.style.data.repository.datasource.io

import android.content.ContentProviderOperation
import android.content.Context
import android.database.Cursor
import com.google.gson.Gson
import com.google.gson.JsonElement
import com.yalin.style.data.SyncConfig
import com.yalin.style.data.entity.AdvanceWallpaperEntity
import com.yalin.style.data.exception.NetworkConnectionException
import com.yalin.style.data.exception.RemoteServerException
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.repository.datasource.provider.StyleContractHelper
import com.yalin.style.data.utils.WallpaperFileHelper
import com.yalin.style.domain.interactor.DefaultObserver
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.*
import java.net.URL
import java.util.ArrayList
import java.util.HashSet
import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.ReentrantLock

/**
 * @author jinyalin
 * @since 2017/7/28.
 */
class AdvanceWallpaperHandler(context: Context) : JSONHandler(context) {
    companion object {
        val TAG = "AdvanceWallpaperHandler"
        val downloadLock = ReentrantLock()
    }

    private var wallpapers: ArrayList<AdvanceWallpaperEntity> = ArrayList()

    override fun makeContentProviderOperations(list: ArrayList<ContentProviderOperation>) {
        val uri = StyleContractHelper.setUriAsCalledFromSyncAdapter(
                StyleContract.AdvanceWallpaper.CONTENT_URI)
        list.add(ContentProviderOperation.newDelete(uri).build())

        val validFiles = HashSet<String>()
        val selectedEntities = querySelectedWallpapers()
        validFiles.addAll(getWallpaperNameSet(selectedEntities))
        for (wallpaper in this.wallpapers) {
            wallpaper.storePath = makeStorePath(wallpaper)
            if (!selectedEntities.contains(wallpaper)) {
                if (wallpaper.lazyDownload || (downloadWallpaperComponent(wallpaper)
                        && WallpaperFileHelper.ensureChecksumValid(mContext,
                        wallpaper.checkSum, wallpaper.storePath))) {
                    LogUtil.D(TAG, "download wallpaper component "
                            + " success, do output wallpaper.")
                    outputWallpaper(wallpaper, list)
                    validFiles.add(makeFilename(wallpaper))
                }
            }
        }
        // delete old wallpapers
        WallpaperFileHelper.deleteOldComponent(mContext, validFiles)
    }

    override fun process(element: JsonElement) {
        val wallpapers = Gson().fromJson(element, Array<AdvanceWallpaperEntity>::class.java)
        this.wallpapers.ensureCapacity(wallpapers.size)
        this.wallpapers.addAll(wallpapers)
    }

    private fun makeFilename(wallpaper: AdvanceWallpaperEntity): String {
        return wallpaper.hashCode().toString() + "_component.apk"
    }

    private fun makeStorePath(wallpaper: AdvanceWallpaperEntity): String {
        val outputDir = WallpaperFileHelper.getAdvanceWallpaperDir(mContext)
        return File(outputDir, makeFilename(wallpaper)).absolutePath
    }

    private fun getWallpaperNameSet(entities: List<AdvanceWallpaperEntity>): Set<String> {
        val ids = HashSet<String>()
        for (entity in entities) {
            ids.add(makeFilename(entity))
        }
        return ids
    }

    private fun outputWallpaper(wallpaper: AdvanceWallpaperEntity,
                                list: ArrayList<ContentProviderOperation>) {
        val uri = StyleContractHelper.setUriAsCalledFromSyncAdapter(
                StyleContract.AdvanceWallpaper.CONTENT_URI)
        val builder = ContentProviderOperation.newInsert(uri)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_WALLPAPER_ID, wallpaper.wallpaperId)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_AUTHOR, wallpaper.author)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_DOWNLOAD_URL, wallpaper.downloadUrl)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_ICON_URL, wallpaper.iconUrl)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_LINK, wallpaper.link)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_NAME, wallpaper.name)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_CHECKSUM, wallpaper.checkSum)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_STORE_PATH, wallpaper.storePath)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_PROVIDER_NAME, wallpaper.providerName)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_SELECTED, 0)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_LAZY_DOWNLOAD,
                if (wallpaper.lazyDownload) 1 else 0)
        builder.withValue(StyleContract.AdvanceWallpaper.COLUMN_NAME_NEED_AD,
                if (wallpaper.needAd) 1 else 0)

        list.add(builder.build())
    }

    private fun querySelectedWallpapers(): List<AdvanceWallpaperEntity> {
        var cursor: Cursor? = null
        try {
            cursor = mContext.contentResolver.query(
                    StyleContract.AdvanceWallpaper.CONTENT_SELECTED_URI, null, null, null, null)
            return AdvanceWallpaperEntity.readCursor(cursor)
        } finally {
            if (cursor != null) {
                cursor.close()
            }
        }
    }

    private fun downloadWallpaperComponent(wallpaper: AdvanceWallpaperEntity): Boolean {
        return downloadWallpaperComponent(wallpaper, null)
    }

    fun downloadWallpaperComponent(wallpaper: AdvanceWallpaperEntity,
                                   observer: DefaultObserver<Long>?): Boolean {
        observer?.onNext(0)
        LogUtil.D(TAG, "Start download wallpaper component to " + wallpaper.storePath)
        val outputFile = File(wallpaper.storePath)
        if (outputFile.exists()) {
            if (WallpaperFileHelper.ensureChecksumValid(mContext,
                    wallpaper.checkSum, wallpaper.storePath)) {
                observer?.onComplete()
                return true
            }
        }
        synchronized(downloadLock) {
            var os: OutputStream? = null
            var _is: InputStream? = null
            try {
                if (outputFile.exists()) {
                    if (WallpaperFileHelper.ensureChecksumValid(mContext,
                            wallpaper.checkSum, wallpaper.storePath)) {
                        observer?.onComplete()
                        return true
                    } else {
                        outputFile.delete()
                    }
                }

                val storePath = outputFile.parentFile
                storePath.mkdirs()
                os = FileOutputStream(outputFile)
                val httpClient = OkHttpClient.Builder()
                        .connectTimeout(SyncConfig.DEFAULT_CONNECT_TIMEOUT.toLong(), TimeUnit.SECONDS)
                        .readTimeout(SyncConfig.DEFAULT_DOWNLOAD_TIMEOUT.toLong(), TimeUnit.SECONDS)
                        .build()
                val request = Request.Builder().url(URL(wallpaper.downloadUrl)).build()

                val response = httpClient.newCall(request).execute()
                val responseCode = response.code()
                if (responseCode in 200..299) {
                    _is = response.body().byteStream()
                    val buffer = ByteArray(1024)
                    var bytesRead: Int
                    var writeLength = 0L
                    bytesRead = _is.read(buffer)
                    while (bytesRead > 0) {
                        os.write(buffer, 0, bytesRead)
                        writeLength += bytesRead
                        observer?.onNext(writeLength)
                        bytesRead = _is.read(buffer)
                    }
                    os.flush()
                    observer?.onComplete()
                    return true
                } else {
                    LogUtil.E(TAG, "Download wallpaper component " + wallpaper.name + " failed.")
                    observer?.onError(RemoteServerException())
                    return false

                }
            } catch (e: IOException) {
                e.printStackTrace()
                observer?.onError(NetworkConnectionException())
                LogUtil.E(TAG, "Download wallpaper component" + wallpaper.name + " failed.", e)
                return false
            } finally {
                ensureChecksum(outputFile, wallpaper.checkSum)
                try {
                    os?.close()
                    _is?.close()
                } catch (e: IOException) {
                    // ignore
                }
            }
        }
    }

    private fun ensureChecksum(file: File, checkSum: String) {
        if (file.exists()) {
            if (!WallpaperFileHelper.ensureChecksumValid(mContext,
                    checkSum, file.absolutePath)) {
                file.delete()
            }
        }
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/GalleryWallpapersHandler.kt
================================================
package com.yalin.style.data.repository.datasource.io

import android.annotation.SuppressLint
import android.content.ContentProviderOperation
import android.content.Context
import android.location.Address
import android.location.Geocoder
import android.net.Uri
import android.support.media.ExifInterface
import android.text.TextUtils
import com.google.gson.JsonElement
import com.yalin.style.data.log.LogUtil
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.data.utils.isTreeUri
import com.yalin.style.data.utils.processUriPermission
import com.yalin.style.domain.GalleryWallpaper
import java.text.SimpleDateFormat
import java.util.ArrayList

/**
 * @author jinyalin
 * @since 2017/5/24.
 */
class GalleryWallpapersHandler(val context: Context,
                               val uris: List<GalleryWallpaper>) : JSONHandler(context) {

    companion object {
        private val TAG = "GalleryWallpapersHandler"

        @SuppressLint("SimpleDateFormat")
        private val sExifDateFormat = SimpleDateFormat("yyyy:MM:dd HH:mm:ss")
    }

    private var mGeocoder: Geocoder = Geocoder(context)

    override fun makeContentProviderOperations(list: ArrayList<ContentProviderOperation>) {
        val uri = StyleContract.GalleryWallpaper.CONTENT_URI
        for (wallpaperEntity in uris) {
            if (TextUtils.isEmpty(wallpaperEntity.uri)) {
                continue
            }
            wallpaperEntity.isTreeUri = isTreeUri(Uri.parse(wallpaperEntity.uri))
            processUriPermission(context, wallpaperEntity)

            val builder = ContentProviderOperation.newInsert(uri)
            builder.withValue(StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI,
                    wallpaperEntity.uri)
            builder.withValue(StyleContract.GalleryWallpaper.COLUMN_NAME_IS_TREE_URI,
                    if (wallpaperEntity.isTreeUri) 1 else 0)

            readMetaData(wallpaperEntity.uri, builder)
            list.add(builder.build())
        }
    }

    override fun process(element: JsonElement) {

    }

    private fun readMetaData(uriString: String, builder: ContentProviderOperation.Builder) {
        try {
            val uri = Uri.parse(uriString)
            var hasMetadata = false
            context.contentResolver.openInputStream(uri).use({ `in` ->
                if (`in` == null) {
                    return
                }
                val exifInterface = ExifInterface(`in`)
                val dateString = exifInterface.getAttribute(ExifInterface.TAG_DATETIME)
                if (!TextUtils.isEmpty(dateString)) {
                    val date = sExifDateFormat.parse(dateString)
                    builder.withValue(StyleContract.GalleryWallpaper.COLUMN_NAME_DATE_TIME,
                            date.time)
                    hasMetadata = true
                }

                val latlong = exifInterface.latLong
                if (latlong != null) {
                    // Reverse geocode
                    var addresses: List<Address>? = null
                    try {
                        addresses = mGeocoder.getFromLocation(latlong[0], latlong[1], 1)
                    } catch (e: IllegalArgumentException) {
                        LogUtil.E(TAG, "Invalid latitude/longitude, skipping location metadata", e)
                    }

                    if (addresses != null && addresses.isNotEmpty()) {
                        val addr = addresses[0]
                        val locality = addr.locality
                        val adminArea = addr.adminArea
                        val countryCode = addr.countryCode
                        val sb = StringBuilder()
                        if (!TextUtils.isEmpty(locality)) {
                            sb.append(locality)
                        }
                        if (!TextUtils.isEmpty(adminArea)) {
                            if (sb.isNotEmpty()) {
                                sb.append(", ")
                            }
                            sb.append(adminArea)
                        }
                        if (!TextUtils.isEmpty(countryCode)) {
                            if (sb.isNotEmpty()) {
                                sb.append(", ")
                            }
                            sb.append(countryCode)
                        }
                        builder.withValue(StyleContract.GalleryWallpaper.COLUMN_NAME_LOCATION,
                                sb.toString())
                        hasMetadata = true
                    }
                }
            })
            if (hasMetadata) {
                builder.withValue(StyleContract.GalleryWallpaper.COLUMN_NAME_HAS_METADATA,
                        if (hasMetadata) 1 else 0)
            }
        } catch (e: Exception) {
            LogUtil.E(TAG, "Couldn't read image metadata.", e)
        }
    }
}

================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/JSONHandler.java
================================================
package com.yalin.style.data.repository.datasource.io;

import android.content.ContentProviderOperation;
import android.content.Context;
import com.google.gson.JsonElement;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;

/**
 * YaLin 2017/1/3.
 */

public abstract class JSONHandler {

  protected Context mContext;

  public JSONHandler(Context context) {
    mContext = context;
  }

  public abstract void makeContentProviderOperations(ArrayList<ContentProviderOperation> list);

  public abstract void process(JsonElement element);

  /**
   * Loads a raw resource and returns its content as a String.
   *
   * @throws IOException If any error was encountered, such as an incorrect resource ID, or
   * inaccessible file.
   */
  public static String parseResource(Context context, int resource) throws IOException {
    InputStream stream = null;
    String data;
    try {
      stream = context.getResources().openRawResource(resource);
      data = parseStream(stream);
    } finally {
      if (stream != null) {
        try {
          stream.close();
        } catch (IOException e) {
          // Ignore exceptions during stream close, other exceptions thrown earlier will
          // be handled by the calling methods
        }
      }
    }

    return data;
  }

  private static String parseStream(final InputStream stream) throws IOException {
    Reader reader = null;
    Writer writer = new StringWriter();
    char[] buffer = new char[1024];

    // IO errors are passed up to the calling method and must be caught there.
    try {
      reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
      int n;
      while ((n = reader.read(buffer)) != -1) {
        writer.write(buffer, 0, n);
      }
    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException e) {
          // Ignore exceptions during stream close, other exceptions thrown earlier will
          // be handled by the calling methods
        }
      }
    }

    return writer.toString();
  }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/RemoveGalleryWallpapersHandler.kt
================================================
package com.yalin.style.data.repository.datasource.io

import android.content.ContentProviderOperation
import android.content.Context
import android.text.TextUtils
import com.google.gson.JsonElement
import com.yalin.style.data.repository.datasource.provider.StyleContract
import com.yalin.style.domain.GalleryWallpaper
import java.util.ArrayList

/**
 * YaLin
 * On 2017/5/26.
 */

class RemoveGalleryWallpapersHandler(val context: Context,
                                     val uris: List<GalleryWallpaper>) : JSONHandler(context) {

    override fun makeContentProviderOperations(list: ArrayList<ContentProviderOperation>) {
        uris.filterNot { TextUtils.isEmpty(it.uri) }
                .map {
                    StyleContract.GalleryWallpaper
                            .buildGalleryWallpaperDeleteUri(it.uri)
                }
                .map { ContentProviderOperation.newDelete(it) }
                .mapTo(list) { it.build() }
    }

    override fun process(element: JsonElement) {

    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/WallpapersHandler.java
================================================
package com.yalin.style.data.repository.datasource.io;

import android.content.ContentProviderOperation;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.yalin.style.data.SyncConfig;
import com.yalin.style.data.entity.WallpaperEntity;
import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract.Wallpaper;
import com.yalin.style.data.repository.datasource.provider.StyleContractHelper;
import com.yalin.style.data.utils.TimeUtil;
import com.yalin.style.data.utils.WallpaperFileHelper;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * YaLin 2017/1/3.
 */

public class WallpapersHandler extends JSONHandler {

    private static final String TAG = "WallpapersHandler";

    private ArrayList<WallpaperEntity> mWallpapers = new ArrayList<>();

    public WallpapersHandler(Context context) {
        super(context);
    }

    @Override
    public void makeContentProviderOperations(ArrayList<ContentProviderOperation> list) {
        Uri uri = StyleContractHelper.setUriAsCalledFromSyncAdapter(Wallpaper.CONTENT_URI);
        list.add(ContentProviderOperation.newDelete(uri).build());

        Set<String> validFiles = new HashSet<>();
        List<WallpaperEntity> keepedEntity = queryKeepedWallpapers();
        validFiles.addAll(getWallpaperIdSet(keepedEntity));
        for (WallpaperEntity wallpaper : mWallpapers) {
            Uri wallpaperUri = Wallpaper.buildWallpaperSaveUri(wallpaper.wallpaperId);
            if (!keepedEntity.contains(wallpaper) && downloadWallpaper(wallpaper, wallpaperUri)
                    && WallpaperFileHelper.ensureWallpaperChecksumValid(mContext,
                    wallpaper.checksum, wallpaper.wallpaperId)) {
                LogUtil.D(TAG, "download wallpaper " + wallpaperUri
                        + " success, do output wallpaper.");
                outputWallpaper(wallpaper, list, wallpaperUri.toString());
                validFiles.add(wallpaper.wallpaperId);
            }
        }
        // delete old wallpapers
        WallpaperFileHelper.deleteOldWallpapers(mContext, validFiles);
    }

    @Override
    public void process(JsonElement element) {
        WallpaperEntity[] wallpapers = new Gson().fromJson(element, WallpaperEntity[].class);
        mWallpapers.ensureCapacity(wallpapers.length);
        Collections.addAll(mWallpapers, wallpapers);
    }

    private Set<String> getWallpaperIdSet(List<WallpaperEntity> entities) {
        Set<String> ids = new HashSet<>();
        for (WallpaperEntity entity : entities) {
            ids.add(entity.wallpaperId);
        }
        return ids;
    }

    private List<WallpaperEntity> queryKeepedWallpapers() {
        Cursor cursor = null;
        try {
            cursor = mContext.getContentResolver().query(Wallpaper.CONTENT_KEEPED_URI,
                    null, null, null, null);
            return WallpaperEntity.readCursor(mContext, cursor);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private void outputWallpaper(WallpaperEntity wallpaper,
                                 ArrayList<ContentProviderOperation> list, String uriString) {
        Uri uri = StyleContractHelper.setUriAsCalledFromSyncAdapter(Wallpaper.CONTENT_URI);
        ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(uri);
        builder.withValue(Wallpaper.COLUMN_NAME_WALLPAPER_ID, wallpaper.wallpaperId);
        builder.withValue(Wallpaper.COLUMN_NAME_TITLE, wallpaper.title);
        builder.withValue(Wallpaper.COLUMN_NAME_IMAGE_URI, uriString);
        builder.withValue(Wallpaper.COLUMN_NAME_BYLINE, wallpaper.byline);
        builder.withValue(Wallpaper.COLUMN_NAME_ATTRIBUTION, wallpaper.attribution);
        builder.withValue(Wallpaper.COLUMN_NAME_ADD_DATE, TimeUtil.getCurrentTime(mContext));
        builder.withValue(Wallpaper.COLUMN_NAME_LIKED, wallpaper.liked ? 1 : 0);
        builder.withValue(Wallpaper.COLUMN_NAME_CHECKSUM, wallpaper.checksum);

        list.add(builder.build());
    }

    private boolean downloadWallpaper(WallpaperEntity wallpaper, Uri uri) {
        LogUtil.D(TAG, "Start download wallpaper uri = " + uri);
        OutputStream os = null;
        InputStream is = null;
        try {
            os = mContext.getContentResolver().openOutputStream(uri);
            if (os == null) {
                return false;
            }
            OkHttpClient httpClient = new OkHttpClient.Builder()
                    .connectTimeout(SyncConfig.DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                    .readTimeout(SyncConfig.DEFAULT_DOWNLOAD_TIMEOUT, TimeUnit.SECONDS)
                    .build();
            Request request = new Request.Builder().url(new URL(wallpaper.imageUri)).build();

            Response response = httpClient.newCall(request).execute();
            int responseCode = response.code();
            if (responseCode >= 200 && responseCode < 300) {
                is = response.body().byteStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = is.read(buffer)) > 0) {
                    os.write(buffer, 0, bytesRead);
                }
                os.flush();
                return true;
            } else {
                LogUtil.E(TAG, "Download wallpaper " + wallpaper.title + " failed.");
                return false;
            }
        } catch (IOException e) {
            e.printStackTrace();
            LogUtil.E(TAG, "Download wallpaper " + wallpaper.title + " failed.", e);
            return false;
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                // ignore
            }
        }
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/net/DataFetcher.java
================================================
package com.yalin.style.data.repository.datasource.net;

import android.content.Context;
import android.text.TextUtils;

import com.yalin.style.data.BuildConfig;
import com.yalin.style.data.SyncConfig;
import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.utils.HttpRequestUtil;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * @author jinyalin
 * @since 2017/7/28.
 */

public abstract class DataFetcher {
    private static final String TAG = "DataFetcher";

    private final Context mContext;

    private final String mWallpaperUrl;

    public DataFetcher(Context context) {
        mContext = context;
        mWallpaperUrl = getUrl();
    }

    public String fetchDataIfNewer() throws IOException {
        OkHttpClient httpClient = new OkHttpClient.Builder()
                .connectTimeout(SyncConfig.DEFAULT_CONNECT_TIMEOUT, TimeUnit.SECONDS)
                .readTimeout(SyncConfig.DEFAULT_READ_TIMEOUT, TimeUnit.SECONDS)
                .build();

        Request request = new Request.Builder()
                .url(new URL(mWallpaperUrl))
                .post(RequestBody.create(null, HttpRequestUtil.getRequestBody(mContext)))
                .build();
        Response response = httpClient.newCall(request).execute();
        if (response == null) {
            LogUtil.F(TAG, "Request for wallpaper returned null response.");
            throw new IOException("Request for data wallpaper returned null response.");
        }
        int status = response.code();
        if (status == HttpURLConnection.HTTP_OK) {
            LogUtil.D(TAG, "Server return HTTP_OK, so new data is available.");
            String body = response.body().string();
            if (TextUtils.isEmpty(body)) {
                LogUtil.F(TAG, "Request for wallpaper returned empty data.");
                throw new IOException("Error fetching wallpaper data : no data.");
            }
            LogUtil.D(TAG, "Wallpaper " + mWallpaperUrl + " read, contents: " + body);
            return body;
        } else if (status == HttpURLConnection.HTTP_NOT_MODIFIED) {
            LogUtil.D(TAG, "HTTP_NOT_MODIFIED: data has not changed since");
            return null;
        } else {
            LogUtil.D(TAG, "Error fetching conference data: HTTP status " + status + " and manifest " +
                    mWallpaperUrl);
            throw new IOException("Error fetching conference data: HTTP status " + status);
        }
    }

    protected abstract String getUrl();
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/net/RemoteAdvanceWallpaperFetcher.java
================================================
package com.yalin.style.data.repository.datasource.net;

import android.content.Context;

import com.yalin.style.data.BuildConfig;


/**
 * @author jinyalin
 * @since 2017/7/28.
 */

public class RemoteAdvanceWallpaperFetcher extends DataFetcher {

    public RemoteAdvanceWallpaperFetcher(Context context) {
        super(context);
    }


    protected String getUrl() {
        return BuildConfig.SERVER_WALLPAPER_ENDPOINT + "/advance";
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContract.java
================================================
package com.yalin.style.data.repository.datasource.provider;

import android.net.Uri;
import android.provider.BaseColumns;

/**
 * YaLin 2016/12/30.
 */

public class StyleContract {

    public static final String AUTHORITY = "com.yalin.style";

    private static final String SCHEME = "content://";

    interface WallpaperColumns {

        /**
         * Type: TEXT
         */
        String COLUMN_NAME_WALLPAPER_ID = "wallpaper_id";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_IMAGE_URI = "image_uri";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_TITLE = "title";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_BYLINE = "byline";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_ATTRIBUTION = "attribution";
        /**
         * Type: long
         */
        String COLUMN_NAME_ADD_DATE = "add_date";
        /**
         * Type: SHORT
         */
        String COLUMN_NAME_LIKED = "keep";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_CHECKSUM = "checksum";
    }

    interface GalleryColumns {

        /**
         * Type: TEXT
         */
        String COLUMN_NAME_CUSTOM_URI = "custom_wallpaper_uri";

        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_IS_TREE_URI = "is_tree_uri";

        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_DATE_TIME = "date_time";

        /**
         * Type: TEXT
         */
        String COLUMN_NAME_LOCATION = "location";

        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_HAS_METADATA = "has_metadata";
    }

    interface AdvanceWallpaperColumns {
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_WALLPAPER_ID = "wallpaper_id";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_ICON_URL = "icon_url";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_NAME = "name";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_LINK = "link";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_AUTHOR = "author";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_DOWNLOAD_URL = "download_url";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_CHECKSUM = "checksum";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_STORE_PATH = "store_path";
        /**
         * Type: TEXT
         */
        String COLUMN_NAME_PROVIDER_NAME = "provider_name";
        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_SELECTED = "selected";

        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_LAZY_DOWNLOAD = "lazy_download";

        /**
         * Type: INTEGER
         */
        String COLUMN_NAME_NEED_AD = "need_ad";
    }

    public static final Uri BASE_CONTENT_URI = Uri.parse(SCHEME + AUTHORITY);

    private static final String PATH_SOURCE = "source";
    private static final String PATH_WALLPAPER = "wallpaper";
    private static final String PATH_GALLERY = "gallery";
    private static final String PATH_ADVANCE_WALLPAPER = "advance_wallpaper";

    public static final String[] TOP_LEVEL_PATHS = {
            PATH_WALLPAPER
    };

    public static final class Source {

        public static final Uri CONTENT_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_SOURCE).build();
    }

    public static final class Wallpaper implements WallpaperColumns, BaseColumns {

        public static final String TABLE_NAME = "wallpaper";

        public static final String PATH_LIKE_WALLPAPER = "like";
        public static final String PATH_LIKED_WALLPAPER = "liked";
        public static final String PATH_SAVE_WALLPAPER = "save";

        public static final Uri CONTENT_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_WALLPAPER).build();

        public static final Uri CONTENT_KEEPED_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_WALLPAPER)
                        .appendPath(PATH_LIKED_WALLPAPER).build();

        public static Uri buildWallpaperUri(String wallpaperId) {
            return CONTENT_URI.buildUpon().appendPath(wallpaperId).build();
        }

        public static Uri buildWallpaperSaveUri(String wallpaperId) {
            return CONTENT_URI.buildUpon()
                    .appendPath(PATH_SAVE_WALLPAPER).appendPath(wallpaperId).build();
        }

        public static Uri buildWallpaperLikeUri(String wallpaperId) {
            return CONTENT_URI.buildUpon()
                    .appendPath(PATH_LIKE_WALLPAPER).appendPath(wallpaperId).build();
        }


        public static String getWallpaperId(Uri uri) {
            return uri.getPathSegments().get(1);
        }

        public static String getWallpaperSaveId(Uri uri) {
            return uri.getPathSegments().get(2);
        }

        public static String getWallpaperLikeId(Uri uri) {
            return uri.getPathSegments().get(2);
        }
    }

    public static final class GalleryWallpaper implements GalleryColumns, BaseColumns {

        public static final String TABLE_NAME = "gallery_wallpaper";

        public static final String PATH_URI = "uri";

        public static final Uri CONTENT_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_GALLERY).build();

        public static Uri buildGalleryWallpaperUri(long insertId) {
            return CONTENT_URI.buildUpon().appendPath(String.valueOf(insertId)).build();
        }

        public static String getGalleryWallpaperId(Uri uri) {
            return uri.getPathSegments().get(1);
        }

        public static Uri buildGalleryWallpaperDeleteUri(String uri) {
            return CONTENT_URI.buildUpon().appendPath(PATH_URI)
                    .appendPath(String.valueOf(uri)).build();
        }

        public static String getGalleryWallpaperDeleteUri(Uri uri) {
            return uri.getPathSegments().get(2);
        }
    }

    public static final class AdvanceWallpaper implements AdvanceWallpaperColumns, BaseColumns {
        public static final String TABLE_NAME = "advance_wallpaper";

        public static final String PATH_SELECTED_WALLPAPER = "selected";

        public static final Uri CONTENT_URI =
                BASE_CONTENT_URI.buildUpon().appendEncodedPath(PATH_ADVANCE_WALLPAPER).build();

        public static final Uri CONTENT_SELECTED_URI =
                BASE_CONTENT_URI.buildUpon().appendPath(PATH_ADVANCE_WALLPAPER)
                        .appendPath(PATH_SELECTED_WALLPAPER).build();


        public static Uri buildWallpaperUri(String wallpaperId) {
            return CONTENT_URI.buildUpon().appendPath(wallpaperId).build();
        }

        public static String getWallpaperId(Uri uri) {
            return uri.getPathSegments().get(1);
        }
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContractHelper.java
================================================
package com.yalin.style.data.repository.datasource.provider;

import android.net.Uri;

/**
 * YaLin 2017/1/3.
 */

public class StyleContractHelper {

  private static final String QUERY_PARAMETER_CALLER_IS_SYNC_ADAPTER = "callerIsSyncAdapter";

  public static Uri setUriAsCalledFromSyncAdapter(Uri uri) {
    return uri.buildUpon().appendQueryParameter(QUERY_PARAMETER_CALLER_IS_SYNC_ADAPTER, "true")
        .build();
  }

  public static boolean isUriCalledFromSyncAdapter(Uri uri) {
    return uri.getBooleanQueryParameter(QUERY_PARAMETER_CALLER_IS_SYNC_ADAPTER, false);
  }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleDatabase.java
================================================
package com.yalin.style.data.repository.datasource.provider;

import android.content.ContentResolver;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;

import com.yalin.style.data.R;
import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract.AdvanceWallpaper;
import com.yalin.style.data.repository.datasource.provider.StyleContract.Wallpaper;
import com.yalin.style.data.repository.datasource.sync.account.Account;

/**
 * YaLin 2016/12/30.
 */

public class StyleDatabase extends SQLiteOpenHelper {

    private static final String TAG = "StyleDatabase";
    private static final String DATABASE_NAME = "style.db";

    private static final int VERSION_2016_12_30 = 1;
    private static final int VERSION_2017_4_30 = 2;
    private static final int VERSION_2017_5_24 = 3;
    private static final int VERSION_2017_7_28 = 4;
    private static final int VERSION_2017_8_11 = 5;
    private static final int CUR_DATABASE_VERSION = VERSION_2017_8_11;

    private final Context mContext;

    interface Tables {

        String WALLPAPER = StyleContract.Wallpaper.TABLE_NAME;
        String GALLERY = StyleContract.GalleryWallpaper.TABLE_NAME;
        String ADVANCE_WALLPAPER = AdvanceWallpaper.TABLE_NAME;
    }

    public StyleDatabase(Context context) {
        super(context, DATABASE_NAME, null, CUR_DATABASE_VERSION);
        mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.WALLPAPER + " ("
                + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + StyleContract.Wallpaper.COLUMN_NAME_WALLPAPER_ID + " TEXT,"
                + StyleContract.Wallpaper.COLUMN_NAME_TITLE + " TEXT,"
                + StyleContract.Wallpaper.COLUMN_NAME_IMAGE_URI + " TEXT,"
                + StyleContract.Wallpaper.COLUMN_NAME_ATTRIBUTION + " TEXT,"
                + StyleContract.Wallpaper.COLUMN_NAME_BYLINE + " TEXT,"
                + StyleContract.Wallpaper.COLUMN_NAME_ADD_DATE + " INTEGER);");

        upgradeFrom20161230to20170430(db);
        upgradeFrom20170430to20170524(db);
        upgradeFrom20170525to20170728(db);
        upgradeFrom20170728to20170811(db);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        LogUtil.D(TAG, "onUpgrade() from " + oldVersion + " to " + newVersion);
        // Cancel any sync currently in progress
        android.accounts.Account account = Account.getAccount();
        if (account != null) {
            LogUtil.D(TAG, "Cancelling any pending syncs for account");
            ContentResolver.cancelSync(account, mContext.getString(R.string.authority));
        }
        int version = oldVersion;
        if (version == VERSION_2016_12_30) {
            upgradeFrom20161230to20170430(db);
            version = VERSION_2017_4_30;
        }
        if (version == VERSION_2017_4_30) {
            upgradeFrom20170430to20170524(db);
            version = VERSION_2017_5_24;
        }
        if (version == VERSION_2017_5_24) {
            upgradeFrom20170525to20170728(db);
            version = VERSION_2017_7_28;
        }
        if (version == VERSION_2017_7_28) {
            upgradeFrom20170728to20170811(db);
            version = VERSION_2017_8_11;
        }
        if (version != CUR_DATABASE_VERSION) {
            LogUtil.E(TAG, "Upgrade unsuccessful -- destroying old data during upgrade");

            db.execSQL("DROP TABLE IF EXISTS " + Tables.WALLPAPER);
            db.execSQL("DROP TABLE IF EXISTS " + Tables.GALLERY);
            onCreate(db);
            version = CUR_DATABASE_VERSION;
        }
    }

    private void upgradeFrom20161230to20170430(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE " + Tables.WALLPAPER
                + " ADD COLUMN " + Wallpaper.COLUMN_NAME_LIKED + " INTEGER NOT NULL DEFAULT 0");
        db.execSQL("ALTER TABLE " + Tables.WALLPAPER
                + " ADD COLUMN " + Wallpaper.COLUMN_NAME_CHECKSUM + " TEXT");
    }

    private void upgradeFrom20170430to20170524(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.GALLERY + " ("
                + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI + " TEXT NOT NULL,"
                + StyleContract.GalleryWallpaper.COLUMN_NAME_IS_TREE_URI + " INTEGER,"
                + StyleContract.GalleryWallpaper.COLUMN_NAME_DATE_TIME + " INTEGER,"
                + StyleContract.GalleryWallpaper.COLUMN_NAME_LOCATION + " TEXT,"
                + StyleContract.GalleryWallpaper.COLUMN_NAME_HAS_METADATA + " INTEGER DEFAULT 0,"
                + "UNIQUE (" + StyleContract.GalleryWallpaper.COLUMN_NAME_CUSTOM_URI
                + ") ON CONFLICT REPLACE);");
    }

    private void upgradeFrom20170525to20170728(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE " + Tables.ADVANCE_WALLPAPER + " ("
                + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
                + AdvanceWallpaper.COLUMN_NAME_WALLPAPER_ID + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_ICON_URL + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_DOWNLOAD_URL + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_NAME + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_AUTHOR + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_STORE_PATH + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_LINK + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_PROVIDER_NAME + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_CHECKSUM + " TEXT,"
                + AdvanceWallpaper.COLUMN_NAME_SELECTED + " INTEGER DEFAULT 0);");
    }

    private void upgradeFrom20170728to20170811(SQLiteDatabase db) {
        db.execSQL("ALTER TABLE " + Tables.ADVANCE_WALLPAPER
                + " ADD COLUMN " + AdvanceWallpaper.COLUMN_NAME_LAZY_DOWNLOAD
                + " INTEGER NOT NULL DEFAULT 0");
        db.execSQL("ALTER TABLE " + Tables.ADVANCE_WALLPAPER
                + " ADD COLUMN " + AdvanceWallpaper.COLUMN_NAME_NEED_AD
                + " INTEGER NOT NULL DEFAULT 0");
    }

    public static void deleteDatabase(Context context) {
        context.deleteDatabase(DATABASE_NAME);
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProvider.java
================================================
package com.yalin.style.data.repository.datasource.provider;

import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.provider.StyleContract.AdvanceWallpaper;
import com.yalin.style.data.repository.datasource.provider.StyleContract.GalleryWallpaper;
import com.yalin.style.data.repository.datasource.provider.StyleContract.Wallpaper;
import com.yalin.style.data.utils.SelectionBuilder;
import com.yalin.style.data.utils.WallpaperFileHelper;

import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * YaLin 2016/12/30.
 */

public class StyleProvider extends ContentProvider {

    private static final String TAG = "StyleProvider";

    private StyleDatabase mOpenHelper;

    private StyleProviderUriMatcher mUriMatcher;

    @Override
    public boolean onCreate() {
        mOpenHelper = new StyleDatabase(getContext());
        mUriMatcher = new StyleProviderUriMatcher();
        return true;
    }

    private void deleteDatabase() {
        mOpenHelper.close();
        Context context = getContext();
        StyleDatabase.deleteDatabase(context);
        mOpenHelper = new StyleDatabase(context);
    }

    @NonNull
    @Override
    public ContentProviderResult[] applyBatch(@NonNull ArrayList<ContentProviderOperation> operations)
            throws OperationApplicationException {
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        db.beginTransaction();
        try {
            final int numOperations = operations.size();
            final ContentProviderResult[] results = new ContentProviderResult[numOperations];
            for (int i = 0; i < numOperations; i++) {
                results[i] = operations.get(i).apply(this, results, i);
            }
            db.setTransactionSuccessful();
            return results;
        } finally {
            db.endTransaction();
        }
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, String[] projection, String selection,
                        String[] selectionArgs,
                        String sortOrder) {
        final SQLiteDatabase db = mOpenHelper.getReadableDatabase();

        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);

        LogUtil.D(TAG, "uri=" + uri + " code=" + uriEnum.code + " proj=" +
                Arrays.toString(projection) + " selection=" + selection + " args="
                + Arrays.toString(selectionArgs) + ")");

        switch (uriEnum) {
            case WALLPAPER:
            case WALLPAPER_ID:
            case WALLPAPER_LIKED:
            case ADVANCE_WALLPAPER:
            case ADVANCE_WALLPAPER_ID:
            case ADVANCE_WALLPAPER_SELECTED: {
                final SelectionBuilder builder = buildSimpleSelection(uri);
                return builder.query(db, projection, BaseColumns._ID + " DESC");
            }
            case GALLERY:
            case GALLERY_ID: {
                final SelectionBuilder builder = buildSimpleSelection(uri);
                return builder.query(db, projection, GalleryWallpaper._ID + " DESC");
            }
            default: {
                final SelectionBuilder builder = buildExpandedSelection(uri, uriEnum.code);

                return builder.query(db, projection, null);
            }
        }
    }

    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, ContentValues values) {
        LogUtil.D(TAG, "insert(uri=" + uri + ", values=" + values.toString()
                + ")");

        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);
        long id = db.insertOrThrow(uriEnum.table, null, values);

        switch (uriEnum) {
            case WALLPAPER:
                return StyleContract.Wallpaper.buildWallpaperUri(
                        values.getAsString(StyleContract.Wallpaper.COLUMN_NAME_WALLPAPER_ID));
            case GALLERY:
                return StyleContract.GalleryWallpaper.buildGalleryWallpaperUri(id);
            case ADVANCE_WALLPAPER: {
                return AdvanceWallpaper.buildWallpaperUri(
                        values.getAsString(AdvanceWallpaper.COLUMN_NAME_WALLPAPER_ID));
            }
            default: {
                throw new UnsupportedOperationException("Unknown insert uri: " + uri);
            }
        }
    }

    @Override
    public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
        LogUtil.D(TAG, "delete(uri=" + uri + ")");
        if (uri == StyleContract.BASE_CONTENT_URI) {
            deleteDatabase();
            return 1;
        }
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);
        final SelectionBuilder builder = buildSimpleSelection(uri);
        switch (uriEnum) {
            case WALLPAPER: {
                builder.where(Wallpaper.COLUMN_NAME_LIKED + " = ?", "0");
                break;
            }
            case ADVANCE_WALLPAPER: {
                builder.where(AdvanceWallpaper.COLUMN_NAME_SELECTED + " = ?", "0");
                break;
            }
            case GALLERY_URI: {
                return builder.delete(db);
            }
        }
        return builder.where(selection, selectionArgs).delete(db);
    }

    @Override
    public int update(@NonNull Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        LogUtil.D(TAG, "update(uri=" + uri + ")");
        if (uri == StyleContract.BASE_CONTENT_URI) {
            deleteDatabase();
            return 1;
        }
        final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        final SelectionBuilder builder = buildSimpleSelection(uri);
        return builder.where(selection, selectionArgs).update(db, values);
    }

    @Nullable
    @Override
    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode)
            throws FileNotFoundException {
        LogUtil.D(TAG, "openReadFile(uri=" + uri + ",mode=" + mode + ")");

        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);
        switch (uriEnum) {
            case WALLPAPER:
                return WallpaperFileHelper.openReadFile(getContext(), queryUriForShow(), mode);
            case WALLPAPER_ID:
                return WallpaperFileHelper.openReadFile(getContext(), uri, mode);
            case WALLPAPER_SAVE:
                return WallpaperFileHelper.openWriteFile(getContext(), uri, mode);
            default:
                throw new FileNotFoundException("Cannot match uri : " + uri);
        }
    }

    private Uri queryUriForShow() {
        Cursor cursor = query(Wallpaper.CONTENT_URI,
                new String[]{StyleContract.Wallpaper.COLUMN_NAME_IMAGE_URI},
                null, null, null);
        try {
            if (cursor != null && cursor.moveToFirst()) {
                return Uri.parse(cursor.getString(0));
            }
            return null;
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private SelectionBuilder buildSimpleSelection(Uri uri) {
        final SelectionBuilder builder = new SelectionBuilder();
        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);

        switch (uriEnum) {
            case WALLPAPER:
            case ADVANCE_WALLPAPER: {
                return builder.table(uriEnum.table);
            }
            case WALLPAPER_ID: {
                String wallpaperId = StyleContract.Wallpaper.getWallpaperId(uri);
                return builder.table(StyleDatabase.Tables.WALLPAPER)
                        .where(Wallpaper.COLUMN_NAME_WALLPAPER_ID + " = ?", wallpaperId);
            }
            case WALLPAPER_LIKE: {
                String wallpaperId = StyleContract.Wallpaper.getWallpaperLikeId(uri);
                return builder.table(StyleDatabase.Tables.WALLPAPER)
                        .where(Wallpaper.COLUMN_NAME_WALLPAPER_ID + " = ?", wallpaperId);
            }
            case WALLPAPER_LIKED: {
                return builder.table(StyleDatabase.Tables.WALLPAPER)
                        .where(Wallpaper.COLUMN_NAME_LIKED + " = ?", "1");
            }
            case GALLERY: {
                return builder.table(StyleDatabase.Tables.GALLERY);
            }
            case GALLERY_ID: {
                String galleryWallpaperId
                        = StyleContract.GalleryWallpaper.getGalleryWallpaperId(uri);
                return builder.table(StyleDatabase.Tables.GALLERY)
                        .where(GalleryWallpaper._ID + " = ?", galleryWallpaperId);
            }
            case GALLERY_URI: {
                String uriString
                        = StyleContract.GalleryWallpaper.getGalleryWallpaperDeleteUri(uri);
                return builder.table(StyleDatabase.Tables.GALLERY)
                        .where(GalleryWallpaper.COLUMN_NAME_CUSTOM_URI + " = ?", uriString);
            }
            case ADVANCE_WALLPAPER_ID: {
                String wallpaperId = AdvanceWallpaper.getWallpaperId(uri);
                return builder.table(StyleDatabase.Tables.ADVANCE_WALLPAPER)
                        .where(AdvanceWallpaper.COLUMN_NAME_WALLPAPER_ID + " = ?", wallpaperId);
            }
            case ADVANCE_WALLPAPER_SELECTED: {
                return builder.table(StyleDatabase.Tables.ADVANCE_WALLPAPER)
                        .where(AdvanceWallpaper.COLUMN_NAME_SELECTED + " = ?", String.valueOf(1));
            }
            default: {
                throw new UnsupportedOperationException("Unknown uri for " + uri);
            }
        }
    }

    private SelectionBuilder buildExpandedSelection(Uri uri, int match) {
        final SelectionBuilder builder = new SelectionBuilder();
        StyleUriEnum uriEnum = mUriMatcher.matchUri(uri);
        if (uriEnum == null) {
            throw new UnsupportedOperationException("Unknown uri: " + uri);
        }
        switch (uriEnum) {
            default: {
                throw new UnsupportedOperationException("Unknown uri: " + uri);
            }
        }
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProviderUriMatcher.java
================================================
package com.yalin.style.data.repository.datasource.provider;

import android.content.UriMatcher;
import android.net.Uri;
import android.util.SparseArray;

/**
 * YaLin 2016/12/30.
 */

public class StyleProviderUriMatcher {

  private UriMatcher mUriMatcher;

  private SparseArray<StyleUriEnum> mEnumsMap = new SparseArray<>();

  public StyleProviderUriMatcher() {
    mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    buildUriMatcher();
  }

  private void buildUriMatcher() {
    final String authority = StyleContract.AUTHORITY;

    StyleUriEnum[] uris = StyleUriEnum.values();
    for (StyleUriEnum uri : uris) {
      mUriMatcher.addURI(authority, uri.path, uri.code);
    }
    buildEnumsMap();
  }

  private void buildEnumsMap() {
    StyleUriEnum[] uris = StyleUriEnum.values();
    for (StyleUriEnum uri : uris) {
      mEnumsMap.put(uri.code, uri);
    }
  }

  public StyleUriEnum matchUri(Uri uri) {
    final int code = mUriMatcher.match(uri);
    try {
      return matchCode(code);
    } catch (UnsupportedOperationException e) {
      throw new UnsupportedOperationException("Unknown uri " + uri);
    }
  }

  public StyleUriEnum matchCode(int code) {
    StyleUriEnum uriEnum = mEnumsMap.get(code);
    if (uriEnum != null) {
      return uriEnum;
    } else {
      throw new UnsupportedOperationException("Unknown uri with code " + code);
    }
  }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleUriEnum.java
================================================
package com.yalin.style.data.repository.datasource.provider;

/**
 * YaLin 2016/12/30.
 */

public enum StyleUriEnum {
    WALLPAPER(100, "wallpaper", StyleDatabase.Tables.WALLPAPER),
    WALLPAPER_SAVE(103, "wallpaper/save/*", null),
    WALLPAPER_LIKE(104, "wallpaper/like/*", null),
    WALLPAPER_LIKED(105, "wallpaper/liked", null),
    WALLPAPER_ID(102, "wallpaper/*", null),

    GALLERY(200, "gallery", StyleDatabase.Tables.GALLERY),
    GALLERY_URI(202, "gallery/uri/*", null),
    GALLERY_ID(201, "gallery/*", null),

    ADVANCE_WALLPAPER(300, "advance_wallpaper", StyleDatabase.Tables.ADVANCE_WALLPAPER),
    ADVANCE_WALLPAPER_SELECTED(302, "advance_wallpaper/selected", null),
    ADVANCE_WALLPAPER_ID(301, "advance_wallpaper/*", null);


    public int code;
    public String path;
    public String table;

    StyleUriEnum(int code, String path, String table) {
        this.code = code;
        this.path = path;
        this.table = table;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/RemoteStyleDataFetcher.java
================================================
package com.yalin.style.data.repository.datasource.sync;

import android.content.Context;

import com.yalin.style.data.BuildConfig;
import com.yalin.style.data.repository.datasource.net.DataFetcher;

/**
 * YaLin 2017/1/3.
 */

public class RemoteStyleDataFetcher extends DataFetcher {


    public RemoteStyleDataFetcher(Context context) {
        super(context);
    }

    @Override
    protected String getUrl() {
        return BuildConfig.SERVER_WALLPAPER_ENDPOINT;
    }
}


================================================
FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/StyleDataHandler.java
================================================
package com.yalin.style.data.repository.datasource.sync;

import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;

import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;
import com.yalin.style.data.log.LogUtil;
import com.yalin.style.data.repository.datasource.io.AdvanceWallpaperHandler;
import com.yalin.style.data.repository.datasource.io.JSONHandler;
import com.yalin.style.data.repository.datasource.io.WallpapersHandler;
import com.yalin.style.data.repository.datasource.provider.StyleContract;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;

/**
 * YaLin 2017/1/3.
 */

public class StyleDataHandler {

    private static final String TAG = "StyleDataHandler";

    private static final String DATA_KEY_WALLPAPER = "wallpapers";
    private static final String DATA_KEY_ADVANCE_WALLPAPER = "advance_wallpapers";

    private static final String[] DATA_KEYS_IN_ORDER = {
            DATA_KEY_WALLPAPER,
            DATA_KEY_ADVANCE_WALLPAPER
    };

    Context mContext = null;

    WallpapersHandler mWallpapersHandler = null;
    AdvanceWallpaperHandler mAdvanceWallpapersHandler = null;

    HashMap<String, JSONHandler> mHandlerForKey = new HashMap<>();

    private int mContentProviderOperationsDone = 0;

    public StyleDataHandler(Context context) {
        mContext = context;
    }

    public void applyStyleData(String[] dataBodies) throws IOException {
        LogUtil.D(TAG, "Applying data from " + dataBodies.length + " files");

        mHandlerForKey.put(DATA_KEY_WALLPAPER, mWallpapersHandler = new WallpapersHandler(mContext));
        mHandlerForKey.put(DATA_KEY_ADVANCE_WALLPAPER,
                mAdvanceWallpapersHandler = new AdvanceWallpaperHandler(mContext));

        LogUtil.D(TAG, "Processing " + dataBodies.length + " JSON objects.");
        for (int i = 0; i < dataBodies.length; i++) {
            LogUtil.D(TAG, "Processing json object #" + (i + 1) + " of " + dataBodies.length);
            processDataBody(dataBodies[i]);
        }

        ArrayList<ContentProviderOperation> batch = new ArrayList<>();
        for (String key : DATA_KEYS_IN_ORDER) {
            LogUtil.D(TAG, "Building content provider operations for: " + key);
            mHandlerForKey.get(key).makeContentProviderOperations(batch);
            LogUtil.D(TAG, "Content provider operations so far: " + batch.size());
        }

        LogUtil.D(TAG, "Applying " + batch.size() + " content provider operations.");
        try {
            int operations = batch.size();
            if (operations > 0) {
                mContext.getContentResolver().applyBatch(StyleContract.AUTHORITY, batch);
            }
            LogUtil.D(TAG, "Successfully applied " + operations + " content provider operations.");
            mContentProviderOperationsDone += operations;
        } catch (RemoteException ex) {
            LogUtil.D(TAG, "RemoteException while applying content provider operations.");
            throw 
Download .txt
gitextract_vzylt4jg/

├── .gitignore
├── README.md
├── build.gradle
├── buildApk.bat
├── buildApk.sh
├── data/
│   ├── .gitignore
│   ├── CMakeLists.txt
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── data/
│       │                   └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── cpp/
│       │   │   └── facet_id-lib.cpp
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── data/
│       │   │                   ├── SyncConfig.java
│       │   │                   ├── cache/
│       │   │                   │   ├── AdvanceWallpaperCache.kt
│       │   │                   │   ├── AdvanceWallpaperCacheImpl.kt
│       │   │                   │   ├── GalleryWallpaperCache.kt
│       │   │                   │   ├── SourcesCache.kt
│       │   │                   │   ├── SourcesCacheImpl.kt
│       │   │                   │   ├── WallpaperCache.java
│       │   │                   │   └── WallpaperCacheImpl.java
│       │   │                   ├── entity/
│       │   │                   │   ├── AdvanceWallpaperEntity.java
│       │   │                   │   ├── DeviceInfo.java
│       │   │                   │   ├── GalleryWallpaperEntity.kt
│       │   │                   │   ├── HttpRequestBody.java
│       │   │                   │   ├── SourceEntity.kt
│       │   │                   │   ├── WallpaperEntity.java
│       │   │                   │   └── mapper/
│       │   │                   │       ├── AdvanceWallpaperEntityMapper.java
│       │   │                   │       └── WallpaperEntityMapper.java
│       │   │                   ├── exception/
│       │   │                   │   ├── LikeException.java
│       │   │                   │   ├── NetworkConnectionException.java
│       │   │                   │   ├── NoContentException.java
│       │   │                   │   ├── RemoteServerException.java
│       │   │                   │   └── ReswitchException.java
│       │   │                   ├── executor/
│       │   │                   │   ├── JobExecutor.java
│       │   │                   │   └── SerialJobExecutor.java
│       │   │                   ├── extensions/
│       │   │                   │   └── DelegateExt.kt
│       │   │                   ├── lock/
│       │   │                   │   ├── LikeWallpaperLock.java
│       │   │                   │   ├── OpenInputStreamLock.java
│       │   │                   │   ├── ResourceLock.java
│       │   │                   │   └── SelectSourceLock.java
│       │   │                   ├── log/
│       │   │                   │   └── LogUtil.java
│       │   │                   ├── observable/
│       │   │                   │   ├── SourcesObservableImpl.kt
│       │   │                   │   └── WallpaperObservableImpl.kt
│       │   │                   ├── repository/
│       │   │                   │   ├── AdvanceWallpaperDataRepository.kt
│       │   │                   │   ├── GalleryWallpaperDataRepository.kt
│       │   │                   │   ├── SourcesDataRepository.kt
│       │   │                   │   ├── StyleWallpaperDataRepository.java
│       │   │                   │   └── datasource/
│       │   │                   │       ├── AdvanceWallpaperDataStore.kt
│       │   │                   │       ├── AdvanceWallpaperDataStoreFactory.kt
│       │   │                   │       ├── AdvanceWallpaperDataStoreImpl.kt
│       │   │                   │       ├── CacheWallpaperDataStore.java
│       │   │                   │       ├── DbWallpaperDataStore.java
│       │   │                   │       ├── GalleryWallpaperDataStore.kt
│       │   │                   │       ├── GalleryWallpaperDataStoreFactory.kt
│       │   │                   │       ├── RemoteAdvanceWallpaperDataStore.kt
│       │   │                   │       ├── SourcesDataStore.kt
│       │   │                   │       ├── SourcesDataStoreFactory.kt
│       │   │                   │       ├── SourcesDataStoreImpl.kt
│       │   │                   │       ├── StyleWallpaperDataStoreFactory.java
│       │   │                   │       ├── WallpaperDataStore.java
│       │   │                   │       ├── io/
│       │   │                   │       │   ├── AdvanceWallpaperHandler.kt
│       │   │                   │       │   ├── GalleryWallpapersHandler.kt
│       │   │                   │       │   ├── JSONHandler.java
│       │   │                   │       │   ├── RemoveGalleryWallpapersHandler.kt
│       │   │                   │       │   └── WallpapersHandler.java
│       │   │                   │       ├── net/
│       │   │                   │       │   ├── DataFetcher.java
│       │   │                   │       │   └── RemoteAdvanceWallpaperFetcher.java
│       │   │                   │       ├── provider/
│       │   │                   │       │   ├── StyleContract.java
│       │   │                   │       │   ├── StyleContractHelper.java
│       │   │                   │       │   ├── StyleDatabase.java
│       │   │                   │       │   ├── StyleProvider.java
│       │   │                   │       │   ├── StyleProviderUriMatcher.java
│       │   │                   │       │   └── StyleUriEnum.java
│       │   │                   │       └── sync/
│       │   │                   │           ├── RemoteStyleDataFetcher.java
│       │   │                   │           ├── StyleDataHandler.java
│       │   │                   │           ├── SyncAdapter.java
│       │   │                   │           ├── SyncHelper.java
│       │   │                   │           ├── SyncService.java
│       │   │                   │           ├── account/
│       │   │                   │           │   ├── Account.java
│       │   │                   │           │   ├── Authenticator.java
│       │   │                   │           │   └── AuthenticatorService.java
│       │   │                   │           └── gallery/
│       │   │                   │               └── GalleryScheduleService.kt
│       │   │                   └── utils/
│       │   │                       ├── ChecksumUtil.java
│       │   │                       ├── DeviceUtil.java
│       │   │                       ├── FacetIdUtil.java
│       │   │                       ├── HttpRequestUtil.java
│       │   │                       ├── NativeFileHelper.kt
│       │   │                       ├── NetworkUtil.java
│       │   │                       ├── SelectionBuilder.java
│       │   │                       ├── TimeUtil.java
│       │   │                       ├── UriUtil.kt
│       │   │                       ├── WallpaperFileHelper.java
│       │   │                       └── WallpaperUtil.kt
│       │   └── res/
│       │       ├── values/
│       │       │   └── strings.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── authenticator.xml
│       │           └── syncadapter.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── data/
│                           └── ExampleUnitTest.java
├── domain/
│   ├── .gitignore
│   ├── build.gradle
│   └── src/
│       └── main/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── domain/
│                               ├── AdvanceWallpaper.java
│                               ├── GalleryWallpaper.java
│                               ├── Source.java
│                               ├── Wallpaper.java
│                               ├── exception/
│                               │   ├── DefaultErrorBundle.java
│                               │   └── ErrorBundle.java
│                               ├── executor/
│                               │   ├── PostExecutionThread.java
│                               │   ├── SerialThreadExecutor.java
│                               │   └── ThreadExecutor.java
│                               ├── interactor/
│                               │   ├── AddGalleryWallpaper.java
│                               │   ├── DefaultObserver.java
│                               │   ├── DownloadAdvanceWallpaper.java
│                               │   ├── ForceNow.java
│                               │   ├── GetAdvanceWallpapers.java
│                               │   ├── GetGalleryUpdateInterval.java
│                               │   ├── GetGalleryWallpaper.java
│                               │   ├── GetSelectedAdvanceWallpaper.java
│                               │   ├── GetSelectedSource.java
│                               │   ├── GetSources.java
│                               │   ├── GetWallpaper.java
│                               │   ├── GetWallpaperCount.java
│                               │   ├── LikeWallpaper.java
│                               │   ├── LoadAdvanceWallpaper.java
│                               │   ├── ObserverSources.java
│                               │   ├── ObserverWallpaper.java
│                               │   ├── OpenWallpaperInputStream.java
│                               │   ├── ReadAdvanceAd.java
│                               │   ├── RemoveGalleryWallpaper.java
│                               │   ├── SelectAdvanceWallpaper.java
│                               │   ├── SelectSource.java
│                               │   ├── SetGalleryUpdateInterval.java
│                               │   ├── SwitchWallpaper.java
│                               │   └── UseCase.java
│                               ├── observable/
│                               │   ├── SourcesObservable.java
│                               │   └── WallpaperObservable.java
│                               └── repository/
│                                   ├── SourcesRepository.java
│                                   └── WallpaperRepository.java
├── engine/
│   ├── .gitignore
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── style/
│       │                   └── engine/
│       │                       └── ExampleInstrumentedTest.java
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   ├── com/
│       │   │   │   └── yalin/
│       │   │   │       └── style/
│       │   │   │           └── engine/
│       │   │   │               ├── GDXWallpaperServiceProxy.kt
│       │   │   │               ├── GLWallpaperServiceProxy.kt
│       │   │   │               ├── IProvider.java
│       │   │   │               ├── ProxyApi.java
│       │   │   │               ├── ProxyProvider.kt
│       │   │   │               ├── WallpaperActiveCallback.kt
│       │   │   │               ├── WallpaperServiceProxy.kt
│       │   │   │               ├── advance/
│       │   │   │               │   ├── AnimationWallpaper.java
│       │   │   │               │   ├── BokehRainbowCircle.java
│       │   │   │               │   └── BokehRainbowWallpaper.java
│       │   │   │               ├── component/
│       │   │   │               │   ├── ComponentContext.java
│       │   │   │               │   └── StyleClassLoader.kt
│       │   │   │               └── resource/
│       │   │   │                   ├── BrandUtil.java
│       │   │   │                   ├── CompatResources.java
│       │   │   │                   ├── ReflectUtil.java
│       │   │   │                   └── ResourcesManager.java
│       │   │   └── net/
│       │   │       └── rbgrn/
│       │   │           └── android/
│       │   │               └── glwallpaperservice/
│       │   │                   ├── BaseConfigChooser.java
│       │   │                   └── GLWallpaperService.java
│       │   └── res/
│       │       └── values/
│       │           └── strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── engine/
│                               └── ExampleUnitTest.java
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── presentation/
│   ├── .gitignore
│   ├── build.gradle
│   ├── component-proguard.pro
│   ├── google-services.json
│   ├── proguard-rules.pro
│   └── src/
│       ├── androidTest/
│       │   └── java/
│       │       └── com/
│       │           └── yalin/
│       │               └── style/
│       │                   ├── ExampleInstrumentedTest.java
│       │                   ├── provider/
│       │                   │   └── DatabaseTest.java
│       │                   └── sync/
│       │                       └── SyncAdapterTest.java
│       ├── demo/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── util/
│       │   │                   └── AdUtil.kt
│       │   └── res/
│       │       └── values/
│       │           └── ad_strings.xml
│       ├── main/
│       │   ├── AndroidManifest.xml
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               ├── LockScreenVisibleReceiver.kt
│       │   │               ├── StyleApplication.kt
│       │   │               ├── StyleWallpaperService.kt
│       │   │               ├── StyleWallpaperServiceMirror.kt
│       │   │               ├── UIThread.kt
│       │   │               ├── WallpaperDetailViewport.kt
│       │   │               ├── analytics/
│       │   │               │   ├── Analytics.kt
│       │   │               │   ├── Event.kt
│       │   │               │   └── IAnalytics.kt
│       │   │               ├── engine/
│       │   │               │   └── StyleWallpaperProxy.kt
│       │   │               ├── event/
│       │   │               │   ├── MainContainerInsetsChangedEvent.java
│       │   │               │   ├── SeenTutorialEvent.java
│       │   │               │   ├── StyleWallpaperSizeChangedEvent.java
│       │   │               │   ├── SwitchWallpaperServiceEvent.java
│       │   │               │   ├── SwitchingPhotosStateChangedEvent.java
│       │   │               │   ├── SystemWallpaperSizeChangedEvent.java
│       │   │               │   ├── WallpaperActivateEvent.java
│       │   │               │   ├── WallpaperDetailOpenedEvent.java
│       │   │               │   └── WallpaperSwitchEvent.java
│       │   │               ├── exception/
│       │   │               │   └── ErrorMessageFactory.java
│       │   │               ├── extensions/
│       │   │               │   └── DelegatesExtensions.kt
│       │   │               ├── injection/
│       │   │               │   ├── HasComponent.kt
│       │   │               │   ├── PerActivity.kt
│       │   │               │   ├── component/
│       │   │               │   │   ├── ApplicationComponent.kt
│       │   │               │   │   ├── SourceComponent.kt
│       │   │               │   │   └── WallpaperComponent.kt
│       │   │               │   └── modules/
│       │   │               │       ├── ApplicationModule.kt
│       │   │               │       ├── SourceModule.kt
│       │   │               │       └── WallpaperModule.kt
│       │   │               ├── mapper/
│       │   │               │   ├── AdvanceWallpaperItemMapper.kt
│       │   │               │   └── WallpaperItemMapper.kt
│       │   │               ├── model/
│       │   │               │   ├── AdvanceWallpaperItem.java
│       │   │               │   ├── GalleryWallpaperItem.java
│       │   │               │   ├── SourceItem.kt
│       │   │               │   └── WallpaperItem.java
│       │   │               ├── presenter/
│       │   │               │   ├── AdvanceSettingPresenter.kt
│       │   │               │   ├── GallerySettingPresenter.kt
│       │   │               │   ├── Presenter.kt
│       │   │               │   ├── SettingsChooseSourcePresenter.kt
│       │   │               │   └── WallpaperDetailPresenter.kt
│       │   │               ├── render/
│       │   │               │   ├── BitmapRegionLoader.java
│       │   │               │   ├── DemoRenderController.kt
│       │   │               │   ├── GLColorOverlay.java
│       │   │               │   ├── GLPicture.java
│       │   │               │   ├── GLTextureView.java
│       │   │               │   ├── GLUtil.java
│       │   │               │   ├── ImageBlurrer.java
│       │   │               │   ├── ImageUtil.java
│       │   │               │   ├── RenderController.kt
│       │   │               │   ├── StyleBlurRenderer.java
│       │   │               │   └── TickingFloatAnimator.java
│       │   │               ├── settings/
│       │   │               │   └── Prefs.java
│       │   │               ├── util/
│       │   │               │   ├── ImageLoader.java
│       │   │               │   ├── MathUtil.java
│       │   │               │   ├── MultiSelectionController.kt
│       │   │               │   ├── ScrimUtil.java
│       │   │               │   ├── SettingsUtil.java
│       │   │               │   ├── ShareUtil.kt
│       │   │               │   ├── SvgPathParser.java
│       │   │               │   └── TypefaceUtil.java
│       │   │               └── view/
│       │   │                   ├── AdvanceSettingView.kt
│       │   │                   ├── GallerySettingView.kt
│       │   │                   ├── LoadingDataView.kt
│       │   │                   ├── SourceChooseView.kt
│       │   │                   ├── WallpaperDetailView.kt
│       │   │                   ├── activity/
│       │   │                   │   ├── AboutActivity.kt
│       │   │                   │   ├── AdvanceSettingActivity.kt
│       │   │                   │   ├── BaseActivity.kt
│       │   │                   │   ├── GallerySettingActivity.kt
│       │   │                   │   ├── SettingsActivity.kt
│       │   │                   │   └── StyleActivity.kt
│       │   │                   ├── component/
│       │   │                   │   ├── CircleProgressView.java
│       │   │                   │   ├── DownloadingDialog.kt
│       │   │                   │   ├── DrawInsetsFrameLayout.java
│       │   │                   │   ├── GalleryEmptyStateGraphicView.kt
│       │   │                   │   ├── ObservableHorizontalScrollView.kt
│       │   │                   │   ├── PanScaleProxyView.java
│       │   │                   │   ├── Scrollbar.kt
│       │   │                   │   ├── ShadowDipsTextView.kt
│       │   │                   │   ├── TintableImageButton.kt
│       │   │                   │   └── Zoomer.kt
│       │   │                   └── fragment/
│       │   │                       ├── AnimatedStyleLogoFragment.kt
│       │   │                       ├── BaseFragment.kt
│       │   │                       ├── SettingsAdvanceFragment.kt
│       │   │                       ├── SettingsChooseSourceFragment.kt
│       │   │                       ├── StyleRenderFragment.java
│       │   │                       ├── TutorialFragment.kt
│       │   │                       └── WallpaperDetailFragment.kt
│       │   └── res/
│       │       ├── anim/
│       │       │   └── image_fade_in.xml
│       │       ├── anim-v21/
│       │       │   └── tutorial_icon_emanate_interpolator.xml
│       │       ├── animator/
│       │       │   ├── fade_in.xml
│       │       │   ├── fade_out.xml
│       │       │   ├── tutorial_icon_emanate_wave1.xml
│       │       │   ├── tutorial_icon_emanate_wave1_path.xml
│       │       │   ├── tutorial_icon_emanate_wave2.xml
│       │       │   ├── tutorial_icon_emanate_wave2_path.xml
│       │       │   └── tutorial_icon_overlay_state_list.xml
│       │       ├── color/
│       │       │   └── selector_skip_tint.xml
│       │       ├── drawable/
│       │       │   ├── gallery_ic_add.xml
│       │       │   ├── gallery_ic_add_folder.xml
│       │       │   ├── gallery_ic_add_photo.xml
│       │       │   ├── gallery_ic_folder.xml
│       │       │   ├── grey_selectable_item_background_circle.xml
│       │       │   ├── intro_background_protection.xml
│       │       │   ├── popup_background.xml
│       │       │   ├── scrubber_control_selector.xml
│       │       │   ├── scrubber_progress_blur_amount.xml
│       │       │   ├── scrubber_progress_dim_amount.xml
│       │       │   ├── scrubber_progress_grey_amount.xml
│       │       │   ├── scrubber_progress_horizontal.xml
│       │       │   ├── settings_source_item_image_overlay.xml
│       │       │   ├── tutorial_icon_on_overlay.xml
│       │       │   └── white_circle_button.xml
│       │       ├── drawable-v21/
│       │       │   ├── avd_tutorial_icon_emanate.xml
│       │       │   ├── grey_selectable_item_background_circle.xml
│       │       │   ├── settings_source_item_image_overlay.xml
│       │       │   ├── tutorial_icon_emanate.xml
│       │       │   └── tutorial_icon_on_overlay.xml
│       │       ├── layout/
│       │       │   ├── activity_about.xml
│       │       │   ├── activity_advance_setting.xml
│       │       │   ├── activity_gallery_setting.xml
│       │       │   ├── activity_main.xml
│       │       │   ├── activity_settings.xml
│       │       │   ├── advance_chosen_wallpaper_item.xml
│       │       │   ├── animated_logo_fragment.xml
│       │       │   ├── dialog_downloading.xml
│       │       │   ├── gallery_chosen_photo_item.xml
│       │       │   ├── gallery_chosen_photo_tree_item.xml
│       │       │   ├── layout_include_about_content.xml
│       │       │   ├── layout_include_active.xml
│       │       │   ├── layout_include_settings_content.xml
│       │       │   ├── layout_include_tutorial_content.xml
│       │       │   ├── layout_include_wallpaper_detail.xml
│       │       │   ├── layout_include_wallpaper_tutorial.xml
│       │       │   ├── layout_settings_choose_source.xml
│       │       │   ├── layout_style_settings.xml
│       │       │   ├── layout_wallpaper_detail.xml
│       │       │   ├── settings_ab_spinner_list_item.xml
│       │       │   ├── settings_ab_spinner_list_item_dropdown.xml
│       │       │   └── settings_choose_source_item.xml
│       │       ├── menu/
│       │       │   ├── advance_activity.xml
│       │       │   ├── gallery_activity.xml
│       │       │   ├── gallery_selection.xml
│       │       │   ├── menu_settings.xml
│       │       │   ├── menu_settings_advanced.xml
│       │       │   └── style_overflow.xml
│       │       ├── values/
│       │       │   ├── attrs.xml
│       │       │   ├── colors.xml
│       │       │   ├── dimens.xml
│       │       │   ├── ids.xml
│       │       │   ├── integers.xml
│       │       │   ├── strings.xml
│       │       │   └── styles.xml
│       │       ├── values-v19/
│       │       │   └── styles.xml
│       │       ├── values-v21/
│       │       │   └── styles.xml
│       │       ├── values-w820dp/
│       │       │   └── dimens.xml
│       │       ├── values-zh-rCN/
│       │       │   └── strings.xml
│       │       └── xml/
│       │           ├── shortcuts.xml
│       │           └── wallpaper.xml
│       ├── production/
│       │   ├── java/
│       │   │   └── com/
│       │   │       └── yalin/
│       │   │           └── style/
│       │   │               └── util/
│       │   │                   └── AdUtil.kt
│       │   └── res/
│       │       └── values/
│       │           └── ad_strings.xml
│       └── test/
│           └── java/
│               └── com/
│                   └── yalin/
│                       └── style/
│                           └── ExampleUnitTest.java
├── settings.gradle
└── switch.properties
Download .txt
SYMBOL INDEX (1055 symbols across 143 files)

FILE: data/src/androidTest/java/com/yalin/data/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: data/src/main/cpp/facet_id-lib.cpp
  function jboolean (line 18) | jboolean
  function jstring (line 28) | jstring
  function jstring (line 34) | jstring get_facet_id(JNIEnv *env, jobject context, jint uId) {
  function check_facet_id (line 163) | int check_facet_id(JNIEnv *env, jstring facet_id) {
  function printLog (line 185) | void printLog(const char *str) {

FILE: data/src/main/java/com/yalin/style/data/SyncConfig.java
  class SyncConfig (line 9) | public class SyncConfig {

FILE: data/src/main/java/com/yalin/style/data/cache/WallpaperCache.java
  type WallpaperCache (line 14) | public interface WallpaperCache {
    method get (line 21) | Observable<WallpaperEntity> get();
    method getNext (line 23) | Observable<WallpaperEntity> getNext();
    method getWallpaperCount (line 25) | Observable<Integer> getWallpaperCount();
    method likeWallpaper (line 27) | void likeWallpaper(String wallpaperId);
    method put (line 29) | void put(Queue<WallpaperEntity> wallpaperEntities);
    method isCached (line 31) | boolean isCached();
    method isCached (line 33) | boolean isCached(String wallpaperId);
    method isDirty (line 35) | boolean isDirty();
    method evictAll (line 37) | void evictAll();

FILE: data/src/main/java/com/yalin/style/data/cache/WallpaperCacheImpl.java
  class WallpaperCacheImpl (line 19) | @Singleton
    method WallpaperCacheImpl (line 24) | @Inject
    method get (line 28) | @Override
    method getNext (line 38) | @Override
    method getWallpaperCount (line 50) | @Override
    method likeWallpaper (line 59) | @Override
    method put (line 70) | @Override
    method isCached (line 75) | @Override
    method isCached (line 80) | @Override
    method isDirty (line 93) | @Override
    method evictAll (line 98) | @Override
    method get (line 106) | private WallpaperEntity get(String wallpaperId) {

FILE: data/src/main/java/com/yalin/style/data/entity/AdvanceWallpaperEntity.java
  class AdvanceWallpaperEntity (line 19) | public class AdvanceWallpaperEntity {
    method readCursor (line 41) | public static List<AdvanceWallpaperEntity> readCursor(Cursor cursor) {
    method readEntityFromCursor (line 59) | public static AdvanceWallpaperEntity readEntityFromCursor(Cursor curso...
    method equals (line 92) | @Override
    method hashCode (line 103) | @Override

FILE: data/src/main/java/com/yalin/style/data/entity/DeviceInfo.java
  class DeviceInfo (line 10) | public class DeviceInfo {
    method DeviceInfo (line 21) | public DeviceInfo(int sdkVersion, String androidId, String manufacturer,
    method getSdkVersion (line 34) | public int getSdkVersion() {
    method getAndroidId (line 38) | public String getAndroidId() {
    method getManufacturer (line 42) | public String getManufacturer() {
    method getModel (line 46) | public String getModel() {
    method getType (line 50) | public String getType() {

FILE: data/src/main/java/com/yalin/style/data/entity/HttpRequestBody.java
  class HttpRequestBody (line 12) | public class HttpRequestBody {
    method HttpRequestBody (line 16) | public HttpRequestBody(Context context, DeviceInfo deviceInfo) {
    method getDeviceInfo (line 21) | public DeviceInfo getDeviceInfo() {

FILE: data/src/main/java/com/yalin/style/data/entity/WallpaperEntity.java
  class WallpaperEntity (line 20) | public class WallpaperEntity {
    method WallpaperEntity (line 37) | public WallpaperEntity() {
    method readCursor (line 40) | public static List<WallpaperEntity> readCursor(Context context, Cursor...
    method readEntityFromCursor (line 61) | public static WallpaperEntity readEntityFromCursor(Cursor cursor) {
    method equals (line 84) | @Override
    method hashCode (line 95) | @Override

FILE: data/src/main/java/com/yalin/style/data/entity/mapper/AdvanceWallpaperEntityMapper.java
  class AdvanceWallpaperEntityMapper (line 18) | @Singleton
    method AdvanceWallpaperEntityMapper (line 20) | @Inject
    method transform (line 25) | public AdvanceWallpaper transform(AdvanceWallpaperEntity wallpaperEnti...
    method transformList (line 45) | public List<AdvanceWallpaper> transformList(List<AdvanceWallpaperEntit...
    method mapToWallpaper (line 54) | public Wallpaper mapToWallpaper(AdvanceWallpaperEntity wallpaperEntity) {

FILE: data/src/main/java/com/yalin/style/data/entity/mapper/WallpaperEntityMapper.java
  class WallpaperEntityMapper (line 21) | @Singleton
    method WallpaperEntityMapper (line 24) | @Inject
    method transform (line 28) | public Wallpaper transform(WallpaperEntity wallpaperEntity) {
    method transformSources (line 42) | public List<Source> transformSources(List<SourceEntity> sourceEntities) {
    method transformSource (line 51) | public Source transformSource(SourceEntity sourceEntity) {
    method transformGalleryWallpaper (line 64) | public List<GalleryWallpaper> transformGalleryWallpaper(
    method transformGalleryWallpaper (line 75) | public GalleryWallpaper transformGalleryWallpaper(

FILE: data/src/main/java/com/yalin/style/data/exception/LikeException.java
  class LikeException (line 8) | public class LikeException extends Exception {
    method LikeException (line 9) | public LikeException() {
    method LikeException (line 13) | public LikeException(final Throwable cause) {

FILE: data/src/main/java/com/yalin/style/data/exception/NetworkConnectionException.java
  class NetworkConnectionException (line 8) | public class NetworkConnectionException extends Exception {
    method NetworkConnectionException (line 9) | public NetworkConnectionException() {
    method NetworkConnectionException (line 13) | public NetworkConnectionException(final Throwable cause) {

FILE: data/src/main/java/com/yalin/style/data/exception/NoContentException.java
  class NoContentException (line 8) | public class NoContentException extends Exception {

FILE: data/src/main/java/com/yalin/style/data/exception/RemoteServerException.java
  class RemoteServerException (line 8) | public class RemoteServerException extends Exception {

FILE: data/src/main/java/com/yalin/style/data/exception/ReswitchException.java
  class ReswitchException (line 8) | public class ReswitchException extends Exception {
    method ReswitchException (line 9) | public ReswitchException() {
    method ReswitchException (line 13) | public ReswitchException(final Throwable cause) {

FILE: data/src/main/java/com/yalin/style/data/executor/JobExecutor.java
  class JobExecutor (line 19) | @Singleton
    method JobExecutor (line 23) | @Inject
    method execute (line 29) | @Override
    class JobThreadFactory (line 34) | private static class JobThreadFactory implements ThreadFactory {
      method newThread (line 37) | @Override

FILE: data/src/main/java/com/yalin/style/data/executor/SerialJobExecutor.java
  class SerialJobExecutor (line 17) | @Singleton
    method SerialJobExecutor (line 22) | @Inject
    method execute (line 27) | @Override
    method scheduleNext (line 41) | protected synchronized void scheduleNext() {

FILE: data/src/main/java/com/yalin/style/data/lock/LikeWallpaperLock.java
  class LikeWallpaperLock (line 19) | @Singleton
    method LikeWallpaperLock (line 22) | @Inject
    method appendDelay (line 27) | @Override

FILE: data/src/main/java/com/yalin/style/data/lock/OpenInputStreamLock.java
  class OpenInputStreamLock (line 16) | @Singleton
    method OpenInputStreamLock (line 19) | @Inject
    method appendDelay (line 24) | @Override

FILE: data/src/main/java/com/yalin/style/data/lock/ResourceLock.java
  class ResourceLock (line 16) | public abstract class ResourceLock {
    method ResourceLock (line 23) | public ResourceLock(ThreadExecutor threadExecutor) {
    method obtain (line 27) | public synchronized boolean obtain() {
    method release (line 36) | public synchronized void release() {
    method appendDelay (line 50) | protected Observable<Void> appendDelay(Observable<Void> observable) {

FILE: data/src/main/java/com/yalin/style/data/lock/SelectSourceLock.java
  class SelectSourceLock (line 16) | @Singleton
    method SelectSourceLock (line 19) | @Inject
    method appendDelay (line 24) | @Override

FILE: data/src/main/java/com/yalin/style/data/log/LogUtil.java
  class LogUtil (line 20) | public class LogUtil {
    method isExternalLogEnabled (line 26) | public static synchronized boolean isExternalLogEnabled() {
    method F (line 34) | public static void F(String tag, String msg, Throwable throwable) {
    method F (line 45) | public static void F(String tag, String msg) {
    method E (line 60) | public static void E(String tag, String msg, Throwable throwable) {
    method E (line 71) | public static void E(String tag, String msg) {
    method D (line 80) | public static void D(String tag, String msg) {
    method getProcessInfo (line 89) | private static String getProcessInfo() {
    method writeLog (line 94) | private static synchronized void writeLog(String tag, String msg) {
    method internalWriteLog (line 98) | private static synchronized void internalWriteLog(String filename, Str...
    method getCurrentTime (line 121) | private static String getCurrentTime() {

FILE: data/src/main/java/com/yalin/style/data/repository/StyleWallpaperDataRepository.java
  class StyleWallpaperDataRepository (line 30) | @Singleton
    method StyleWallpaperDataRepository (line 37) | @Inject
    method getWallpaper (line 49) | @Override
    method switchWallpaper (line 55) | @Override
    method openInputStream (line 61) | @Override
    method getWallpaperCount (line 68) | @Override
    method likeWallpaper (line 74) | @Override
    method addGalleryWallpaperUris (line 81) | @Override
    method removeGalleryWallpaperUris (line 89) | @Override
    method getGalleryWallpapers (line 97) | @Override
    method getAdvanceWallpapers (line 105) | @Override
    method loadAdvanceWallpapers (line 113) | @Override
    method downloadAdvanceWallpaper (line 121) | @Override
    method selectAdvanceWallpaper (line 129) | @Override
    method getAdvanceWallpaper (line 137) | public AdvanceWallpaper getAdvanceWallpaper() {
    method readAdvanceAd (line 142) | @Override
    method foreNow (line 148) | @Override
    method setGalleryUpdateInterval (line 156) | @Override
    method getGalleryUpdateInterval (line 164) | @Override

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/CacheWallpaperDataStore.java
  class CacheWallpaperDataStore (line 18) | public class CacheWallpaperDataStore implements WallpaperDataStore {
    method CacheWallpaperDataStore (line 23) | public CacheWallpaperDataStore(WallpaperCache wallpaperCache,
    method getWallPaperEntity (line 29) | @Override
    method switchWallPaperEntity (line 34) | @Override
    method openInputStream (line 45) | @Override
    method getWallpaperCount (line 50) | @Override
    method likeWallpaper (line 55) | @Override

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/DbWallpaperDataStore.java
  class DbWallpaperDataStore (line 30) | public class DbWallpaperDataStore implements WallpaperDataStore {
    method DbWallpaperDataStore (line 42) | public DbWallpaperDataStore(Context context, WallpaperCache wallpaperC...
    method getWallPaperEntity (line 51) | @Override
    method switchWallPaperEntity (line 56) | @Override
    method openInputStream (line 61) | @Override
    method getWallpaperCount (line 84) | @Override
    method likeWallpaper (line 102) | @Override
    method createEntitiesObservable (line 139) | private Observable<Queue<WallpaperEntity>> createEntitiesObservable() {
    method buildDefaultWallpaper (line 166) | public static WallpaperEntity buildDefaultWallpaper() {
    method buildKeepContentValue (line 180) | private ContentValues buildKeepContentValue(WallpaperEntity entity) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/StyleWallpaperDataStoreFactory.java
  class StyleWallpaperDataStoreFactory (line 19) | @Singleton
    method StyleWallpaperDataStoreFactory (line 27) | @Inject
    method create (line 37) | public WallpaperDataStore create() {
    method createDbDataStore (line 47) | public WallpaperDataStore createDbDataStore() {
    method onDataRefresh (line 52) | public void onDataRefresh() {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/WallpaperDataStore.java
  type WallpaperDataStore (line 14) | public interface WallpaperDataStore {
    method getWallPaperEntity (line 16) | Observable<WallpaperEntity> getWallPaperEntity();
    method switchWallPaperEntity (line 18) | Observable<WallpaperEntity> switchWallPaperEntity();
    method openInputStream (line 20) | Observable<InputStream> openInputStream(String wallpaperId);
    method getWallpaperCount (line 22) | Observable<Integer> getWallpaperCount();
    method likeWallpaper (line 24) | Observable<Boolean> likeWallpaper(String wallpaperId);

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/JSONHandler.java
  class JSONHandler (line 20) | public abstract class JSONHandler {
    method JSONHandler (line 24) | public JSONHandler(Context context) {
    method makeContentProviderOperations (line 28) | public abstract void makeContentProviderOperations(ArrayList<ContentPr...
    method process (line 30) | public abstract void process(JsonElement element);
    method parseResource (line 38) | public static String parseResource(Context context, int resource) thro...
    method parseStream (line 58) | private static String parseStream(final InputStream stream) throws IOE...

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/io/WallpapersHandler.java
  class WallpapersHandler (line 37) | public class WallpapersHandler extends JSONHandler {
    method WallpapersHandler (line 43) | public WallpapersHandler(Context context) {
    method makeContentProviderOperations (line 47) | @Override
    method process (line 70) | @Override
    method getWallpaperIdSet (line 77) | private Set<String> getWallpaperIdSet(List<WallpaperEntity> entities) {
    method queryKeepedWallpapers (line 85) | private List<WallpaperEntity> queryKeepedWallpapers() {
    method outputWallpaper (line 98) | private void outputWallpaper(WallpaperEntity wallpaper,
    method downloadWallpaper (line 114) | private boolean downloadWallpaper(WallpaperEntity wallpaper, Uri uri) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/net/DataFetcher.java
  class DataFetcher (line 26) | public abstract class DataFetcher {
    method DataFetcher (line 33) | public DataFetcher(Context context) {
    method fetchDataIfNewer (line 38) | public String fetchDataIfNewer() throws IOException {
    method getUrl (line 73) | protected abstract String getUrl();

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/net/RemoteAdvanceWallpaperFetcher.java
  class RemoteAdvanceWallpaperFetcher (line 13) | public class RemoteAdvanceWallpaperFetcher extends DataFetcher {
    method RemoteAdvanceWallpaperFetcher (line 15) | public RemoteAdvanceWallpaperFetcher(Context context) {
    method getUrl (line 20) | protected String getUrl() {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContract.java
  class StyleContract (line 10) | public class StyleContract {
    type WallpaperColumns (line 16) | interface WallpaperColumns {
    type GalleryColumns (line 52) | interface GalleryColumns {
    type AdvanceWallpaperColumns (line 80) | interface AdvanceWallpaperColumns {
    class Source (line 144) | public static final class Source {
    class Wallpaper (line 150) | public static final class Wallpaper implements WallpaperColumns, BaseC...
      method buildWallpaperUri (line 165) | public static Uri buildWallpaperUri(String wallpaperId) {
      method buildWallpaperSaveUri (line 169) | public static Uri buildWallpaperSaveUri(String wallpaperId) {
      method buildWallpaperLikeUri (line 174) | public static Uri buildWallpaperLikeUri(String wallpaperId) {
      method getWallpaperId (line 180) | public static String getWallpaperId(Uri uri) {
      method getWallpaperSaveId (line 184) | public static String getWallpaperSaveId(Uri uri) {
      method getWallpaperLikeId (line 188) | public static String getWallpaperLikeId(Uri uri) {
    class GalleryWallpaper (line 193) | public static final class GalleryWallpaper implements GalleryColumns, ...
      method buildGalleryWallpaperUri (line 202) | public static Uri buildGalleryWallpaperUri(long insertId) {
      method getGalleryWallpaperId (line 206) | public static String getGalleryWallpaperId(Uri uri) {
      method buildGalleryWallpaperDeleteUri (line 210) | public static Uri buildGalleryWallpaperDeleteUri(String uri) {
      method getGalleryWallpaperDeleteUri (line 215) | public static String getGalleryWallpaperDeleteUri(Uri uri) {
    class AdvanceWallpaper (line 220) | public static final class AdvanceWallpaper implements AdvanceWallpaper...
      method buildWallpaperUri (line 233) | public static Uri buildWallpaperUri(String wallpaperId) {
      method getWallpaperId (line 237) | public static String getWallpaperId(Uri uri) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContractHelper.java
  class StyleContractHelper (line 9) | public class StyleContractHelper {
    method setUriAsCalledFromSyncAdapter (line 13) | public static Uri setUriAsCalledFromSyncAdapter(Uri uri) {
    method isUriCalledFromSyncAdapter (line 18) | public static boolean isUriCalledFromSyncAdapter(Uri uri) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleDatabase.java
  class StyleDatabase (line 19) | public class StyleDatabase extends SQLiteOpenHelper {
    type Tables (line 33) | interface Tables {
    method StyleDatabase (line 40) | public StyleDatabase(Context context) {
    method onCreate (line 45) | @Override
    method onUpgrade (line 62) | @Override
    method upgradeFrom20161230to20170430 (line 98) | private void upgradeFrom20161230to20170430(SQLiteDatabase db) {
    method upgradeFrom20170430to20170524 (line 105) | private void upgradeFrom20170430to20170524(SQLiteDatabase db) {
    method upgradeFrom20170525to20170728 (line 117) | private void upgradeFrom20170525to20170728(SQLiteDatabase db) {
    method upgradeFrom20170728to20170811 (line 132) | private void upgradeFrom20170728to20170811(SQLiteDatabase db) {
    method deleteDatabase (line 141) | public static void deleteDatabase(Context context) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProvider.java
  class StyleProvider (line 32) | public class StyleProvider extends ContentProvider {
    method onCreate (line 40) | @Override
    method deleteDatabase (line 47) | private void deleteDatabase() {
    method applyBatch (line 54) | @NonNull
    method query (line 73) | @Nullable
    method getType (line 109) | @Nullable
    method insert (line 115) | @Nullable
    method delete (line 141) | @Override
    method update (line 167) | @Override
    method openFile (line 180) | @Nullable
    method queryUriForShow (line 199) | private Uri queryUriForShow() {
    method buildSimpleSelection (line 215) | private SelectionBuilder buildSimpleSelection(Uri uri) {
    method buildExpandedSelection (line 268) | private SelectionBuilder buildExpandedSelection(Uri uri, int match) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProviderUriMatcher.java
  class StyleProviderUriMatcher (line 11) | public class StyleProviderUriMatcher {
    method StyleProviderUriMatcher (line 17) | public StyleProviderUriMatcher() {
    method buildUriMatcher (line 22) | private void buildUriMatcher() {
    method buildEnumsMap (line 32) | private void buildEnumsMap() {
    method matchUri (line 39) | public StyleUriEnum matchUri(Uri uri) {
    method matchCode (line 48) | public StyleUriEnum matchCode(int code) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleUriEnum.java
  type StyleUriEnum (line 7) | public enum StyleUriEnum {
    method StyleUriEnum (line 27) | StyleUriEnum(int code, String path, String table) {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/RemoteStyleDataFetcher.java
  class RemoteStyleDataFetcher (line 12) | public class RemoteStyleDataFetcher extends DataFetcher {
    method RemoteStyleDataFetcher (line 15) | public RemoteStyleDataFetcher(Context context) {
    method getUrl (line 19) | @Override

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/StyleDataHandler.java
  class StyleDataHandler (line 27) | public class StyleDataHandler {
    method StyleDataHandler (line 48) | public StyleDataHandler(Context context) {
    method applyStyleData (line 52) | public void applyStyleData(String[] dataBodies) throws IOException {
    method processDataBody (line 98) | private void processDataBody(String dataBody) throws IOException {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncAdapter.java
  class SyncAdapter (line 16) | public class SyncAdapter extends AbstractThreadedSyncAdapter {
    method SyncAdapter (line 24) | public SyncAdapter(Context context, boolean autoInitialize) {
    method onPerformSync (line 34) | @Override

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncHelper.java
  class SyncHelper (line 22) | public class SyncHelper {
    method SyncHelper (line 29) | public SyncHelper(Context context) {
    method performSync (line 34) | public boolean performSync(SyncResult syncResult, Bundle extras) {
    method doStyleSync (line 44) | private boolean doStyleSync() throws IOException {
    method isOnline (line 59) | private boolean isOnline() {
    method updateSyncInterval (line 66) | public static void updateSyncInterval(final Context context) {
    method calculateRecommendedSyncInterval (line 78) | private static long calculateRecommendedSyncInterval(final Context con...

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncService.java
  class SyncService (line 12) | public class SyncService extends Service {
    method onCreate (line 17) | @Override
    method onBind (line 27) | @Nullable

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/Account.java
  class Account (line 12) | public class Account {
    method createSyncAccount (line 21) | public static android.accounts.Account createSyncAccount(Context conte...
    method getAccount (line 34) | public static android.accounts.Account getAccount() {

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/Authenticator.java
  class Authenticator (line 12) | public class Authenticator extends AbstractAccountAuthenticator {
    method Authenticator (line 14) | public Authenticator(Context context) {
    method editProperties (line 18) | @Override
    method addAccount (line 25) | @Override
    method confirmCredentials (line 36) | @Override
    method getAuthToken (line 45) | @Override
    method getAuthTokenLabel (line 55) | @Override
    method updateCredentials (line 61) | @Override
    method hasFeatures (line 70) | @Override

FILE: data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/AuthenticatorService.java
  class AuthenticatorService (line 12) | public class AuthenticatorService extends Service {
    method onCreate (line 16) | @Override
    method onBind (line 22) | @Nullable

FILE: data/src/main/java/com/yalin/style/data/utils/ChecksumUtil.java
  class ChecksumUtil (line 17) | public class ChecksumUtil {
    method getChecksum (line 18) | public static String getChecksum(File file) {

FILE: data/src/main/java/com/yalin/style/data/utils/DeviceUtil.java
  class DeviceUtil (line 13) | public class DeviceUtil {
    method DeviceUtil (line 15) | private DeviceUtil() {
    method getSDKVersion (line 19) | public static int getSDKVersion() {
    method getAndroidID (line 23) | @SuppressLint("HardwareIds")
    method getManufacturer (line 28) | public static String getManufacturer() {
    method getModel (line 32) | public static String getModel() {
    method getBrand (line 42) | public static String getBrand() {

FILE: data/src/main/java/com/yalin/style/data/utils/FacetIdUtil.java
  class FacetIdUtil (line 10) | public class FacetIdUtil {
    method checkCurrentFacetId (line 15) | public static boolean checkCurrentFacetId(Context context) {
    method getFacetId (line 19) | public static String getFacetId(Context context) {
    method checkCurrentFacetId (line 23) | private static native boolean checkCurrentFacetId(Context context, int...
    method getFacetId (line 25) | private static native String getFacetId(Context context, int uId);
    method getUid (line 27) | private static int getUid(Context context) {

FILE: data/src/main/java/com/yalin/style/data/utils/HttpRequestUtil.java
  class HttpRequestUtil (line 14) | public class HttpRequestUtil {
    method getRequestBody (line 17) | public static String getRequestBody(Context context) {
    method getDeviceJson (line 22) | private static DeviceInfo getDeviceJson(Context context) {

FILE: data/src/main/java/com/yalin/style/data/utils/NetworkUtil.java
  class NetworkUtil (line 12) | public class NetworkUtil {
    method isThereInternetConnection (line 13) | public static boolean isThereInternetConnection(Context context) {

FILE: data/src/main/java/com/yalin/style/data/utils/SelectionBuilder.java
  class SelectionBuilder (line 20) | public class SelectionBuilder {
    method reset (line 34) | public SelectionBuilder reset() {
    method where (line 47) | public SelectionBuilder where(String selection, String... selectionArg...
    method groupBy (line 70) | public SelectionBuilder groupBy(String groupBy) {
    method having (line 75) | public SelectionBuilder having(String having) {
    method table (line 80) | public SelectionBuilder table(String table) {
    method table (line 88) | public SelectionBuilder table(String table, String... tableParams) {
    method assertTable (line 103) | private void assertTable() {
    method mapToTable (line 109) | public SelectionBuilder mapToTable(String column, String table) {
    method map (line 114) | public SelectionBuilder map(String fromColumn, String toClause) {
    method getSelection (line 124) | public String getSelection() {
    method getSelectionArgs (line 133) | public String[] getSelectionArgs() {
    method mapColumns (line 137) | private void mapColumns(String[] columns) {
    method toString (line 146) | @Override
    method query (line 156) | public Cursor query(SQLiteDatabase db, String[] columns, String orderB...
    method query (line 163) | public Cursor query(SQLiteDatabase db, boolean distinct, String[] colu...
    method update (line 178) | public int update(SQLiteDatabase db, ContentValues values) {
    method delete (line 187) | public int delete(SQLiteDatabase db) {

FILE: data/src/main/java/com/yalin/style/data/utils/TimeUtil.java
  class TimeUtil (line 9) | public class TimeUtil {
    method getCurrentTime (line 11) | public static long getCurrentTime(final Context context) {

FILE: data/src/main/java/com/yalin/style/data/utils/WallpaperFileHelper.java
  class WallpaperFileHelper (line 23) | public class WallpaperFileHelper {
    method openReadFile (line 30) | public static ParcelFileDescriptor openReadFile(Context context, Uri u...
    method openWriteFile (line 47) | public static ParcelFileDescriptor openWriteFile(Context context, Uri ...
    method generateFileName (line 59) | private static String generateFileName(String wallpaperId) {
    method parseMode (line 63) | private static int parseMode(String mode) {
    method copyAssets (line 88) | public static boolean copyAssets(Context context, String name, File ou...
    method deleteOldWallpapers (line 117) | public static void deleteOldWallpapers(Context context, Set<String> ex...
    method deleteOldComponent (line 134) | public static void deleteOldComponent(Context context, Set<String> exc...
    method deleteOldWallpapers (line 149) | public static void deleteOldWallpapers(Context context, String... excl...
    method ensureWallpaperChecksumValid (line 166) | public static boolean ensureWallpaperChecksumValid(Context context,
    method ensureChecksumValid (line 183) | public static boolean ensureChecksumValid(Context context,
    method getAdvanceWallpaperDir (line 198) | public static File getAdvanceWallpaperDir(Context context) {
    method isNeedDownloadAdvanceComponent (line 202) | public static boolean isNeedDownloadAdvanceComponent(boolean lazy, Str...

FILE: data/src/test/java/com/yalin/data/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: domain/src/main/java/com/yalin/style/domain/AdvanceWallpaper.java
  class AdvanceWallpaper (line 8) | public class AdvanceWallpaper {

FILE: domain/src/main/java/com/yalin/style/domain/GalleryWallpaper.java
  class GalleryWallpaper (line 8) | public class GalleryWallpaper {

FILE: domain/src/main/java/com/yalin/style/domain/Source.java
  class Source (line 8) | public class Source {

FILE: domain/src/main/java/com/yalin/style/domain/Wallpaper.java
  class Wallpaper (line 8) | public class Wallpaper {

FILE: domain/src/main/java/com/yalin/style/domain/exception/DefaultErrorBundle.java
  class DefaultErrorBundle (line 8) | public class DefaultErrorBundle implements ErrorBundle {
    method DefaultErrorBundle (line 13) | public DefaultErrorBundle(Exception exception) {
    method getException (line 17) | @Override
    method getErrorMessage (line 22) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/exception/ErrorBundle.java
  type ErrorBundle (line 8) | public interface ErrorBundle {
    method getException (line 9) | Exception getException();
    method getErrorMessage (line 11) | String getErrorMessage();

FILE: domain/src/main/java/com/yalin/style/domain/executor/PostExecutionThread.java
  type PostExecutionThread (line 10) | public interface PostExecutionThread {
    method getScheduler (line 11) | Scheduler getScheduler();

FILE: domain/src/main/java/com/yalin/style/domain/executor/SerialThreadExecutor.java
  type SerialThreadExecutor (line 10) | public interface SerialThreadExecutor extends Executor {

FILE: domain/src/main/java/com/yalin/style/domain/executor/ThreadExecutor.java
  type ThreadExecutor (line 10) | public interface ThreadExecutor extends Executor {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/AddGalleryWallpaper.java
  class AddGalleryWallpaper (line 20) | public class AddGalleryWallpaper extends UseCase<Boolean, AddGalleryWall...
    method AddGalleryWallpaper (line 23) | @Inject
    method buildUseCaseObservable (line 32) | @Override
    class Params (line 38) | public static final class Params {
      method Params (line 42) | private Params(List<GalleryWallpaper> galleryWallpapers) {
      method addGalleryWallpaperUris (line 46) | public static Params addGalleryWallpaperUris(List<GalleryWallpaper> ...

FILE: domain/src/main/java/com/yalin/style/domain/interactor/DefaultObserver.java
  class DefaultObserver (line 10) | public class DefaultObserver<T> extends DisposableObserver<T> {
    method onNext (line 11) | @Override
    method onComplete (line 16) | @Override
    method onError (line 21) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/DownloadAdvanceWallpaper.java
  class DownloadAdvanceWallpaper (line 17) | public class DownloadAdvanceWallpaper extends UseCase<Long, DownloadAdva...
    method DownloadAdvanceWallpaper (line 20) | @Inject
    method buildUseCaseObservable (line 29) | @Override
    class Params (line 35) | public static final class Params {
      method Params (line 39) | private Params(String wallpaperId) {
      method download (line 43) | public static Params download(String wallpaperId) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/ForceNow.java
  class ForceNow (line 17) | public class ForceNow extends UseCase<Boolean, ForceNow.Params> {
    method ForceNow (line 20) | @Inject
    method buildUseCaseObservable (line 29) | @Override
    class Params (line 34) | public static final class Params {
      method Params (line 37) | private Params(String galleryWallpaperUri) {
      method fromUri (line 41) | public static Params fromUri(String galleryWallpaperUri) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetAdvanceWallpapers.java
  class GetAdvanceWallpapers (line 20) | public class GetAdvanceWallpapers extends UseCase<List<AdvanceWallpaper>...
    method GetAdvanceWallpapers (line 23) | @Inject
    method buildUseCaseObservable (line 32) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetGalleryUpdateInterval.java
  class GetGalleryUpdateInterval (line 17) | public class GetGalleryUpdateInterval extends UseCase<Integer, Void> {
    method GetGalleryUpdateInterval (line 21) | @Inject
    method buildUseCaseObservable (line 30) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetGalleryWallpaper.java
  class GetGalleryWallpaper (line 19) | public class GetGalleryWallpaper extends UseCase<List<GalleryWallpaper>,...
    method GetGalleryWallpaper (line 22) | @Inject
    method buildUseCaseObservable (line 31) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetSelectedAdvanceWallpaper.java
  class GetSelectedAdvanceWallpaper (line 13) | public class GetSelectedAdvanceWallpaper {
    method GetSelectedAdvanceWallpaper (line 16) | @Inject
    method getSelected (line 21) | public AdvanceWallpaper getSelected() {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetSelectedSource.java
  class GetSelectedSource (line 12) | public class GetSelectedSource {
    method GetSelectedSource (line 15) | @Inject
    method getSelectedSourceId (line 20) | public int getSelectedSourceId() {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetSources.java
  class GetSources (line 20) | public class GetSources extends UseCase<List<Source>, Void> {
    method GetSources (line 23) | @Inject
    method buildUseCaseObservable (line 32) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetWallpaper.java
  class GetWallpaper (line 18) | public class GetWallpaper extends UseCase<Wallpaper, Void> {
    method GetWallpaper (line 21) | @Inject
    method buildUseCaseObservable (line 30) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/GetWallpaperCount.java
  class GetWallpaperCount (line 18) | public class GetWallpaperCount extends UseCase<Integer, Void> {
    method GetWallpaperCount (line 21) | @Inject
    method buildUseCaseObservable (line 30) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/LikeWallpaper.java
  class LikeWallpaper (line 19) | public class LikeWallpaper extends UseCase<Boolean, Params> {
    method LikeWallpaper (line 23) | @Inject
    method buildUseCaseObservable (line 33) | @Override
    class Params (line 39) | public static final class Params {
      method Params (line 43) | private Params(String wallpaperId) {
      method likeWallpaper (line 47) | public static LikeWallpaper.Params likeWallpaper(String wallpaperId) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/LoadAdvanceWallpaper.java
  class LoadAdvanceWallpaper (line 20) | public class LoadAdvanceWallpaper extends UseCase<List<AdvanceWallpaper>...
    method LoadAdvanceWallpaper (line 23) | @Inject
    method buildUseCaseObservable (line 32) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/ObserverSources.java
  class ObserverSources (line 12) | public class ObserverSources {
    method ObserverSources (line 16) | @Inject
    method registerObserver (line 21) | public void registerObserver(DefaultObserver<Void> observer) {
    method unregisterObserver (line 25) | public void unregisterObserver(DefaultObserver<Void> observer) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/ObserverWallpaper.java
  class ObserverWallpaper (line 12) | public class ObserverWallpaper {
    method ObserverWallpaper (line 16) | @Inject
    method registerObserver (line 21) | public void registerObserver(DefaultObserver<Void> observer) {
    method unregisterObserver (line 25) | public void unregisterObserver(DefaultObserver<Void> observer) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/OpenWallpaperInputStream.java
  class OpenWallpaperInputStream (line 20) | public class OpenWallpaperInputStream
    method OpenWallpaperInputStream (line 24) | @Inject
    method buildUseCaseObservable (line 33) | @Override
    class Params (line 39) | public static final class Params {
      method Params (line 42) | private Params(String wallpaperId) {
      method openInputStream (line 46) | public static Params openInputStream(String wallpaperId) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/ReadAdvanceAd.java
  class ReadAdvanceAd (line 17) | public class ReadAdvanceAd extends UseCase<Boolean, ReadAdvanceAd.Params> {
    method ReadAdvanceAd (line 21) | @Inject
    method buildUseCaseObservable (line 30) | @Override
    class Params (line 36) | public static final class Params {
      method Params (line 40) | private Params(String wallpaperId) {
      method read (line 44) | public static Params read(String wallpaperId) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/RemoveGalleryWallpaper.java
  class RemoveGalleryWallpaper (line 21) | public class RemoveGalleryWallpaper extends UseCase<Boolean, Params> {
    method RemoveGalleryWallpaper (line 25) | @Inject
    method buildUseCaseObservable (line 34) | @Override
    class Params (line 40) | public static final class Params {
      method Params (line 44) | private Params(List<GalleryWallpaper> galleryWallpaperUris) {
      method removeGalleryWallpaperUris (line 48) | public static RemoveGalleryWallpaper.Params removeGalleryWallpaperUris(

FILE: domain/src/main/java/com/yalin/style/domain/interactor/SelectAdvanceWallpaper.java
  class SelectAdvanceWallpaper (line 17) | public class SelectAdvanceWallpaper extends UseCase<Boolean, SelectAdvan...
    method SelectAdvanceWallpaper (line 20) | @Inject
    method buildUseCaseObservable (line 29) | @Override
    class Params (line 35) | public static final class Params {
      method Params (line 39) | private Params(String wallpaperId, boolean tempSelect) {
      method selectWallpaper (line 44) | public static Params selectWallpaper(String wallpaperId, boolean tem...

FILE: domain/src/main/java/com/yalin/style/domain/interactor/SelectSource.java
  class SelectSource (line 17) | public class SelectSource extends UseCase<Boolean, SelectSource.Params> {
    method SelectSource (line 20) | @Inject
    method buildUseCaseObservable (line 29) | @Override
    class Params (line 34) | public static final class Params {
      method Params (line 39) | public Params(int sourceId, boolean tempSelect) {
      method selectSource (line 44) | public static Params selectSource(int sourceId, boolean tempSelect) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/SetGalleryUpdateInterval.java
  class SetGalleryUpdateInterval (line 17) | public class SetGalleryUpdateInterval extends UseCase<Boolean, SetGaller...
    method SetGalleryUpdateInterval (line 20) | @Inject
    method buildUseCaseObservable (line 29) | @Override
    class Params (line 35) | public static final class Params {
      method Params (line 38) | private Params(int intervalMin) {
      method interval (line 42) | public static Params interval(int intervalMin) {

FILE: domain/src/main/java/com/yalin/style/domain/interactor/SwitchWallpaper.java
  class SwitchWallpaper (line 18) | public class SwitchWallpaper extends UseCase<Wallpaper, Void> {
    method SwitchWallpaper (line 21) | @Inject
    method buildUseCaseObservable (line 30) | @Override

FILE: domain/src/main/java/com/yalin/style/domain/interactor/UseCase.java
  class UseCase (line 19) | public abstract class UseCase<T, Params> {
    method UseCase (line 25) | public UseCase(ThreadExecutor threadExecutor, SerialThreadExecutor ser...
    method buildUseCaseObservable (line 33) | abstract Observable<T> buildUseCaseObservable(Params params);
    method execute (line 35) | public void execute(DisposableObserver<T> observer, Params params) {
    method executeSerial (line 43) | public void executeSerial(DisposableObserver<T> observer, Params param...
    method dispose (line 51) | public void dispose() {
    method addDisposable (line 57) | private void addDisposable(Disposable disposable) {

FILE: domain/src/main/java/com/yalin/style/domain/observable/SourcesObservable.java
  type SourcesObservable (line 10) | public interface SourcesObservable {
    method registerObserver (line 11) | void registerObserver(DefaultObserver<Void> observer);
    method unregisterObserver (line 13) | void unregisterObserver(DefaultObserver<Void> observer);

FILE: domain/src/main/java/com/yalin/style/domain/observable/WallpaperObservable.java
  type WallpaperObservable (line 10) | public interface WallpaperObservable {
    method registerObserver (line 11) | void registerObserver(DefaultObserver<Void> observer);
    method unregisterObserver (line 13) | void unregisterObserver(DefaultObserver<Void> observer);

FILE: domain/src/main/java/com/yalin/style/domain/repository/SourcesRepository.java
  type SourcesRepository (line 14) | public interface SourcesRepository {
    method getSources (line 19) | Observable<List<Source>> getSources();
    method selectSource (line 21) | Observable<Boolean> selectSource(int sourceId, boolean tempSelect);
    method getWallpaperRepository (line 23) | WallpaperRepository getWallpaperRepository();
    method getSelectedSource (line 25) | int getSelectedSource();

FILE: domain/src/main/java/com/yalin/style/domain/repository/WallpaperRepository.java
  type WallpaperRepository (line 17) | public interface WallpaperRepository {
    method getWallpaper (line 19) | Observable<Wallpaper> getWallpaper();
    method switchWallpaper (line 21) | Observable<Wallpaper> switchWallpaper();
    method openInputStream (line 23) | Observable<InputStream> openInputStream(String wallpaperId);
    method getWallpaperCount (line 25) | Observable<Integer> getWallpaperCount();
    method likeWallpaper (line 27) | Observable<Boolean> likeWallpaper(String wallpaperId);
    method addGalleryWallpaperUris (line 29) | Observable<Boolean> addGalleryWallpaperUris(List<GalleryWallpaper> uris);
    method removeGalleryWallpaperUris (line 31) | Observable<Boolean> removeGalleryWallpaperUris(List<GalleryWallpaper> ...
    method getGalleryWallpapers (line 33) | Observable<List<GalleryWallpaper>> getGalleryWallpapers();
    method getAdvanceWallpapers (line 35) | Observable<List<AdvanceWallpaper>> getAdvanceWallpapers();
    method loadAdvanceWallpapers (line 37) | Observable<List<AdvanceWallpaper>> loadAdvanceWallpapers();
    method downloadAdvanceWallpaper (line 39) | Observable<Long> downloadAdvanceWallpaper(String wallpaperId);
    method selectAdvanceWallpaper (line 41) | Observable<Boolean> selectAdvanceWallpaper(String wallpaperId, boolean...
    method getAdvanceWallpaper (line 43) | AdvanceWallpaper getAdvanceWallpaper();
    method readAdvanceAd (line 45) | Observable<Boolean> readAdvanceAd(String wallpaperId);
    method foreNow (line 47) | Observable<Boolean> foreNow(String wallpaperUri);
    method setGalleryUpdateInterval (line 49) | Observable<Boolean> setGalleryUpdateInterval(int intervalMin);
    method getGalleryUpdateInterval (line 51) | Observable<Integer> getGalleryUpdateInterval();

FILE: engine/src/androidTest/java/com/yalin/style/engine/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 19) | @Test

FILE: engine/src/main/java/com/yalin/style/engine/IProvider.java
  type IProvider (line 11) | public interface IProvider {
    method provideProxy (line 13) | WallpaperService provideProxy(Context host);

FILE: engine/src/main/java/com/yalin/style/engine/ProxyApi.java
  class ProxyApi (line 13) | public class ProxyApi {
    method getProvider (line 15) | private static IProvider getProvider(ComponentContext context, String ...
    method getProxy (line 29) | public static WallpaperService getProxy(Context context,

FILE: engine/src/main/java/com/yalin/style/engine/advance/AnimationWallpaper.java
  class AnimationWallpaper (line 24) | public abstract class AnimationWallpaper extends WallpaperServiceProxy {
    method AnimationWallpaper (line 26) | public AnimationWallpaper(Context host) {
    class AnimationEngine (line 30) | protected abstract class AnimationEngine extends ActiveEngine {
      method run (line 34) | public void run() {
      method onDestroy (line 42) | @Override
      method onVisibilityChanged (line 49) | @Override
      method onSurfaceChanged (line 61) | @Override
      method onSurfaceDestroyed (line 68) | @Override
      method onOffsetsChanged (line 76) | @Override
      method drawFrame (line 84) | protected abstract void drawFrame();
      method iteration (line 86) | protected void iteration() {

FILE: engine/src/main/java/com/yalin/style/engine/advance/BokehRainbowCircle.java
  class BokehRainbowCircle (line 20) | public class BokehRainbowCircle {
    method BokehRainbowCircle (line 49) | public BokehRainbowCircle(float xCenter, float yCenter, float radius,
    method tick (line 69) | void tick() {
    method isDone (line 85) | boolean isDone() {

FILE: engine/src/main/java/com/yalin/style/engine/advance/BokehRainbowWallpaper.java
  class BokehRainbowWallpaper (line 29) | public class BokehRainbowWallpaper extends AnimationWallpaper {
    method BokehRainbowWallpaper (line 31) | public BokehRainbowWallpaper(Context host) {
    method onCreateEngine (line 35) | @Override
    class BokehEngine (line 40) | class BokehEngine extends AnimationEngine {
      method onCreate (line 53) | @Override
      method onSurfaceChanged (line 61) | @Override
      method onOffsetsChanged (line 80) | @Override
      method onCommand (line 92) | @Override
      method drawFrame (line 101) | @Override
      method draw (line 117) | void draw(Canvas c) {
      method iteration (line 161) | @Override
      method createRandomCircle (line 179) | void createRandomCircle() {
      method getColor (line 185) | int getColor(float yFraction) {
      method createCircle (line 190) | void createCircle(int x, int y) {

FILE: engine/src/main/java/com/yalin/style/engine/component/ComponentContext.java
  class ComponentContext (line 19) | public class ComponentContext extends ContextWrapper implements Wallpape...
    method ComponentContext (line 26) | public ComponentContext(Context base, String componentPath) {
    method getResources (line 34) | @Override
    method getClassLoader (line 42) | @Override
    method getClassLoader (line 48) | private ClassLoader getClassLoader(String componentFilePath) {
    method getAssets (line 56) | @Override
    method getApplicationContext (line 61) | @Override
    method onWallpaperActivate (line 66) | @Override
    method onWallpaperDeactivate (line 73) | @Override

FILE: engine/src/main/java/com/yalin/style/engine/resource/BrandUtil.java
  class BrandUtil (line 10) | public class BrandUtil {
    method isMiUi (line 11) | public static boolean isMiUi(Resources resources) {
    method isVivo (line 15) | public static boolean isVivo(Resources resources) {
    method isNubia (line 19) | public static boolean isNubia(Resources resources) {
    method isNotRawResources (line 23) | public static boolean isNotRawResources(Resources resources) {

FILE: engine/src/main/java/com/yalin/style/engine/resource/CompatResources.java
  class CompatResources (line 44) | public class CompatResources extends Resources {
    method CompatResources (line 48) | public CompatResources(Resources host, AssetManager assets,
    method getText (line 54) | @NonNull
    method getQuantityText (line 64) | @NonNull
    method getString (line 74) | @NonNull
    method getString (line 84) | @NonNull
    method getQuantityString (line 94) | @NonNull
    method getQuantityString (line 104) | @NonNull
    method getText (line 114) | @Override
    method getTextArray (line 123) | @NonNull
    method getStringArray (line 133) | @NonNull
    method getIntArray (line 143) | @NonNull
    method obtainTypedArray (line 153) | @NonNull
    method getDimension (line 163) | @Override
    method getDimensionPixelOffset (line 172) | @Override
    method getDimensionPixelSize (line 181) | @Override
    method getFraction (line 190) | @Override
    method getDrawable (line 199) | @Override
    method getDrawable (line 208) | @RequiresApi(api = 21)
    method getDrawableForDensity (line 219) | @RequiresApi(api = 15)
    method getDrawableForDensity (line 230) | @RequiresApi(api = 21)
    method getMovie (line 240) | @Override
    method getColor (line 249) | @Override
    method getColor (line 258) | @RequiresApi(api = 23)
    method getColorStateList (line 268) | @Nullable
    method getColorStateList (line 278) | @RequiresApi(api = 23)
    method getBoolean (line 290) | @Override
    method getInteger (line 299) | @Override
    method getLayout (line 308) | @Override
    method getAnimation (line 317) | @Override
    method getXml (line 326) | @Override
    method openRawResource (line 335) | @Override
    method openRawResource (line 344) | @Override
    method openRawResourceFd (line 353) | @Override
    method getValue (line 362) | @Override
    method getValueForDensity (line 372) | @RequiresApi(api = 15)
    method getValue (line 383) | @Override
    method obtainAttributes (line 393) | @Override
    method updateConfiguration (line 402) | @Override
    method getDisplayMetrics (line 411) | @Override
    method getConfiguration (line 420) | @Override
    method getIdentifier (line 429) | @Override
    method getResourceName (line 438) | @Override
    method getResourcePackageName (line 447) | @Override
    method getResourceTypeName (line 456) | @Override
    method getResourceEntryName (line 465) | @Override
    method parseBundleExtras (line 474) | @Override
    method parseBundleExtra (line 484) | @Override
    method obtainAttributes (line 494) | public static TypedArray obtainAttributes(

FILE: engine/src/main/java/com/yalin/style/engine/resource/ReflectUtil.java
  class ReflectUtil (line 12) | public class ReflectUtil {
    method getField (line 14) | public static Object getField(Class clazz, Object target, String name)
    method getFieldNoException (line 21) | public static Object getFieldNoException(Class clazz, Object target, S...
    method setField (line 31) | public static void setField(Class clazz, Object target, String name, O...
    method setFieldNoException (line 38) | public static void setFieldNoException(Class clazz, Object target, Str...
    method invoke (line 46) | @SuppressWarnings("unchecked")
    method invoke (line 62) | @SuppressWarnings("unchecked")
    method invokeNoException (line 71) | @SuppressWarnings("unchecked")
    method invokeConstructor (line 82) | @SuppressWarnings("unchecked")

FILE: engine/src/main/java/com/yalin/style/engine/resource/ResourcesManager.java
  class ResourcesManager (line 19) | public class ResourcesManager {
    method createCompatResources (line 20) | public static synchronized Resources createCompatResources(Context con...
    method createResources (line 27) | public static synchronized Resources createResources(Context context, ...
    method createAssetManager (line 34) | private static AssetManager createAssetManager(Context context, String...
    method createResourcesCompat (line 45) | private static ResourcesCompat createResourcesCompat(Resources hostRes...
    method hookResources (line 60) | private static void hookResources(Context context, Resources resources) {
    method getContextImpl (line 86) | private static Context getContextImpl(Context base) throws Exception {
    method getActivityThread (line 96) | private static Object getActivityThread(Context base) throws Exception {
    class ResourcesCompat (line 113) | private static abstract class ResourcesCompat {
      method createResources (line 114) | abstract Resources createResources(Context context,
    class MiUiResourcesCompat (line 119) | private static final class MiUiResourcesCompat extends ResourcesCompat {
      method createResources (line 120) | @Override
    class VivoResourcesCompat (line 132) | private static final class VivoResourcesCompat extends ResourcesCompat {
      method createResources (line 133) | @Override
    class NubiaResourcesCompat (line 152) | private static final class NubiaResourcesCompat extends ResourcesCompat {
      method createResources (line 153) | @Override
    class AdaptationResourcesCompat (line 164) | private static final class AdaptationResourcesCompat extends Resources...
      method createResources (line 165) | @Override
    class AndroidResourcesCompat (line 186) | private static final class AndroidResourcesCompat extends ResourcesCom...
      method createResources (line 188) | @Override

FILE: engine/src/main/java/net/rbgrn/android/glwallpaperservice/BaseConfigChooser.java
  class BaseConfigChooser (line 28) | abstract class BaseConfigChooser implements GLSurfaceView.EGLConfigChoos...
    method BaseConfigChooser (line 31) | public BaseConfigChooser(int[] configSpec, int eglContextClientVersion) {
    method chooseConfig (line 36) | public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
    method chooseConfig (line 62) | abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
    method filterConfigSpec (line 67) | private int[] filterConfigSpec(int[] configSpec) {
    class ComponentSizeChooser (line 83) | public static class ComponentSizeChooser extends BaseConfigChooser {
      method ComponentSizeChooser (line 84) | public ComponentSizeChooser(int redSize, int greenSize, int blueSize...
      method chooseConfig (line 98) | @Override
      method findConfigAttrib (line 121) | private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfi...
    class SimpleEGLConfigChooser (line 143) | public static class SimpleEGLConfigChooser extends ComponentSizeChooser {
      method SimpleEGLConfigChooser (line 144) | public SimpleEGLConfigChooser(boolean withDepthBuffer, int eglContex...

FILE: engine/src/main/java/net/rbgrn/android/glwallpaperservice/GLWallpaperService.java
  class GLWallpaperService (line 41) | public class GLWallpaperService extends WallpaperService {
    method onCreateEngine (line 44) | @Override
    class GLEngine (line 49) | public class GLEngine extends Engine {
      method GLEngine (line 61) | public GLEngine() {
      method onVisibilityChanged (line 65) | @Override
      method onCreate (line 75) | @Override
      method onDestroy (line 81) | @Override
      method onSurfaceChanged (line 88) | @Override
      method onSurfaceCreated (line 95) | @Override
      method onSurfaceDestroyed (line 102) | @Override
      method setGLWrapper (line 112) | public void setGLWrapper(GLSurfaceView.GLWrapper glWrapper) {
      method setDebugFlags (line 116) | public void setDebugFlags(int debugFlags) {
      method getDebugFlags (line 120) | public int getDebugFlags() {
      method setRenderer (line 124) | public void setRenderer(GLSurfaceView.Renderer renderer) {
      method setEGLContextFactory (line 139) | public void setEGLContextFactory(GLSurfaceView.EGLContextFactory fac...
      method setEGLWindowSurfaceFactory (line 144) | public void setEGLWindowSurfaceFactory(GLSurfaceView.EGLWindowSurfac...
      method setEGLConfigChooser (line 149) | public void setEGLConfigChooser(GLSurfaceView.EGLConfigChooser confi...
      method setEGLConfigChooser (line 154) | public void setEGLConfigChooser(boolean needDepth) {
      method setEGLConfigChooser (line 158) | public void setEGLConfigChooser(int redSize, int greenSize, int blue...
      method setEGLContextClientVersion (line 166) | public void setEGLContextClientVersion(int version) {
      method setRenderMode (line 171) | public void setRenderMode(int renderMode) {
      method getRenderMode (line 175) | public int getRenderMode() {
      method requestRender (line 179) | public void requestRender() {
      method onPause (line 183) | public void onPause() {
      method onResume (line 187) | public void onResume() {
      method queueEvent (line 191) | public void queueEvent(Runnable r) {
      method checkRenderThreadState (line 196) | private void checkRenderThreadState() {
    type Renderer (line 208) | @Deprecated
  class LogWriter (line 213) | class LogWriter extends Writer {
    method close (line 216) | @Override
    method flush (line 221) | @Override
    method write (line 226) | @Override
    method flushBuilder (line 238) | private void flushBuilder() {
  type EGLContextFactory (line 253) | @Deprecated
  class DefaultContextFactory (line 257) | class DefaultContextFactory implements GLSurfaceView.EGLContextFactory {
    method DefaultContextFactory (line 261) | DefaultContextFactory(int eglContextClientVersion) {
    method createContext (line 265) | public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConf...
    method destroyContext (line 272) | public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext c...
  type EGLWindowSurfaceFactory (line 282) | @Deprecated
  class DefaultWindowSurfaceFactory (line 286) | class DefaultWindowSurfaceFactory implements GLSurfaceView.EGLWindowSurf...
    method createWindowSurface (line 288) | public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay
    method destroySurface (line 309) | public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface s...
  type GLWrapper (line 319) | @Deprecated
  class EglHelper (line 323) | class EglHelper {
    method EglHelper (line 336) | public EglHelper(GLSurfaceView.EGLConfigChooser chooser, GLSurfaceView...
    method start (line 349) | public void start() {
    method createSurface (line 403) | public GL createSurface(SurfaceHolder holder) {
    method swap (line 451) | public boolean swap() {
    method destroySurface (line 461) | public void destroySurface() {
    method finish (line 469) | public void finish() {
  class GLThread (line 481) | class GLThread extends Thread {
    method GLThread (line 515) | GLThread(GLSurfaceView.Renderer renderer, GLSurfaceView.EGLConfigChoos...
    method run (line 530) | @Override
    method stopEglLocked (line 549) | private void stopEglLocked() {
    method guardedRun (line 557) | private void guardedRun() throws InterruptedException {
    method isDone (line 694) | private boolean isDone() {
    method setRenderMode (line 700) | public void setRenderMode(int renderMode) {
    method getRenderMode (line 712) | public int getRenderMode() {
    method requestRender (line 718) | public void requestRender() {
    method surfaceCreated (line 725) | public void surfaceCreated(SurfaceHolder holder) {
    method surfaceDestroyed (line 736) | public void surfaceDestroyed() {
    method onPause (line 753) | public void onPause() {
    method onResume (line 760) | public void onResume() {
    method onWindowResize (line 768) | public void onWindowResize(int w, int h) {
    method requestExitAndWait (line 777) | public void requestExitAndWait() {
    method queueEvent (line 797) | public void queueEvent(Runnable r) {
    method getEvent (line 807) | private Runnable getEvent() {
    class GLThreadManager (line 817) | private class GLThreadManager {
      method threadExiting (line 819) | public synchronized void threadExiting(GLThread thread) {
      method tryAcquireEglSurface (line 835) | public synchronized boolean tryAcquireEglSurface(GLThread thread) {
      method releaseEglSurface (line 844) | public synchronized void releaseEglSurface(GLThread thread) {
  type EGLConfigChooser (line 858) | @Deprecated

FILE: engine/src/test/java/com/yalin/style/engine/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 13) | @Test

FILE: presentation/src/androidTest/java/com/yalin/style/ExampleInstrumentedTest.java
  class ExampleInstrumentedTest (line 17) | @RunWith(AndroidJUnit4.class)
    method useAppContext (line 20) | @Test

FILE: presentation/src/androidTest/java/com/yalin/style/provider/DatabaseTest.java
  class DatabaseTest (line 19) | @RunWith(AndroidJUnit4.class)
    method testInsertWallpaper (line 22) | @Test
    method testOpenFile (line 58) | @Test

FILE: presentation/src/androidTest/java/com/yalin/style/sync/SyncAdapterTest.java
  class SyncAdapterTest (line 14) | @RunWith(AndroidJUnit4.class)
    method syncAdapterTest (line 17) | @Test

FILE: presentation/src/main/java/com/yalin/style/event/MainContainerInsetsChangedEvent.java
  class MainContainerInsetsChangedEvent (line 10) | public class MainContainerInsetsChangedEvent {
    method MainContainerInsetsChangedEvent (line 13) | public MainContainerInsetsChangedEvent(Rect insets) {
    method getInsets (line 17) | public Rect getInsets() {

FILE: presentation/src/main/java/com/yalin/style/event/SeenTutorialEvent.java
  class SeenTutorialEvent (line 8) | public class SeenTutorialEvent {

FILE: presentation/src/main/java/com/yalin/style/event/StyleWallpaperSizeChangedEvent.java
  class StyleWallpaperSizeChangedEvent (line 8) | public class StyleWallpaperSizeChangedEvent {
    method StyleWallpaperSizeChangedEvent (line 12) | public StyleWallpaperSizeChangedEvent(int width, int height) {
    method getWidth (line 17) | public int getWidth() {
    method getHeight (line 21) | public int getHeight() {

FILE: presentation/src/main/java/com/yalin/style/event/SwitchWallpaperServiceEvent.java
  class SwitchWallpaperServiceEvent (line 8) | public class SwitchWallpaperServiceEvent {

FILE: presentation/src/main/java/com/yalin/style/event/SwitchingPhotosStateChangedEvent.java
  class SwitchingPhotosStateChangedEvent (line 8) | public class SwitchingPhotosStateChangedEvent {
    method SwitchingPhotosStateChangedEvent (line 12) | public SwitchingPhotosStateChangedEvent(int id, boolean switchingPhoto...
    method getCurrentId (line 17) | public int getCurrentId() {
    method isSwitchingPhotos (line 21) | public boolean isSwitchingPhotos() {

FILE: presentation/src/main/java/com/yalin/style/event/SystemWallpaperSizeChangedEvent.java
  class SystemWallpaperSizeChangedEvent (line 8) | public class SystemWallpaperSizeChangedEvent {
    method SystemWallpaperSizeChangedEvent (line 12) | public SystemWallpaperSizeChangedEvent(int width, int height) {
    method getWidth (line 17) | public int getWidth() {
    method getHeight (line 21) | public int getHeight() {

FILE: presentation/src/main/java/com/yalin/style/event/WallpaperActivateEvent.java
  class WallpaperActivateEvent (line 8) | public class WallpaperActivateEvent {
    method WallpaperActivateEvent (line 11) | public WallpaperActivateEvent(boolean wallpaperActivate) {
    method isWallpaperActivate (line 15) | public boolean isWallpaperActivate() {

FILE: presentation/src/main/java/com/yalin/style/event/WallpaperDetailOpenedEvent.java
  class WallpaperDetailOpenedEvent (line 8) | public class WallpaperDetailOpenedEvent {
    method WallpaperDetailOpenedEvent (line 11) | public WallpaperDetailOpenedEvent(boolean wallpaperDetailOpened) {
    method isWallpaperDetailOpened (line 15) | public boolean isWallpaperDetailOpened() {

FILE: presentation/src/main/java/com/yalin/style/event/WallpaperSwitchEvent.java
  class WallpaperSwitchEvent (line 8) | public class WallpaperSwitchEvent {

FILE: presentation/src/main/java/com/yalin/style/exception/ErrorMessageFactory.java
  class ErrorMessageFactory (line 17) | public class ErrorMessageFactory {
    method ErrorMessageFactory (line 18) | private ErrorMessageFactory() {
    method create (line 29) | public static String create(Context context, Exception exception) {

FILE: presentation/src/main/java/com/yalin/style/model/AdvanceWallpaperItem.java
  class AdvanceWallpaperItem (line 11) | public class AdvanceWallpaperItem implements Parcelable {
    method AdvanceWallpaperItem (line 29) | public AdvanceWallpaperItem() {
    method AdvanceWallpaperItem (line 32) | protected AdvanceWallpaperItem(Parcel in) {
    method createFromParcel (line 48) | @Override
    method newArray (line 53) | @Override
    method describeContents (line 59) | @Override
    method writeToParcel (line 64) | @Override

FILE: presentation/src/main/java/com/yalin/style/model/GalleryWallpaperItem.java
  class GalleryWallpaperItem (line 11) | public class GalleryWallpaperItem implements Parcelable {
    method GalleryWallpaperItem (line 19) | public GalleryWallpaperItem() {
    method GalleryWallpaperItem (line 23) | protected GalleryWallpaperItem(Parcel in) {
    method writeToParcel (line 32) | @Override
    method describeContents (line 42) | @Override
    method createFromParcel (line 48) | @Override
    method newArray (line 53) | @Override
    method equals (line 59) | @Override
    method hashCode (line 68) | @Override

FILE: presentation/src/main/java/com/yalin/style/model/WallpaperItem.java
  class WallpaperItem (line 10) | public class WallpaperItem implements Parcelable {
    method WallpaperItem (line 22) | public WallpaperItem() {
    method WallpaperItem (line 25) | protected WallpaperItem(Parcel in) {
    method createFromParcel (line 36) | @Override
    method newArray (line 41) | @Override
    method describeContents (line 47) | @Override
    method writeToParcel (line 52) | @Override

FILE: presentation/src/main/java/com/yalin/style/render/BitmapRegionLoader.java
  class BitmapRegionLoader (line 31) | public class BitmapRegionLoader {
    method newInstance (line 41) | public static BitmapRegionLoader newInstance(InputStream in) throws IO...
    method newInstance (line 45) | public static BitmapRegionLoader newInstance(InputStream in, int rotat...
    method BitmapRegionLoader (line 63) | private BitmapRegionLoader(InputStream in) throws IOException {
    method decodeRegion (line 80) | public synchronized Bitmap decodeRegion(Rect rect, Options options) {
    method getWidth (line 147) | public synchronized int getWidth() {
    method getHeight (line 151) | public synchronized int getHeight() {
    method destroy (line 155) | public synchronized void destroy() {

FILE: presentation/src/main/java/com/yalin/style/render/GLColorOverlay.java
  class GLColorOverlay (line 23) | class GLColorOverlay {
    method GLColorOverlay (line 64) | public GLColorOverlay() {
    method initGl (line 68) | public static void initGl() {
    method draw (line 79) | public void draw(float[] mvpMatrix) {
    method setColor (line 106) | public void setColor(int color) {

FILE: presentation/src/main/java/com/yalin/style/render/GLPicture.java
  class GLPicture (line 26) | class GLPicture {
    method initGl (line 92) | public static void initGl() {
    method GLPicture (line 110) | public GLPicture(BitmapRegionLoader bitmapRegionLoader, int maxHeight) {
    method GLPicture (line 167) | public GLPicture(Bitmap bitmap) {
    method draw (line 211) | public void draw(float[] mvpMatrix, float alpha) {
    method destroy (line 268) | public void destroy() {

FILE: presentation/src/main/java/com/yalin/style/render/GLTextureView.java
  class GLTextureView (line 44) | public class GLTextureView extends TextureView implements TextureView.Su...
    method GLTextureView (line 93) | public GLTextureView(Context context) {
    method GLTextureView (line 102) | public GLTextureView(Context context, AttributeSet attrs) {
    method finalize (line 107) | @Override
    method init (line 120) | private void init() {
    method setGLWrapper (line 138) | public void setGLWrapper(GLWrapper glWrapper) {
    method setDebugFlags (line 152) | public void setDebugFlags(int debugFlags) {
    method getDebugFlags (line 161) | public int getDebugFlags() {
    method setPreserveEGLContextOnPause (line 183) | public void setPreserveEGLContextOnPause(boolean preserveOnPause) {
    method getPreserveEGLContextOnPause (line 190) | public boolean getPreserveEGLContextOnPause() {
    method setRenderer (line 220) | public void setRenderer(GLSurfaceView.Renderer renderer) {
    method setEGLContextFactory (line 246) | public void setEGLContextFactory(EGLContextFactory factory) {
    method setEGLWindowSurfaceFactory (line 260) | public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
    method setEGLConfigChooser (line 278) | public void setEGLConfigChooser(EGLConfigChooser configChooser) {
    method setEGLConfigChooser (line 297) | public void setEGLConfigChooser(boolean needDepth) {
    method setEGLConfigChooser (line 313) | public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
    method setEGLContextClientVersion (line 346) | public void setEGLContextClientVersion(int version) {
    method setRenderMode (line 367) | public void setRenderMode(int renderMode) {
    method getRenderMode (line 379) | public int getRenderMode() {
    method requestRender (line 390) | public void requestRender() {
    method onSurfaceTextureAvailable (line 394) | @Override
    method onSurfaceTextureSizeChanged (line 399) | @Override
    method onSizeChanged (line 404) | @Override
    method onSurfaceTextureDestroyed (line 410) | @Override
    method onSurfaceTextureUpdated (line 416) | @Override
    method on (line 425) | public void on(SurfaceHolder holder) {
    method onPause (line 435) | public void onPause() {
    method onResume (line 446) | public void onResume() {
    method queueEvent (line 457) | public void queueEvent(Runnable r) {
    method onAttachedToWindow (line 465) | @Override
    method onDetachedFromWindow (line 490) | @Override
    type GLWrapper (line 526) | public interface GLWrapper {
      method wrap (line 533) | GL wrap(GL gl);
    type EGLContextFactory (line 542) | public interface EGLContextFactory {
      method createContext (line 543) | EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eg...
      method destroyContext (line 545) | void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
    class DefaultContextFactory (line 548) | private class DefaultContextFactory implements EGLContextFactory {
      method createContext (line 551) | public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLCo...
      method destroyContext (line 559) | public void destroyContext(EGL10 egl, EGLDisplay display,
    type EGLWindowSurfaceFactory (line 577) | public interface EGLWindowSurfaceFactory {
      method createWindowSurface (line 581) | EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLCon...
      method destroySurface (line 584) | void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
    class DefaultWindowSurfaceFactory (line 587) | private static class DefaultWindowSurfaceFactory implements EGLWindowS...
      method createWindowSurface (line 589) | public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
      method destroySurface (line 606) | public void destroySurface(EGL10 egl, EGLDisplay display,
    type EGLConfigChooser (line 619) | public interface EGLConfigChooser {
      method chooseConfig (line 630) | EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
    class BaseConfigChooser (line 633) | private abstract class BaseConfigChooser
      method BaseConfigChooser (line 635) | public BaseConfigChooser(int[] configSpec) {
      method chooseConfig (line 639) | public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
      method chooseConfig (line 665) | abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
      method filterConfigSpec (line 670) | private int[] filterConfigSpec(int[] configSpec) {
    class ComponentSizeChooser (line 691) | private class ComponentSizeChooser extends BaseConfigChooser {
      method ComponentSizeChooser (line 692) | public ComponentSizeChooser(int redSize, int greenSize, int blueSize,
      method chooseConfig (line 711) | @Override
      method findConfigAttrib (line 737) | private int findConfigAttrib(EGL10 egl, EGLDisplay display,
    class SimpleEGLConfigChooser (line 760) | private class SimpleEGLConfigChooser extends ComponentSizeChooser {
      method SimpleEGLConfigChooser (line 761) | public SimpleEGLConfigChooser(boolean withDepthBuffer) {
    class EglHelper (line 770) | private static class EglHelper {
      method EglHelper (line 771) | public EglHelper(WeakReference<GLTextureView> glTextureViewWeakRef) {
      method start (line 780) | public void start() {
      method createSurface (line 835) | public boolean createSurface() {
      method createGL (line 898) | GL createGL() {
      method swap (line 927) | public int swap() {
      method destroySurface (line 934) | public void destroySurface() {
      method destroySurfaceImp (line 941) | private void destroySurfaceImp() {
      method finish (line 954) | public void finish() {
      method throwEglException (line 971) | private void throwEglException(String function) {
      method throwEglException (line 975) | public static void throwEglException(String function, int error) {
      method logEglErrorAsWarning (line 984) | public static void logEglErrorAsWarning(String tag, String function,...
      method formatEglError (line 988) | public static String formatEglError(String function, int error) {
    class GLThread (line 1009) | static class GLThread extends Thread {
      method GLThread (line 1010) | GLThread(WeakReference<GLTextureView> glTextureViewWeakRef) {
      method run (line 1019) | @Override
      method stopEglSurfaceLocked (line 1039) | private void stopEglSurfaceLocked() {
      method stopEglContextLocked (line 1050) | private void stopEglContextLocked() {
      method guardedRun (line 1058) | private void guardedRun() throws InterruptedException {
      method ableToDraw (line 1354) | public boolean ableToDraw() {
      method readyToDraw (line 1358) | private boolean readyToDraw() {
      method setRenderMode (line 1364) | public void setRenderMode(int renderMode) {
      method getRenderMode (line 1374) | public int getRenderMode() {
      method requestRender (line 1380) | public void requestRender() {
      method surfaceCreated (line 1387) | public void surfaceCreated() {
      method surfaceDestroyed (line 1407) | public void surfaceDestroyed() {
      method onPause (line 1424) | public void onPause() {
      method onResume (line 1444) | public void onResume() {
      method onWindowResize (line 1466) | public void onWindowResize(int w, int h) {
      method requestExitAndWait (line 1490) | public void requestExitAndWait() {
      method requestReleaseEglContextLocked (line 1506) | public void requestReleaseEglContextLocked() {
      method queueEvent (line 1516) | public void queueEvent(Runnable r) {
    class LogWriter (line 1560) | static class LogWriter extends Writer {
      method close (line 1562) | @Override
      method flush (line 1567) | @Override
      method write (line 1572) | @Override
      method flushBuilder (line 1584) | private void flushBuilder() {
    method checkRenderThreadState (line 1595) | private void checkRenderThreadState() {
    class GLThreadManager (line 1602) | private static class GLThreadManager {
      method threadExiting (line 1605) | public synchronized void threadExiting(GLThread thread) {
      method tryAcquireEglContextLocked (line 1623) | public boolean tryAcquireEglContextLocked(GLThread thread) {
      method releaseEglContextLocked (line 1647) | public void releaseEglContextLocked(GLThread thread) {
      method shouldReleaseEGLContextWhenPausing (line 1654) | public synchronized boolean shouldReleaseEGLContextWhenPausing() {
      method shouldTerminateEGLWhenPausing (line 1661) | public synchronized boolean shouldTerminateEGLWhenPausing() {
      method checkGLDriver (line 1666) | public synchronized void checkGLDriver(GL10 gl) {
      method checkGLESVersion (line 1685) | private void checkGLESVersion() {

FILE: presentation/src/main/java/com/yalin/style/render/GLUtil.java
  class GLUtil (line 16) | public class GLUtil {
    method loadShader (line 22) | public static int loadShader(int type, String shaderCode) {
    method createAndLinkProgram (line 34) | public static int createAndLinkProgram(int vertexShaderHandle, int fra...
    method loadTexture (line 53) | public static int loadTexture(Bitmap bitmap) {
    method checkGlError (line 88) | public static void checkGlError(String glOperation) {
    method asFloatBuffer (line 98) | public static FloatBuffer asFloatBuffer(float[] array) {
    method newFloatBuffer (line 105) | public static FloatBuffer newFloatBuffer(int size) {

FILE: presentation/src/main/java/com/yalin/style/render/ImageBlurrer.java
  class ImageBlurrer (line 30) | public class ImageBlurrer {
    method ImageBlurrer (line 39) | public ImageBlurrer(Context context, Bitmap src) {
    method blurBitmap (line 48) | public Bitmap blurBitmap(float radius, float desaturateAmount) {
    method doBlur (line 75) | private void doBlur(float amount, Allocation input, Allocation output) {
    method doDesaturate (line 81) | private void doDesaturate(float normalizedAmount, Allocation input, Al...
    method destroy (line 99) | public void destroy() {

FILE: presentation/src/main/java/com/yalin/style/render/ImageUtil.java
  class ImageUtil (line 22) | public class ImageUtil {
    method calculateDarkness (line 24) | public static float calculateDarkness(Bitmap bitmap) {
    method ImageUtil (line 48) | private ImageUtil() {
    method calculateSampleSize (line 51) | public static int calculateSampleSize(int rawSize, int targetSize) {

FILE: presentation/src/main/java/com/yalin/style/render/StyleBlurRenderer.java
  class StyleBlurRenderer (line 33) | public class StyleBlurRenderer implements GLSurfaceView.Renderer {
    method StyleBlurRenderer (line 83) | public StyleBlurRenderer(Context context, Callbacks callbacks) {
    method getNumberOfKeyframes (line 98) | private int getNumberOfKeyframes() {
    method recomputeMaxPrescaledBlurPixels (line 104) | public void recomputeMaxPrescaledBlurPixels() {
    method recomputeMaxDimAmount (line 120) | public void recomputeMaxDimAmount() {
    method recomputeGreyAmount (line 125) | public void recomputeGreyAmount() {
    method onSurfaceCreated (line 132) | public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    method onSurfaceChanged (line 159) | public void onSurfaceChanged(GL10 unused, int width, int height) {
    method hintViewportSize (line 172) | public void hintViewportSize(int width, int height) {
    method onDrawFrame (line 177) | public void onDrawFrame(GL10 unused) {
    method setNormalOffsetX (line 207) | public void setNormalOffsetX(float x) {
    method onViewportChanged (line 212) | private void onViewportChanged() {
    method blurRadiusAtFrame (line 220) | private float blurRadiusAtFrame(float f) {
    method setAndConsumeBitmapRegionLoader (line 224) | public void setAndConsumeBitmapRegionLoader(final BitmapRegionLoader b...
    method setDemoMode (line 280) | public void setDemoMode(boolean demoMode) {
    method setIsPreview (line 285) | public void setIsPreview(boolean preview) {
    class GLPictureSet (line 289) | private class GLPictureSet {
      method GLPictureSet (line 298) | public GLPictureSet(int id) {
      method load (line 302) | public void load(BitmapRegionLoader bitmapRegionLoader) {
      method recomputeTransformMatrices (line 405) | private void recomputeTransformMatrices() {
      method drawFrame (line 473) | public void drawFrame(float globalAlpha) {
      method destroyPictures (line 523) | public void destroyPictures() {
    method destroy (line 533) | public void destroy() {
    method isBlurred (line 538) | public boolean isBlurred() {
    method setIsBlurred (line 542) | public void setIsBlurred(final boolean isBlurred, final boolean artDet...
    type Callbacks (line 567) | public interface Callbacks {
      method requestRender (line 568) | void requestRender();

FILE: presentation/src/main/java/com/yalin/style/render/TickingFloatAnimator.java
  class TickingFloatAnimator (line 24) | public class TickingFloatAnimator {
    method create (line 34) | public static TickingFloatAnimator create() {
    method from (line 38) | public TickingFloatAnimator from(float startValue) {
    method to (line 45) | public TickingFloatAnimator to(float endValue) {
    method withDuration (line 50) | public TickingFloatAnimator withDuration(int duration) {
    method withInterpolator (line 55) | public TickingFloatAnimator withInterpolator(TimeInterpolator interpol...
    method withEndListener (line 60) | public TickingFloatAnimator withEndListener(Runnable listener) {
    method cancel (line 65) | public void cancel() {
    method tick (line 70) | public boolean tick() {
    method start (line 101) | public void start() {
    method isRunning (line 108) | public boolean isRunning() {
    method currentValue (line 112) | public float currentValue() {
    method TickingFloatAnimator (line 116) | private TickingFloatAnimator() {

FILE: presentation/src/main/java/com/yalin/style/settings/Prefs.java
  class Prefs (line 12) | public class Prefs {
    method getSharedPreferences (line 22) | public synchronized static SharedPreferences getSharedPreferences(Cont...
    method Prefs (line 30) | private Prefs() {

FILE: presentation/src/main/java/com/yalin/style/util/ImageLoader.java
  class ImageLoader (line 26) | public class ImageLoader {
    method ImageLoader (line 37) | public ImageLoader(Context context) {
    method ImageLoader (line 46) | public ImageLoader(Context context, int placeHolderResId) {
    method loadImage (line 59) | public void loadImage(String url, ImageView imageView,
    method loadImage (line 72) | public void loadImage(String url, ImageView imageView,
    method loadImage (line 89) | public void loadImage(String url, ImageView imageView,
    method beginImageLoad (line 102) | public BitmapRequestBuilder beginImageLoad(String url,
    method loadImage (line 122) | public void loadImage(String url, ImageView imageView) {
    method loadImage (line 134) | public void loadImage(String url, ImageView imageView, boolean crop) {
    method loadImage (line 138) | public void loadImage(Context context, @DrawableRes int drawableResId,...
    class VariableWidthImageLoader (line 142) | private static class VariableWidthImageLoader extends BaseGlideUrlLoad...
      method VariableWidthImageLoader (line 145) | public VariableWidthImageLoader(Context context) {
      method getUrl (line 155) | @Override

FILE: presentation/src/main/java/com/yalin/style/util/MathUtil.java
  class MathUtil (line 7) | public class MathUtil {
    method constrain (line 9) | public static float constrain(float min, float max, float v) {
    method interpolate (line 13) | public static float interpolate(float x1, float x2, float f) {
    method uninterpolate (line 17) | public static float uninterpolate(float x1, float x2, float v) {
    method floorEven (line 24) | public static int floorEven(int num) {
    method roundMult4 (line 28) | public static int roundMult4(int num) {
    method intDivideRoundUp (line 34) | public static int intDivideRoundUp(int num, int divisor) {

FILE: presentation/src/main/java/com/yalin/style/util/ScrimUtil.java
  class ScrimUtil (line 18) | public class ScrimUtil {
    method ScrimUtil (line 22) | private ScrimUtil() {
    method makeCubicGradientScrimDrawable (line 30) | public static Drawable makeCubicGradientScrimDrawable(int baseColor,

FILE: presentation/src/main/java/com/yalin/style/util/SettingsUtil.java
  class SettingsUtil (line 7) | public class SettingsUtil {

FILE: presentation/src/main/java/com/yalin/style/util/SvgPathParser.java
  class SvgPathParser (line 11) | public class SvgPathParser {
    method transformX (line 24) | protected float transformX(float x) {
    method transformY (line 28) | protected float transformY(float y) {
    method parsePath (line 32) | public Path parsePath(String s) throws ParseException {
    method advanceToNextToken (line 169) | private int advanceToNextToken() {
    method consumeCommand (line 187) | private char consumeCommand() throws ParseException {
    method consumeAndTransformPoint (line 196) | private void consumeAndTransformPoint(PointF out, boolean relative) th...
    method consumeValue (line 205) | private float consumeValue() throws ParseException {

FILE: presentation/src/main/java/com/yalin/style/util/TypefaceUtil.java
  class TypefaceUtil (line 14) | public class TypefaceUtil {
    method getAndCache (line 17) | public static Typeface getAndCache(Context context, String assetPath) {

FILE: presentation/src/main/java/com/yalin/style/view/component/CircleProgressView.java
  class CircleProgressView (line 29) | public class CircleProgressView extends View {
    method CircleProgressView (line 52) | public CircleProgressView(Context context) {
    method CircleProgressView (line 56) | public CircleProgressView(Context context, AttributeSet attrs) {
    method CircleProgressView (line 60) | public CircleProgressView(Context context, AttributeSet attrs, int def...
    method start (line 86) | private void start() {
    method stop (line 96) | private void stop() {
    method isRunning (line 106) | private boolean isRunning() {
    method onVisibilityChanged (line 110) | @Override
    method onAttachedToWindow (line 120) | @Override
    method onDetachedFromWindow (line 126) | @Override
    method onSizeChanged (line 132) | @Override
    method draw (line 141) | @Override
    method gradient (line 157) | private static int gradient(int color1, int color2, float p) {
    method toggleAppearingMode (line 170) | private void toggleAppearingMode() {
    method get (line 182) | @Override
    method set (line 187) | @Override
    method get (line 194) | @Override
    method set (line 199) | @Override
    method setupAnimations (line 205) | private void setupAnimations() {
    method setCurrentGlobalAngle (line 240) | public void setCurrentGlobalAngle(float currentGlobalAngle) {
    method getCurrentGlobalAngle (line 245) | public float getCurrentGlobalAngle() {
    method setCurrentSweepAngle (line 249) | public void setCurrentSweepAngle(float currentSweepAngle) {
    method getCurrentSweepAngle (line 254) | public float getCurrentSweepAngle() {

FILE: presentation/src/main/java/com/yalin/style/view/component/DrawInsetsFrameLayout.java
  class DrawInsetsFrameLayout (line 18) | public class DrawInsetsFrameLayout extends FrameLayout {
    method DrawInsetsFrameLayout (line 28) | public DrawInsetsFrameLayout(Context context) {
    method DrawInsetsFrameLayout (line 33) | public DrawInsetsFrameLayout(Context context, AttributeSet attrs) {
    method DrawInsetsFrameLayout (line 38) | public DrawInsetsFrameLayout(Context context, AttributeSet attrs, int ...
    method init (line 43) | private void init(Context context, AttributeSet attrs, int defStyle) {
    method onAttachedToWindow (line 57) | @Override
    method onDetachedFromWindow (line 74) | @Override
    method setOnInsetsCallback (line 91) | public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
    method fitSystemWindows (line 95) | @Override
    method onDraw (line 106) | @Override
    type OnInsetsCallback (line 159) | public interface OnInsetsCallback {
      method onInsetsChanged (line 160) | void onInsetsChanged(Rect insets);

FILE: presentation/src/main/java/com/yalin/style/view/component/PanScaleProxyView.java
  class PanScaleProxyView (line 27) | public class PanScaleProxyView extends View {
    method PanScaleProxyView (line 58) | public PanScaleProxyView(Context context) {
    method PanScaleProxyView (line 62) | public PanScaleProxyView(Context context, AttributeSet attrs) {
    method PanScaleProxyView (line 66) | public PanScaleProxyView(Context context, AttributeSet attrs, int defS...
    method onSizeChanged (line 80) | @Override
    method hitTest (line 98) | private void hitTest(float x, float y, PointF dest) {
    method onTouchEvent (line 103) | @Override
    method onScaleBegin (line 127) | @Override
    method onScale (line 137) | @Override
    method constrainViewport (line 167) | private void constrainViewport() {
    method onDown (line 215) | @Override
    method onSingleTapConfirmed (line 227) | @Override
    method onDoubleTapEvent (line 235) | @Override
    method onScroll (line 261) | @Override
    method onFling (line 284) | @Override
    method fling (line 295) | private void fling(int velocityX, int velocityY) {
    method postAnimateTick (line 315) | private void postAnimateTick() {
    method run (line 321) | @Override
    method computeScrollSurfaceSize (line 376) | private void computeScrollSurfaceSize(Point out) {
    method setViewportTopLeft (line 388) | private void setViewportTopLeft(float x, float y) {
    method getCurrentViewport (line 413) | public RectF getCurrentViewport() {
    method triggerViewportChangedListener (line 417) | private void triggerViewportChangedListener() {
    method onSaveInstanceState (line 429) | @Override
    method onRestoreInstanceState (line 437) | @Override
    method setRelativeAspectRatio (line 450) | public void setRelativeAspectRatio(float relativeAspectRatio) {
    method setViewport (line 456) | public void setViewport(RectF viewport) {
    method setMaxZoom (line 461) | public void setMaxZoom(int maxZoom) {
    method setOnViewportChangedListener (line 465) | public void setOnViewportChangedListener(OnViewportChangedListener onV...
    method setOnOtherGestureListener (line 469) | public void setOnOtherGestureListener(OnOtherGestureListener onOtherGe...
    method enablePanScale (line 473) | public void enablePanScale(boolean panScaleEnabled) {
    class SavedState (line 480) | public static class SavedState extends BaseSavedState {
      method SavedState (line 483) | public SavedState(Parcelable superState) {
      method writeToParcel (line 487) | @Override
      method toString (line 496) | @Override
      method createFromParcel (line 505) | @Override
      method newArray (line 510) | @Override
      method SavedState (line 516) | SavedState(Parcel in) {
    type OnViewportChangedListener (line 522) | public interface OnViewportChangedListener {
      method onViewportChanged (line 523) | void onViewportChanged();
    type OnOtherGestureListener (line 526) | public interface OnOtherGestureListener {
      method onSingleTapUp (line 527) | void onSingleTapUp();

FILE: presentation/src/main/java/com/yalin/style/view/fragment/StyleRenderFragment.java
  class StyleRenderFragment (line 36) | public class StyleRenderFragment extends Fragment implements RenderContr...
    method createInstance (line 50) | public static StyleRenderFragment createInstance(boolean demoMode, boo...
    method onCreate (line 59) | @Override
    method onSaveInstanceState (line 72) | @Override
    method onCreateView (line 79) | @Nullable
    method onHiddenChanged (line 106) | @Override
    method onDestroyView (line 114) | @Override
    method onResume (line 120) | @Override
    method onPause (line 128) | @Override
    method queueEventOnGlThread (line 136) | @Override
    method requestRender (line 143) | @Override
    method onResourceReady (line 152) | @Override
    method getSize (line 169) | @Override
    class StyleView (line 175) | public class StyleView extends GLTextureView {
      method StyleView (line 181) | public StyleView(Context context) {
      method onSizeChanged (line 199) | @Override
      method onDetachedFromWindow (line 206) | @Override

FILE: presentation/src/test/java/com/yalin/style/ExampleUnitTest.java
  class ExampleUnitTest (line 12) | public class ExampleUnitTest {
    method addition_isCorrect (line 14) | @Test
Condensed preview — 342 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (955K chars).
[
  {
    "path": ".gitignore",
    "chars": 118,
    "preview": "*.iml\n.gradle\n/local.properties\n/.idea/workspace.xml\n/.idea/libraries\n.DS_Store\n/build\n/captures\n.externalNativeBuild\n"
  },
  {
    "path": "README.md",
    "chars": 1198,
    "preview": "# Deprecated, Not maintain anymore.\n\n# Style Live Wallpaper\n\nA live wallpaper project for Android\n====================\n<"
  },
  {
    "path": "build.gradle",
    "chars": 632,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "buildApk.bat",
    "chars": 645,
    "preview": "@echo off\necho Start Build Apk\n\ncall gradlew clean\ncall gradlew assembleProductionRelease -Dchannel=kinglloy\ncall gradle"
  },
  {
    "path": "buildApk.sh",
    "chars": 630,
    "preview": "#!/usr/bin/env bash\necho \"Start Build Apk\"\n\n./gradlew clean\n./gradlew assembleProductionRelease -Dchannel=kinglloy\n./gra"
  },
  {
    "path": "data/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "data/CMakeLists.txt",
    "chars": 1773,
    "preview": "# Sets the minimum version of CMake required to build the native\n# library. You should either keep the default value or "
  },
  {
    "path": "data/build.gradle",
    "chars": 2960,
    "preview": "buildscript {\n    repositories {\n        mavenCentral()\n    }\n    dependencies {\n        classpath 'me.tatarka:gradle-re"
  },
  {
    "path": "data/proguard-rules.pro",
    "chars": 939,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
  },
  {
    "path": "data/src/androidTest/java/com/yalin/data/ExampleInstrumentedTest.java",
    "chars": 737,
    "preview": "package com.yalin.data;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport and"
  },
  {
    "path": "data/src/main/AndroidManifest.xml",
    "chars": 2355,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.yalin.style.data\">\n\n    <uses-perm"
  },
  {
    "path": "data/src/main/cpp/facet_id-lib.cpp",
    "chars": 8341,
    "preview": "#include <jni.h>\n#include <string>\n#include <android/log.h>\n\n#define LOG_TAG (\"facet_id_check\")\n#define LOGI(...) __andr"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/SyncConfig.java",
    "chars": 568,
    "preview": "package com.yalin.style.data;\n\nimport java.util.concurrent.TimeUnit;\n\n/**\n * YaLin 2017/1/3.\n */\n\npublic class SyncConfi"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/AdvanceWallpaperCache.kt",
    "chars": 612,
    "preview": "package com.yalin.style.data.cache\n\nimport com.yalin.style.data.entity.AdvanceWallpaperEntity\n\n/**\n * @author jinyalin\n "
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/AdvanceWallpaperCacheImpl.kt",
    "chars": 2111,
    "preview": "package com.yalin.style.data.cache\n\nimport android.text.TextUtils\nimport com.yalin.style.data.entity.AdvanceWallpaperEnt"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/GalleryWallpaperCache.kt",
    "chars": 720,
    "preview": "package com.yalin.style.data.cache\n\nimport com.yalin.style.data.entity.GalleryWallpaperEntity\nimport javax.inject.Inject"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/SourcesCache.kt",
    "chars": 392,
    "preview": "package com.yalin.style.data.cache\n\nimport android.content.Context\nimport com.yalin.style.data.entity.SourceEntity\nimpor"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/SourcesCacheImpl.kt",
    "chars": 3729,
    "preview": "package com.yalin.style.data.cache\n\nimport android.content.Context\nimport android.graphics.Color\nimport com.yalin.style."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/WallpaperCache.java",
    "chars": 630,
    "preview": "package com.yalin.style.data.cache;\n\nimport com.yalin.style.data.entity.WallpaperEntity;\n\nimport java.util.Queue;\n\nimpor"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/cache/WallpaperCacheImpl.java",
    "chars": 3262,
    "preview": "package com.yalin.style.data.cache;\n\nimport android.text.TextUtils;\n\nimport com.fernandocejas.arrow.checks.Preconditions"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/AdvanceWallpaperEntity.java",
    "chars": 4355,
    "preview": "package com.yalin.style.data.entity;\n\nimport android.database.Cursor;\nimport android.text.TextUtils;\n\nimport com.yalin.s"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/DeviceInfo.java",
    "chars": 1211,
    "preview": "package com.yalin.style.data.entity;\n\nimport com.yalin.style.data.BuildConfig;\n\n/**\n * @author jinyalin\n * @since 2017/4"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/GalleryWallpaperEntity.kt",
    "chars": 2994,
    "preview": "package com.yalin.style.data.entity\n\nimport android.content.Context\nimport android.database.Cursor\nimport android.net.Ur"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/HttpRequestBody.java",
    "chars": 509,
    "preview": "package com.yalin.style.data.entity;\n\nimport android.content.Context;\n\nimport com.yalin.style.data.utils.FacetIdUtil;\n\n/"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/SourceEntity.kt",
    "chars": 316,
    "preview": "package com.yalin.style.data.entity\n\n\n/**\n * @author jinyalin\n * *\n * @since 2017/5/23.\n */\n\nclass SourceEntity(var id: "
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/WallpaperEntity.java",
    "chars": 3494,
    "preview": "package com.yalin.style.data.entity;\n\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.tex"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/mapper/AdvanceWallpaperEntityMapper.java",
    "chars": 2386,
    "preview": "package com.yalin.style.data.entity.mapper;\n\nimport com.fernandocejas.arrow.checks.Preconditions;\nimport com.yalin.style"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/entity/mapper/WallpaperEntityMapper.java",
    "chars": 3506,
    "preview": "package com.yalin.style.data.entity.mapper;\n\nimport com.fernandocejas.arrow.checks.Preconditions;\nimport com.yalin.style"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/exception/LikeException.java",
    "chars": 271,
    "preview": "package com.yalin.style.data.exception;\n\n/**\n * @author jinyalin\n * @since 2017/4/29.\n */\n\npublic class LikeException ex"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/exception/NetworkConnectionException.java",
    "chars": 310,
    "preview": "package com.yalin.style.data.exception;\n\n/**\n * @author jinyalin\n * @since 2017/4/29.\n */\n\npublic class NetworkConnectio"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/exception/NoContentException.java",
    "chars": 145,
    "preview": "package com.yalin.style.data.exception;\n\n/**\n * @author jinyalin\n * @since 2017/7/31.\n */\n\npublic class NoContentExcepti"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/exception/RemoteServerException.java",
    "chars": 147,
    "preview": "package com.yalin.style.data.exception;\n\n/**\n * @author jinyalin\n * @since 2017/8/4.\n */\n\npublic class RemoteServerExcep"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/exception/ReswitchException.java",
    "chars": 283,
    "preview": "package com.yalin.style.data.exception;\n\n/**\n * @author jinyalin\n * @since 2017/4/29.\n */\n\npublic class ReswitchExceptio"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/executor/JobExecutor.java",
    "chars": 1124,
    "preview": "package com.yalin.style.data.executor;\n\nimport android.support.annotation.NonNull;\n\nimport com.yalin.style.domain.execut"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/executor/SerialJobExecutor.java",
    "chars": 1008,
    "preview": "package com.yalin.style.data.executor;\n\nimport android.support.annotation.NonNull;\n\n\nimport com.yalin.style.domain.execu"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/extensions/DelegateExt.kt",
    "chars": 1853,
    "preview": "package com.yalin.style.data.extensions\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport "
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/lock/LikeWallpaperLock.java",
    "chars": 756,
    "preview": "package com.yalin.style.data.lock;\n\nimport com.yalin.style.domain.executor.ThreadExecutor;\nimport com.yalin.style.domain"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/lock/OpenInputStreamLock.java",
    "chars": 602,
    "preview": "package com.yalin.style.data.lock;\n\nimport com.yalin.style.domain.executor.ThreadExecutor;\n\nimport io.reactivex.Observab"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/lock/ResourceLock.java",
    "chars": 1390,
    "preview": "package com.yalin.style.data.lock;\n\nimport com.yalin.style.domain.executor.ThreadExecutor;\nimport com.yalin.style.domain"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/lock/SelectSourceLock.java",
    "chars": 596,
    "preview": "package com.yalin.style.data.lock;\n\nimport com.yalin.style.domain.executor.ThreadExecutor;\n\nimport java.util.concurrent."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/log/LogUtil.java",
    "chars": 3688,
    "preview": "package com.yalin.style.data.log;\n\nimport android.os.Environment;\nimport android.os.Process;\nimport android.util.Log;\n\ni"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/observable/SourcesObservableImpl.kt",
    "chars": 2102,
    "preview": "package com.yalin.style.data.observable\n\nimport android.content.Context\nimport android.database.ContentObserver\nimport a"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/observable/WallpaperObservableImpl.kt",
    "chars": 3860,
    "preview": "package com.yalin.style.data.observable\n\nimport android.content.Context\nimport android.database.ContentObserver\nimport a"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/AdvanceWallpaperDataRepository.kt",
    "chars": 5257,
    "preview": "package com.yalin.style.data.repository\n\nimport android.content.Context\nimport com.yalin.style.data.entity.mapper.Advanc"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/GalleryWallpaperDataRepository.kt",
    "chars": 4386,
    "preview": "package com.yalin.style.data.repository\n\nimport com.yalin.style.data.entity.mapper.WallpaperEntityMapper\nimport com.yali"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/SourcesDataRepository.kt",
    "chars": 2130,
    "preview": "package com.yalin.style.data.repository\n\nimport android.content.Context\nimport com.yalin.style.data.entity.mapper.Wallpa"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/StyleWallpaperDataRepository.java",
    "chars": 6444,
    "preview": "package com.yalin.style.data.repository;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport com.fer"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStore.kt",
    "chars": 590,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport com.yalin.style.data.entity.AdvanceWallpaperEntity\nimport io."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStoreFactory.kt",
    "chars": 810,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.Context\nimport com.yalin.style.data.cache.Adv"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/AdvanceWallpaperDataStoreImpl.kt",
    "chars": 6705,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.ContentValues\nimport android.content.Context\n"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/CacheWallpaperDataStore.java",
    "chars": 1796,
    "preview": "package com.yalin.style.data.repository.datasource;\n\nimport com.yalin.style.data.cache.WallpaperCache;\nimport com.yalin."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/DbWallpaperDataStore.java",
    "chars": 6953,
    "preview": "package com.yalin.style.data.repository.datasource;\n\nimport android.content.ContentResolver;\nimport android.content.Cont"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/GalleryWallpaperDataStore.kt",
    "chars": 14844,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.ContentProviderOperation\nimport android.conte"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/GalleryWallpaperDataStoreFactory.kt",
    "chars": 661,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.Context\nimport com.yalin.style.data.cache.Gal"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/RemoteAdvanceWallpaperDataStore.kt",
    "chars": 4935,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.ContentProviderOperation\nimport android.conte"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStore.kt",
    "chars": 376,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport com.yalin.style.data.entity.SourceEntity\nimport io.reactivex."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStoreFactory.kt",
    "chars": 590,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.Context\nimport com.yalin.style.data.cache.Sou"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/SourcesDataStoreImpl.kt",
    "chars": 1233,
    "preview": "package com.yalin.style.data.repository.datasource\n\nimport android.content.Context\nimport com.yalin.style.data.cache.Sou"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/StyleWallpaperDataStoreFactory.java",
    "chars": 1688,
    "preview": "package com.yalin.style.data.repository.datasource;\n\n\nimport android.content.Context;\n\nimport com.yalin.style.data.cache"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/WallpaperDataStore.java",
    "chars": 542,
    "preview": "package com.yalin.style.data.repository.datasource;\n\nimport com.yalin.style.data.entity.WallpaperEntity;\n\nimport java.io"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/io/AdvanceWallpaperHandler.kt",
    "chars": 9092,
    "preview": "package com.yalin.style.data.repository.datasource.io\n\nimport android.content.ContentProviderOperation\nimport android.co"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/io/GalleryWallpapersHandler.kt",
    "chars": 4901,
    "preview": "package com.yalin.style.data.repository.datasource.io\n\nimport android.annotation.SuppressLint\nimport android.content.Con"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/io/JSONHandler.java",
    "chars": 2277,
    "preview": "package com.yalin.style.data.repository.datasource.io;\n\nimport android.content.ContentProviderOperation;\nimport android."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/io/RemoveGalleryWallpapersHandler.kt",
    "chars": 1016,
    "preview": "package com.yalin.style.data.repository.datasource.io\n\nimport android.content.ContentProviderOperation\nimport android.co"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/io/WallpapersHandler.java",
    "chars": 6347,
    "preview": "package com.yalin.style.data.repository.datasource.io;\n\nimport android.content.ContentProviderOperation;\nimport android."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/net/DataFetcher.java",
    "chars": 2679,
    "preview": "package com.yalin.style.data.repository.datasource.net;\n\nimport android.content.Context;\nimport android.text.TextUtils;\n"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/net/RemoteAdvanceWallpaperFetcher.java",
    "chars": 448,
    "preview": "package com.yalin.style.data.repository.datasource.net;\n\nimport android.content.Context;\n\nimport com.yalin.style.data.Bu"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContract.java",
    "chars": 6931,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\nimport android.net.Uri;\nimport android.provider.BaseColumn"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleContractHelper.java",
    "chars": 582,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\nimport android.net.Uri;\n\n/**\n * YaLin 2017/1/3.\n */\n\npubli"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleDatabase.java",
    "chars": 6416,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\nimport android.content.ContentResolver;\nimport android.con"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProvider.java",
    "chars": 10788,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\nimport android.content.ContentProvider;\nimport android.con"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleProviderUriMatcher.java",
    "chars": 1380,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\nimport android.content.UriMatcher;\nimport android.net.Uri;"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/provider/StyleUriEnum.java",
    "chars": 966,
    "preview": "package com.yalin.style.data.repository.datasource.provider;\n\n/**\n * YaLin 2016/12/30.\n */\n\npublic enum StyleUriEnum {\n "
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/RemoteStyleDataFetcher.java",
    "chars": 480,
    "preview": "package com.yalin.style.data.repository.datasource.sync;\n\nimport android.content.Context;\n\nimport com.yalin.style.data.B"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/StyleDataHandler.java",
    "chars": 4851,
    "preview": "package com.yalin.style.data.repository.datasource.sync;\n\nimport android.content.ContentProviderOperation;\nimport androi"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncAdapter.java",
    "chars": 1316,
    "preview": "package com.yalin.style.data.repository.datasource.sync;\n\nimport android.accounts.Account;\nimport android.content.Abstra"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncHelper.java",
    "chars": 2588,
    "preview": "package com.yalin.style.data.repository.datasource.sync;\n\n\nimport android.accounts.Account;\nimport android.content.Conte"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/SyncService.java",
    "chars": 718,
    "preview": "package com.yalin.style.data.repository.datasource.sync;\n\nimport android.app.Service;\nimport android.content.Intent;\nimp"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/Account.java",
    "chars": 1078,
    "preview": "package com.yalin.style.data.repository.datasource.sync.account;\n\nimport android.accounts.AccountManager;\nimport android"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/Authenticator.java",
    "chars": 2060,
    "preview": "package com.yalin.style.data.repository.datasource.sync.account;\n\nimport android.accounts.*;\nimport android.accounts.Acc"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/account/AuthenticatorService.java",
    "chars": 542,
    "preview": "package com.yalin.style.data.repository.datasource.sync.account;\n\nimport android.app.Service;\nimport android.content.Int"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/repository/datasource/sync/gallery/GalleryScheduleService.kt",
    "chars": 6308,
    "preview": "package com.yalin.style.data.repository.datasource.sync.gallery\n\nimport android.app.AlarmManager\nimport android.app.Inte"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/ChecksumUtil.java",
    "chars": 1122,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.util.Base64;\n\nimport java.io.File;\nimport java.io.FileInputStream;\ni"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/DeviceUtil.java",
    "chars": 1219,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport andr"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/FacetIdUtil.java",
    "chars": 805,
    "preview": "package com.yalin.style.data.utils;\n\n\nimport android.content.Context;\n\n/**\n * @author jinyalin\n * @since 2017/4/26.\n */\n"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/HttpRequestUtil.java",
    "chars": 943,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.content.Context;\n\nimport com.google.gson.Gson;\nimport com.yalin.styl"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/NativeFileHelper.kt",
    "chars": 1567,
    "preview": "package com.yalin.style.data.utils\n\nimport android.content.Context\nimport android.text.TextUtils\nimport com.yalin.style."
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/NetworkUtil.java",
    "chars": 665,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.content.Context;\nimport android.net.ConnectivityManager;\nimport andr"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/SelectionBuilder.java",
    "chars": 5255,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.content.ContentValues;\nimport android.database.Cursor;\nimport androi"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/TimeUtil.java",
    "chars": 229,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.content.Context;\n\n/**\n * YaLin 2017/1/3.\n */\n\npublic class TimeUtil "
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/UriUtil.kt",
    "chars": 9737,
    "preview": "package com.yalin.style.data.utils\n\nimport android.annotation.TargetApi\nimport android.content.Context\nimport android.co"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/WallpaperFileHelper.java",
    "chars": 7366,
    "preview": "package com.yalin.style.data.utils;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.ParcelFil"
  },
  {
    "path": "data/src/main/java/com/yalin/style/data/utils/WallpaperUtil.kt",
    "chars": 378,
    "preview": "package com.yalin.style.data.utils\n\nimport android.content.Context\nimport android.net.Uri\nimport com.yalin.style.data.re"
  },
  {
    "path": "data/src/main/res/values/strings.xml",
    "chars": 684,
    "preview": "<resources>\n    <string name=\"app_name\">Style</string>\n\n    <string name=\"authority\">com.yalin.style</string>\n\n    <stri"
  },
  {
    "path": "data/src/main/res/values-zh-rCN/strings.xml",
    "chars": 630,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">Style</string>\n\n    <string name=\"authori"
  },
  {
    "path": "data/src/main/res/xml/authenticator.xml",
    "chars": 289,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<account-authenticator xmlns:android=\"http://schemas.android.com/apk/res/android\""
  },
  {
    "path": "data/src/main/res/xml/syncadapter.xml",
    "chars": 267,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<sync-adapter xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  androi"
  },
  {
    "path": "data/src/test/java/com/yalin/data/ExampleUnitTest.java",
    "chars": 392,
    "preview": "package com.yalin.data;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit test, whic"
  },
  {
    "path": "domain/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "domain/build.gradle",
    "chars": 346,
    "preview": "apply plugin: 'java'\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n}\n\nsourceCompatibility = \"1.7"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/AdvanceWallpaper.java",
    "chars": 486,
    "preview": "package com.yalin.style.domain;\n\n/**\n * @author jinyalin\n * @since 2017/7/28.\n */\n\npublic class AdvanceWallpaper {\n    p"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/GalleryWallpaper.java",
    "chars": 276,
    "preview": "package com.yalin.style.domain;\n\n/**\n * @author jinyalin\n * @since 2017/5/24.\n */\n\npublic class GalleryWallpaper {\n    p"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/Source.java",
    "chars": 287,
    "preview": "package com.yalin.style.domain;\n\n/**\n * @author jinyalin\n * @since 2017/5/22.\n */\n\npublic class Source {\n    public int "
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/Wallpaper.java",
    "chars": 337,
    "preview": "package com.yalin.style.domain;\n\n/**\n * @author jinyalin\n * @since 2017/4/18.\n */\n\npublic class Wallpaper {\n\n    public "
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/exception/DefaultErrorBundle.java",
    "chars": 587,
    "preview": "package com.yalin.style.domain.exception;\n\n/**\n * @author jinyalin\n * @since 2017/4/18.\n */\n\npublic class DefaultErrorBu"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/exception/ErrorBundle.java",
    "chars": 187,
    "preview": "package com.yalin.style.domain.exception;\n\n/**\n * @author jinyalin\n * @since 2017/4/18.\n */\n\npublic interface ErrorBundl"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/executor/PostExecutionThread.java",
    "chars": 195,
    "preview": "package com.yalin.style.domain.executor;\n\nimport io.reactivex.Scheduler;\n\n/**\n * @author jinyalin\n * @since 2017/4/18.\n "
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/executor/SerialThreadExecutor.java",
    "chars": 190,
    "preview": "package com.yalin.style.domain.executor;\n\nimport java.util.concurrent.Executor;\n\n/**\n * @author jinyalin\n * @since 2017/"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/executor/ThreadExecutor.java",
    "chars": 184,
    "preview": "package com.yalin.style.domain.executor;\n\nimport java.util.concurrent.Executor;\n\n/**\n * @author jinyalin\n * @since 2017/"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/AddGalleryWallpaper.java",
    "chars": 1650,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.GalleryWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/DefaultObserver.java",
    "chars": 479,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport io.reactivex.observers.DisposableObserver;\n\n/**\n * @author jinyalin\n "
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/DownloadAdvanceWallpaper.java",
    "chars": 1488,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/ForceNow.java",
    "chars": 1418,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetAdvanceWallpapers.java",
    "chars": 1204,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.AdvanceWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetGalleryUpdateInterval.java",
    "chars": 1126,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetGalleryWallpaper.java",
    "chars": 1198,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.GalleryWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetSelectedAdvanceWallpaper.java",
    "chars": 607,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.AdvanceWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetSelectedSource.java",
    "chars": 507,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.repository.SourcesRepository;\n\nimport javax.in"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetSources.java",
    "chars": 1085,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.Source;\nimport com.yalin.style.domain.executor"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetWallpaper.java",
    "chars": 1095,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.Wallpaper;\nimport com.yalin.style.domain.execu"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/GetWallpaperCount.java",
    "chars": 1085,
    "preview": "package com.yalin.style.domain.interactor;\n\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yali"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/LikeWallpaper.java",
    "chars": 1581,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.fernandocejas.arrow.checks.Preconditions;\nimport com.yalin.style."
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/LoadAdvanceWallpaper.java",
    "chars": 1205,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.AdvanceWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/ObserverSources.java",
    "chars": 659,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.observable.SourcesObservable;\n\nimport javax.in"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/ObserverWallpaper.java",
    "chars": 687,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.observable.WallpaperObservable;\n\nimport javax."
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/OpenWallpaperInputStream.java",
    "chars": 1617,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.fernandocejas.arrow.checks.Preconditions;\nimport com.yalin.style."
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/ReadAdvanceAd.java",
    "chars": 1415,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/RemoveGalleryWallpaper.java",
    "chars": 1776,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.GalleryWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/SelectAdvanceWallpaper.java",
    "chars": 1664,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/SelectSource.java",
    "chars": 1498,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/SetGalleryUpdateInterval.java",
    "chars": 1484,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.executor.PostExecutionThread;\nimport com.yalin"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/SwitchWallpaper.java",
    "chars": 1117,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.yalin.style.domain.Wallpaper;\nimport com.yalin.style.domain.execu"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/interactor/UseCase.java",
    "chars": 2361,
    "preview": "package com.yalin.style.domain.interactor;\n\nimport com.fernandocejas.arrow.checks.Preconditions;\nimport com.yalin.style."
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/observable/SourcesObservable.java",
    "chars": 313,
    "preview": "package com.yalin.style.domain.observable;\n\nimport com.yalin.style.domain.interactor.DefaultObserver;\n\n/**\n * @author ji"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/observable/WallpaperObservable.java",
    "chars": 315,
    "preview": "package com.yalin.style.domain.observable;\n\nimport com.yalin.style.domain.interactor.DefaultObserver;\n\n/**\n * @author ji"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/repository/SourcesRepository.java",
    "chars": 518,
    "preview": "package com.yalin.style.domain.repository;\n\nimport com.yalin.style.domain.Source;\n\nimport java.util.List;\n\nimport io.rea"
  },
  {
    "path": "domain/src/main/java/com/yalin/style/domain/repository/WallpaperRepository.java",
    "chars": 1411,
    "preview": "package com.yalin.style.domain.repository;\n\nimport com.yalin.style.domain.AdvanceWallpaper;\nimport com.yalin.style.domai"
  },
  {
    "path": "engine/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "engine/build.gradle",
    "chars": 1520,
    "preview": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\n\nandroid {\n    compileSdkVersion COMPILE_SDK_VERSION "
  },
  {
    "path": "engine/proguard-rules.pro",
    "chars": 937,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in /U"
  },
  {
    "path": "engine/src/androidTest/java/com/yalin/style/engine/ExampleInstrumentedTest.java",
    "chars": 753,
    "preview": "package com.yalin.style.engine;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nim"
  },
  {
    "path": "engine/src/main/AndroidManifest.xml",
    "chars": 230,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n\n    package=\"com.yalin.style.engine\">\n\n    <applic"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/GDXWallpaperServiceProxy.kt",
    "chars": 2293,
    "preview": "package com.yalin.style.engine\n\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android."
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/GLWallpaperServiceProxy.kt",
    "chars": 2230,
    "preview": "package com.yalin.style.engine\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.c"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/IProvider.java",
    "chars": 233,
    "preview": "package com.yalin.style.engine;\n\nimport android.content.Context;\nimport android.service.wallpaper.WallpaperService;\n\n/**"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/ProxyApi.java",
    "chars": 1278,
    "preview": "package com.yalin.style.engine;\n\nimport android.content.Context;\nimport android.service.wallpaper.WallpaperService;\n\nimp"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/ProxyProvider.kt",
    "chars": 1398,
    "preview": "package com.yalin.style.engine\n\nimport android.content.Context\nimport android.service.wallpaper.WallpaperService\nimport "
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/WallpaperActiveCallback.kt",
    "chars": 179,
    "preview": "package com.yalin.style.engine\n\n/**\n * @author jinyalin\n * @since 2017/8/1.\n */\ninterface WallpaperActiveCallback {\n    "
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/WallpaperServiceProxy.kt",
    "chars": 2294,
    "preview": "package com.yalin.style.engine\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.c"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/advance/AnimationWallpaper.java",
    "chars": 2315,
    "preview": "/*\n * Copyright (C) 2007 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/advance/BokehRainbowCircle.java",
    "chars": 1856,
    "preview": "/*\n * Copyright (C) 2007 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/advance/BokehRainbowWallpaper.java",
    "chars": 5312,
    "preview": "/*\n * Copyright (C) 2007 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/component/ComponentContext.java",
    "chars": 2039,
    "preview": "package com.yalin.style.engine.component;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/component/StyleClassLoader.kt",
    "chars": 3757,
    "preview": "package com.yalin.style.engine.component\n\nimport android.content.Context\nimport android.os.Build\nimport android.util.Log"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/resource/BrandUtil.java",
    "chars": 782,
    "preview": "package com.yalin.style.engine.resource;\n\nimport android.content.res.Resources;\n\n/**\n * @author jinyalin\n * @since 2017/"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/resource/CompatResources.java",
    "chars": 15437,
    "preview": "package com.yalin.style.engine.resource;\n\nimport android.content.res.AssetFileDescriptor;\nimport android.content.res.Ass"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/resource/ReflectUtil.java",
    "chars": 2845,
    "preview": "package com.yalin.style.engine.resource;\n\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport j"
  },
  {
    "path": "engine/src/main/java/com/yalin/style/engine/resource/ResourcesManager.java",
    "chars": 8559,
    "preview": "package com.yalin.style.engine.resource;\n\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport "
  },
  {
    "path": "engine/src/main/java/net/rbgrn/android/glwallpaperservice/BaseConfigChooser.java",
    "chars": 6922,
    "preview": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "engine/src/main/java/net/rbgrn/android/glwallpaperservice/GLWallpaperService.java",
    "chars": 36299,
    "preview": "/*\n * Copyright (C) 2008 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "engine/src/main/res/values/strings.xml",
    "chars": 69,
    "preview": "<resources>\n    <string name=\"app_name\">engine</string>\n</resources>\n"
  },
  {
    "path": "engine/src/test/java/com/yalin/style/engine/ExampleUnitTest.java",
    "chars": 400,
    "preview": "package com.yalin.style.engine;\n\nimport org.junit.Test;\n\nimport static org.junit.Assert.*;\n\n/**\n * Example local unit te"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 230,
    "preview": "#Tue Apr 18 15:48:48 CST 2017\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 659,
    "preview": "COMPILE_SDK_VERSION=25\nBUILD_TOOLS_VERSION=25.0.2\nMIN_SDK_VERSION=19\nTARGET_SDK_VERSION=25\n\nAPP_VERSION_NAME=2.7.1\nAPP_V"
  },
  {
    "path": "gradlew",
    "chars": 4971,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "presentation/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "presentation/build.gradle",
    "chars": 4744,
    "preview": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-kapt'\napply plugin: 'kotlin"
  },
  {
    "path": "presentation/component-proguard.pro",
    "chars": 1235,
    "preview": "# for component\n-keep public class com.yalin.style.engine.StyleWallpaperProxy{\n    *;\n}\n-keep public class com.yalin.sty"
  },
  {
    "path": "presentation/google-services.json",
    "chars": 1009,
    "preview": "{\n  \"project_info\": {\n    \"project_number\": \"938703193302\",\n    \"firebase_url\": \"https://style-997fc.firebaseio.com\",\n  "
  },
  {
    "path": "presentation/proguard-rules.pro",
    "chars": 3599,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
  },
  {
    "path": "presentation/src/androidTest/java/com/yalin/style/ExampleInstrumentedTest.java",
    "chars": 718,
    "preview": "package com.yalin.style;\n\nimport android.content.Context;\nimport android.support.test.InstrumentationRegistry;\nimport an"
  },
  {
    "path": "presentation/src/androidTest/java/com/yalin/style/provider/DatabaseTest.java",
    "chars": 2212,
    "preview": "package com.yalin.style.provider;\n\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android."
  },
  {
    "path": "presentation/src/androidTest/java/com/yalin/style/sync/SyncAdapterTest.java",
    "chars": 1106,
    "preview": "package com.yalin.style.sync;\n\nimport android.accounts.Account;\nimport android.content.ContentResolver;\nimport android.o"
  },
  {
    "path": "presentation/src/demo/java/com/yalin/style/util/AdUtil.kt",
    "chars": 1642,
    "preview": "package com.yalin.style.util\n\nimport android.app.Activity\nimport com.google.android.gms.ads.*\nimport com.yalin.style.R\ni"
  },
  {
    "path": "presentation/src/demo/res/values/ad_strings.xml",
    "chars": 507,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"test_id\" translatable=\"false\">ca-app-pub-3940256099"
  },
  {
    "path": "presentation/src/main/AndroidManifest.xml",
    "chars": 3668,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/LockScreenVisibleReceiver.kt",
    "chars": 287,
    "preview": "package com.yalin.style\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content."
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/StyleApplication.kt",
    "chars": 2567,
    "preview": "package com.yalin.style\n\n//import com.facebook.stetho.Stetho\n\nimport android.content.Context\nimport android.support.mult"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/StyleWallpaperService.kt",
    "chars": 3121,
    "preview": "package com.yalin.style\n\nimport android.app.WallpaperManager\nimport android.content.ActivityNotFoundException\nimport and"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/StyleWallpaperServiceMirror.kt",
    "chars": 229,
    "preview": "package com.yalin.style\n\n/**\n * YaLin 2016/12/30.\n */\nclass StyleWallpaperServiceMirror : StyleWallpaperService() {\n\n   "
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/UIThread.kt",
    "chars": 456,
    "preview": "package com.yalin.style\n\nimport com.yalin.style.domain.executor.PostExecutionThread\n\nimport javax.inject.Inject\nimport j"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/WallpaperDetailViewport.kt",
    "chars": 2306,
    "preview": "/*\n * Copyright 2014 Google Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not us"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/analytics/Analytics.kt",
    "chars": 1506,
    "preview": "package com.yalin.style.analytics\n\nimport android.content.Context\nimport android.os.Bundle\n\nimport com.flurry.android.Fl"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/analytics/Event.kt",
    "chars": 1413,
    "preview": "package com.yalin.style.analytics\n\n\n/**\n * @author jinyalin\n * *\n * @since 2017/5/3.\n */\n\nobject Event {\n    val SETTING"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/analytics/IAnalytics.kt",
    "chars": 455,
    "preview": "package com.yalin.style.analytics\n\nimport android.content.Context\n\n/**\n * @author jinyalin\n * *\n * @since 2017/8/4.\n */\n"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/engine/StyleWallpaperProxy.kt",
    "chars": 10991,
    "preview": "package com.yalin.style.engine\n\nimport android.app.KeyguardManager\nimport android.app.WallpaperManager\nimport android.co"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/MainContainerInsetsChangedEvent.java",
    "chars": 342,
    "preview": "package com.yalin.style.event;\n\nimport android.graphics.Rect;\n\n/**\n * @author jinyalin\n * @since 2017/4/25.\n */\n\npublic "
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/SeenTutorialEvent.java",
    "chars": 116,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/5/2.\n */\n\npublic class SeenTutorialEvent {\n}\n"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/StyleWallpaperSizeChangedEvent.java",
    "chars": 421,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/25.\n */\n\npublic class StyleWallpaperSizeChanged"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/SwitchWallpaperServiceEvent.java",
    "chars": 127,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/7/31.\n */\n\npublic class SwitchWallpaperServiceEve"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/SwitchingPhotosStateChangedEvent.java",
    "chars": 479,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/25.\n */\n\npublic class SwitchingPhotosStateChang"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/SystemWallpaperSizeChangedEvent.java",
    "chars": 423,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/25.\n */\n\npublic class SystemWallpaperSizeChange"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/WallpaperActivateEvent.java",
    "chars": 373,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/21.\n */\n\npublic class WallpaperActivateEvent {\n"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/WallpaperDetailOpenedEvent.java",
    "chars": 405,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/21.\n */\n\npublic class WallpaperDetailOpenedEven"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/event/WallpaperSwitchEvent.java",
    "chars": 120,
    "preview": "package com.yalin.style.event;\n\n/**\n * @author jinyalin\n * @since 2017/4/28.\n */\n\npublic class WallpaperSwitchEvent {\n}\n"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/exception/ErrorMessageFactory.java",
    "chars": 1533,
    "preview": "package com.yalin.style.exception;\n\nimport android.content.Context;\n\nimport com.yalin.style.R;\nimport com.yalin.style.da"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/extensions/DelegatesExtensions.kt",
    "chars": 789,
    "preview": "package com.yalin.style.extensions\n\nimport kotlin.properties.ReadWriteProperty\nimport kotlin.reflect.KProperty\n\n/**\n * @"
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/injection/HasComponent.kt",
    "chars": 141,
    "preview": "package com.yalin.style.injection\n\n/**\n * @author jinyalin\n * *\n * @since 2017/4/20.\n */\n\ninterface HasComponent<C> {\n  "
  },
  {
    "path": "presentation/src/main/java/com/yalin/style/injection/PerActivity.kt",
    "chars": 193,
    "preview": "package com.yalin.style.injection\n\n\nimport javax.inject.Scope\n\n/**\n * @author jinyalin\n * *\n * @since 2017/4/20.\n */\n@Sc"
  }
]

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

About this extraction

This page contains the full source code of the jinkg/Style GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 342 files (868.2 KB), approximately 198.9k tokens, and a symbol index with 1055 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!