From c38cd82bf178e290a655cde1848096652799ad13 Mon Sep 17 00:00:00 2001 From: David Hamm Date: Sun, 6 Jul 2014 22:54:16 +0200 Subject: [PATCH] switched to gradle build system --- .classpath | 10 - .gitignore | 9 +- .idea/.name | 1 + .idea/codeStyleSettings.xml | 202 ++ .idea/compiler.xml | 23 + .idea/copyright/profiles_settings.xml | 3 + .idea/encodings.xml | 5 + .idea/gradle.xml | 18 + .idea/libraries/acra_4_4_0.xml | 11 + .idea/libraries/jackson_core_lgpl_1_9_13.xml | 11 + .../libraries/jackson_mapper_lgpl_1_9_13.xml | 11 + .idea/libraries/jmdns_3_4_1.xml | 11 + .idea/misc.xml | 10 + .idea/modules.xml | 10 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 7 + .project | 33 - .settings/org.eclipse.jdt.core.prefs | 5 - AndroidManifest.xml | 112 - android-xbmcremote.iml | 19 + ant.properties | 1 - app/.gitignore | 1 + app/app.iml | 70 + app/build.gradle | 32 + app/proguard-rules.pro | 17 + app/src/main/AndroidManifest.xml | 178 ++ .../remote/business/AbstractManager.java | 791 ++++--- .../remote/business/AbstractThread.java | 255 +- .../android/remote/business/CacheManager.java | 46 +- .../xbmc/android/remote/business/Command.java | 27 +- .../remote/business/ControlManager.java | 628 ++--- .../remote/business/DiskCacheThread.java | 296 +-- .../remote/business/DownloadThread.java | 389 +-- .../remote/business/EventClientManager.java | 265 +-- .../android/remote/business/InfoManager.java | 390 +-- .../remote/business/ManagerFactory.java | 119 +- .../remote/business/ManagerThread.java | 215 +- .../remote/business/MemCacheThread.java | 340 +-- .../android/remote/business/MusicManager.java | 1339 ++++++----- .../business/NowPlayingPollerThread.java | 90 +- .../remote/business/TvShowManager.java | 81 +- .../android/remote/business/VideoManager.java | 544 ++--- .../business/provider/HostProvider.java | 870 ++++--- .../receiver/AndroidBroadcastReceiver.java | 88 +- .../business/receiver/AutoStartReceiver.java | 114 +- .../presentation/activity/AboutActivity.java | 185 +- .../activity/AbsListActivity.java | 391 +-- .../activity/ConfigurationManager.java | 268 +-- .../presentation/activity/DialogFactory.java | 156 +- .../activity/EpisodeDetailsActivity.java | 664 +++--- .../activity/GestureRemoteActivity.java | 51 +- .../presentation/activity/GridActivity.java | 85 +- .../presentation/activity/HomeActivity.java | 227 +- .../activity/HostSettingsActivity.java | 223 +- .../presentation/activity/ListActivity.java | 85 +- .../activity/MediaIntentActivity.java | 23 +- .../activity/MovieDetailsActivity.java | 665 +++--- .../activity/MovieLibraryActivity.java | 586 ++--- .../activity/MusicArtistActivity.java | 412 ++-- .../activity/MusicGenreActivity.java | 461 ++-- .../activity/MusicLibraryActivity.java | 635 ++--- .../activity/NowPlayingActivity.java | 135 +- .../activity/PlaylistActivity.java | 76 +- .../presentation/activity/RemoteActivity.java | 75 +- .../activity/SettingsActivity.java | 218 +- .../activity/TvShowDetailsActivity.java | 599 ++--- .../activity/TvShowLibraryActivity.java | 584 ++--- .../activity/UrlIntentActivity.java | 135 +- .../appwidget/RemoteControllerWidget.java | 28 +- .../controller/AbstractController.java | 671 +++--- .../controller/ActorListController.java | 124 +- .../controller/AlbumListController.java | 406 ++-- .../controller/AppWidgetRemoteController.java | 95 +- .../controller/ArtistListController.java | 149 +- .../controller/EpisodeListController.java | 349 +-- .../controller/FileListController.java | 240 +- .../controller/GestureController.java | 185 +- .../controller/HomeController.java | 1215 +++++----- .../controller/HostPreference.java | 490 ++-- .../presentation/controller/IController.java | 57 +- .../controller/ListController.java | 509 ++-- .../ListControllerOnKeyListener.java | 72 +- .../controller/MediaIntentController.java | 103 +- .../controller/MovieGenreListController.java | 109 +- .../controller/MovieListController.java | 363 +-- .../controller/MusicGenreListController.java | 102 +- .../controller/MusicPlaylistController.java | 332 +-- .../controller/NowPlayingController.java | 457 ++-- .../controller/PlaylistController.java | 533 +++-- .../controller/RemoteController.java | 1104 ++++----- .../controller/SeasonListController.java | 150 +- .../controller/SettingsController.java | 116 +- .../controller/SongListController.java | 387 +-- .../controller/TvShowListController.java | 316 +-- .../controller/UrlIntentController.java | 693 +++--- .../drawable/CrossFadeDrawable.java | 284 +++ .../drawable/FastBitmapDrawable.java | 78 +- .../BigPictureNotificationBuilder.java | 37 + .../LargeIconNotificationBuilder.java | 52 + .../notification/NotificationBuilder.java | 62 + .../NowPlayingNotificationManager.java | 162 ++ .../presentation/widget/AbstractItemView.java | 284 ++- .../widget/FiveLabelsItemView.java | 244 +- .../presentation/widget/FlexibleItemView.java | 245 +- .../widget/GridPosterItemView.java | 113 +- .../remote/presentation/widget/JewelView.java | 496 ++-- .../presentation/widget/OneLabelItemView.java | 107 +- .../widget/ThreeLabelsItemView.java | 126 +- .../remote/presentation/wizard/Wizard.java | 260 +- .../presentation/wizard/WizardPage.java | 220 +- .../wizard/listener/ActionListener.java | 15 +- .../listener/PageCanFinishListener.java | 14 +- .../wizard/setupwizard/SetupWizard.java | 58 +- .../wizard/setupwizard/SetupWizardPage1.java | 321 ++- .../wizard/setupwizard/SetupWizardPage2.java | 344 +-- .../wizard/setupwizard/SetupWizardPage3.java | 255 +- .../setupwizard/SetupWizardPageLogin.java | 218 +- .../java/org/xbmc/android/util/Base64.java | 2094 +++++++++++++++++ .../org/xbmc/android/util/ClientFactory.java | 599 ++--- .../xbmc/android/util/ConnectionFactory.java | 175 +- .../java}/org/xbmc/android/util/Crc32.java | 173 +- .../org/xbmc/android/util/HostFactory.java | 564 ++--- .../org/xbmc/android/util/IOUtilities.java | 65 + .../xbmc/android/util/ImportUtilities.java | 222 +- .../org/xbmc/android/util/KeyTracker.java | 106 + .../xbmc/android/util/MacAddressResolver.java | 43 +- .../util/OnLongPressBackKeyTracker.java | 38 + .../org/xbmc/android/util/PowerDown.java | 11 +- .../org/xbmc/android/util/SMSConstants.java | 76 +- .../org/xbmc/android/util/SmsMmsMessage.java | 837 ++++--- .../org/xbmc/android/util/SmsPopupUtils.java | 2042 ++++++++-------- .../java/org/xbmc/android/util/WakeOnLan.java | 79 + .../org/xbmc/android/util/WifiHelper.java | 93 +- .../xbmc/android/util/YoutubeURLParser.java | 10 +- .../xbmc/android/widget/FastScrollView.java | 49 +- .../xbmc/android/widget/IdleListDetector.java | 31 +- .../org/xbmc/android/widget/IdleListener.java | 15 +- .../gestureremote/GestureRemoteAnimation.java | 187 +- .../gestureremote/GestureRemoteCursor.java | 297 ++- .../gestureremote/GestureRemoteView.java | 1135 +++++---- .../gestureremote/IGestureListener.java | 83 +- .../slidingtabs/SlidingTabActivity.java | 423 ++-- .../widget/slidingtabs/SlidingTabHost.java | 1174 ++++----- .../slidingtabs/SlidingTabScrollView.java | 124 +- .../widget/slidingtabs/SlidingTabWidget.java | 1132 ++++----- .../widget/slidingtabs/SnapAnimation.java | 196 +- .../org/xbmc/api/business/CoverResponse.java | 107 +- .../org/xbmc/api/business/DataResponse.java | 101 +- .../xbmc/api/business/IControlManager.java | 385 +-- .../api/business/IEventClientManager.java | 113 + .../org/xbmc/api/business/IInfoManager.java | 222 +- .../java}/org/xbmc/api/business/IManager.java | 98 +- .../org/xbmc/api/business/IMusicManager.java | 578 ++--- .../xbmc/api/business/INotifiableManager.java | 73 +- .../xbmc/api/business/ISortableManager.java | 82 +- .../org/xbmc/api/business/ITvShowManager.java | 53 +- .../org/xbmc/api/business/IVideoManager.java | 307 +-- .../main/java}/org/xbmc/api/data/IClient.java | 83 +- .../org/xbmc/api/data/IControlClient.java | 668 +++--- .../java}/org/xbmc/api/data/IEventClient.java | 290 ++- .../java}/org/xbmc/api/data/IInfoClient.java | 261 +- .../java}/org/xbmc/api/data/IMusicClient.java | 675 +++--- .../org/xbmc/api/data/IPictureClient.java | 65 +- .../org/xbmc/api/data/ITvShowClient.java | 63 +- .../java}/org/xbmc/api/data/IVideoClient.java | 314 +-- .../java}/org/xbmc/api/info/FileTypes.java | 232 +- .../java/org/xbmc/api/info/GuiActions.java | 275 +++ .../java}/org/xbmc/api/info/GuiSettings.java | 94 +- .../java/org/xbmc/api/info/MusicInfo.java | 48 + .../java}/org/xbmc/api/info/PlayStatus.java | 96 +- .../java/org/xbmc/api/info/SystemInfo.java | 75 + .../java/org/xbmc/api/info/VideoInfo.java | 61 + .../main/java}/org/xbmc/api/object/Actor.java | 30 +- .../main/java}/org/xbmc/api/object/Album.java | 162 +- .../java}/org/xbmc/api/object/Artist.java | 121 +- .../java}/org/xbmc/api/object/Episode.java | 48 +- .../org/xbmc/api/object/FileLocation.java | 54 +- .../main/java}/org/xbmc/api/object/Genre.java | 33 +- .../main/java}/org/xbmc/api/object/Host.java | 261 +- .../java}/org/xbmc/api/object/ICoverArt.java | 72 +- .../org/xbmc/api/object/INamedResource.java | 0 .../main/java}/org/xbmc/api/object/Movie.java | 236 +- .../java}/org/xbmc/api/object/Season.java | 14 +- .../main/java}/org/xbmc/api/object/Song.java | 157 +- .../java}/org/xbmc/api/object/TvShow.java | 77 +- .../presentation/INotifiableController.java | 65 +- .../java}/org/xbmc/api/type/CacheType.java | 4 +- .../org/xbmc/api/type/DirectoryMask.java | 22 +- .../java}/org/xbmc/api/type/ListType.java | 2 +- .../main/java}/org/xbmc/api/type/LogType.java | 0 .../java}/org/xbmc/api/type/MediaType.java | 39 +- .../java}/org/xbmc/api/type/SeekType.java | 0 .../java}/org/xbmc/api/type/SortType.java | 6 +- .../java}/org/xbmc/api/type/ThumbSize.java | 136 +- .../org/xbmc/eventclient/ButtonCodes.java | 358 +-- .../org/xbmc/eventclient/EventClient.java | 205 +- .../java}/org/xbmc/eventclient/Packet.java | 212 +- .../org/xbmc/eventclient/PacketACTION.java | 26 +- .../org/xbmc/eventclient/PacketBUTTON.java | 142 ++ .../java}/org/xbmc/eventclient/PacketBYE.java | 11 +- .../org/xbmc/eventclient/PacketHELO.java | 26 +- .../java}/org/xbmc/eventclient/PacketLOG.java | 29 +- .../org/xbmc/eventclient/PacketMOUSE.java | 15 +- .../xbmc/eventclient/PacketNOTIFICATION.java | 33 +- .../org/xbmc/eventclient/PacketPING.java | 8 +- .../org/xbmc/httpapi/BroadcastListener.java | 696 +++--- .../java}/org/xbmc/httpapi/Connection.java | 1111 ++++----- .../main/java}/org/xbmc/httpapi/HttpApi.java | 18 +- .../org/xbmc/httpapi/NoNetworkException.java | 69 +- .../org/xbmc/httpapi/NoSettingsException.java | 74 +- .../org/xbmc/httpapi/WifiStateException.java | 4 +- .../httpapi/WrongDataFormatException.java | 89 +- .../java}/org/xbmc/httpapi/client/Client.java | 564 ++--- .../xbmc/httpapi/client/ControlClient.java | 278 ++- .../org/xbmc/httpapi/client/InfoClient.java | 385 +-- .../org/xbmc/httpapi/client/MusicClient.java | 639 ++--- .../xbmc/httpapi/client/PictureClient.java | 24 +- .../org/xbmc/httpapi/client/TvShowClient.java | 358 +-- .../org/xbmc/httpapi/client/VideoClient.java | 530 +++-- .../java}/org/xbmc/jsonrpc/Connection.java | 215 +- .../main/java}/org/xbmc/jsonrpc/JsonRpc.java | 20 +- .../java}/org/xbmc/jsonrpc/client/Client.java | 268 ++- .../xbmc/jsonrpc/client/ControlClient.java | 428 ++-- .../org/xbmc/jsonrpc/client/InfoClient.java | 135 +- .../org/xbmc/jsonrpc/client/MusicClient.java | 564 +++-- .../org/xbmc/jsonrpc/client/TvShowClient.java | 488 ++-- .../org/xbmc/jsonrpc/client/VideoClient.java | 386 +-- app/src/main/res/anim/slide_left.xml | 8 + app/src/main/res/anim/slide_right.xml | 9 + .../main/res}/drawable-hdpi-v4/about_back.png | Bin .../drawable-hdpi-v4/bottom_logo_down.png | Bin .../res}/drawable-hdpi-v4/bottom_logo_up.png | Bin .../drawable-hdpi-v4/bottom_text_down.9.png | Bin .../drawable-hdpi-v4/bottom_text_up.9.png | Bin .../res}/drawable-hdpi-v4/bottombar_bg.png | Bin .../main/res}/drawable-hdpi-v4/bubble_add.png | Bin .../res}/drawable-hdpi-v4/bubble_del_down.png | Bin .../res}/drawable-hdpi-v4/bubble_del_up.png | Bin .../res}/drawable-hdpi-v4/coverbox_back.png | Bin .../res}/drawable-hdpi-v4/default_album.png | Bin .../res}/drawable-hdpi-v4/default_jewel.png | Bin .../res}/drawable-hdpi-v4/default_poster.png | Bin .../res}/drawable-hdpi-v4/default_season.png | Bin .../res}/drawable-hdpi-v4/default_tvshow.png | Bin .../src/main/res}/drawable-hdpi-v4/icon.png | Bin .../main/res}/drawable-hdpi-v4/icon_album.png | Bin .../res}/drawable-hdpi-v4/icon_album_dark.png | Bin .../drawable-hdpi-v4/icon_album_dark_big.png | Bin .../res}/drawable-hdpi-v4/icon_artist.png | Bin .../drawable-hdpi-v4/icon_artist_dark.png | Bin .../main/res}/drawable-hdpi-v4/icon_file.png | Bin .../res}/drawable-hdpi-v4/icon_folder.png | Bin .../drawable-hdpi-v4/icon_folder_dark.png | Bin .../main/res}/drawable-hdpi-v4/icon_genre.png | Bin .../res}/drawable-hdpi-v4/icon_genre_dark.png | Bin .../res}/drawable-hdpi-v4/icon_home_movie.png | Bin .../res}/drawable-hdpi-v4/icon_home_music.png | Bin .../drawable-hdpi-v4/icon_home_picture.png | Bin .../drawable-hdpi-v4/icon_home_playing.png | Bin .../res}/drawable-hdpi-v4/icon_home_power.png | Bin .../drawable-hdpi-v4/icon_home_reconnect.png | Bin .../drawable-hdpi-v4/icon_home_remote.png | Bin .../res}/drawable-hdpi-v4/icon_home_tv.png | Bin .../res}/drawable-hdpi-v4/icon_lastfm.png | Bin .../res}/drawable-hdpi-v4/icon_movie_dark.png | Bin .../res}/drawable-hdpi-v4/icon_picture.png | Bin .../main/res}/drawable-hdpi-v4/icon_play.png | Bin .../drawable-hdpi-v4/icon_playlist_dark.png | Bin .../res}/drawable-hdpi-v4/icon_shoutcast.png | Bin .../main/res}/drawable-hdpi-v4/icon_song.png | Bin .../res}/drawable-hdpi-v4/icon_song_dark.png | Bin .../res}/drawable-hdpi-v4/icon_song_light.png | Bin .../res}/drawable-hdpi-v4/icon_va_dark.png | Bin .../main/res}/drawable-hdpi-v4/icon_video.png | Bin .../main/res}/drawable-hdpi-v4/jewel_cd.9.png | Bin .../res}/drawable-hdpi-v4/jewel_dvd.9.png | Bin .../main/res}/drawable-hdpi-v4/jewel_tv.9.png | Bin .../drawable-hdpi-v4/layout_top_bar.9.png | Bin .../main/res}/drawable-hdpi-v4/menu_about.png | Bin .../res}/drawable-hdpi-v4/menu_add_host.png | Bin .../main/res}/drawable-hdpi-v4/menu_album.png | Bin .../res}/drawable-hdpi-v4/menu_download.png | Bin .../main/res}/drawable-hdpi-v4/menu_exit.png | Bin .../drawable-hdpi-v4/menu_gesture_mode.png | Bin .../drawable-hdpi-v4/menu_hide_watched.png | Bin .../res}/drawable-hdpi-v4/menu_nowplaying.png | Bin .../res}/drawable-hdpi-v4/menu_qr_code.png | Bin .../res}/drawable-hdpi-v4/menu_refresh.png | Bin .../res}/drawable-hdpi-v4/menu_remote.png | Bin .../res}/drawable-hdpi-v4/menu_settings.png | Bin .../drawable-hdpi-v4/menu_show_watched.png | Bin .../main/res}/drawable-hdpi-v4/menu_song.png | Bin .../main/res}/drawable-hdpi-v4/menu_sort.png | Bin .../res}/drawable-hdpi-v4/menu_switch.png | Bin .../res}/drawable-hdpi-v4/menu_text_entry.png | Bin .../main/res}/drawable-hdpi-v4/menu_view.png | Bin .../res}/drawable-hdpi-v4/menu_xbmc_exit.png | Bin .../res}/drawable-hdpi-v4/menu_xbmc_s.png | Bin .../now_playing_next_down.png | Bin .../drawable-hdpi-v4/now_playing_next_up.png | Bin .../now_playing_pause_down.png | Bin .../drawable-hdpi-v4/now_playing_pause_up.png | Bin .../now_playing_play_down.png | Bin .../drawable-hdpi-v4/now_playing_play_up.png | Bin .../now_playing_playlist_down.png | Bin .../now_playing_playlist_up.png | Bin .../now_playing_previous_down.png | Bin .../now_playing_previous_up.png | Bin .../now_playing_stop_down.png | Bin .../drawable-hdpi-v4/now_playing_stop_up.png | Bin .../main/res}/drawable-hdpi-v4/pgbar_act.png | Bin .../res}/drawable-hdpi-v4/pgbar_thumb.png | Bin .../drawable-hdpi-v4/playlist_rightboxes.png | Bin .../drawable-hdpi-v4/remote_gest_cursor.png | Bin .../remote_xbox__top_left.png | Bin .../remote_xbox__top_right.png | Bin .../res/drawable-hdpi-v4/remote_xbox_back.xml | 5 + .../remote_xbox_back_down.png | Bin .../drawable-hdpi-v4/remote_xbox_back_up.png | Bin .../drawable-hdpi-v4/remote_xbox_display.xml | 5 + .../remote_xbox_display_down.png | Bin .../remote_xbox_display_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_down.xml | 5 + .../remote_xbox_down_down.png | Bin .../drawable-hdpi-v4/remote_xbox_down_up.png | Bin .../remote_xbox_gesture_back_down.png | Bin .../remote_xbox_gesture_info_down.png | Bin .../remote_xbox_gesture_menu_down.png | Bin .../remote_xbox_gesture_title_down.png | Bin .../remote_xbox_gesturezone.png | Bin .../remote_xbox_gesturezone_dim.png | Bin .../drawable-hdpi-v4/remote_xbox_images.xml | 5 + .../remote_xbox_images_down.png | Bin .../remote_xbox_images_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_info.xml | 5 + .../remote_xbox_info_down.png | Bin .../drawable-hdpi-v4/remote_xbox_info_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_left.xml | 5 + .../remote_xbox_left_down.png | Bin .../drawable-hdpi-v4/remote_xbox_left_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_menu.xml | 5 + .../remote_xbox_menu_down.png | Bin .../drawable-hdpi-v4/remote_xbox_menu_up.png | Bin .../drawable-hdpi-v4/remote_xbox_music.xml | 5 + .../remote_xbox_music_down.png | Bin .../drawable-hdpi-v4/remote_xbox_music_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_next.xml | 5 + .../remote_xbox_next_down.png | Bin .../drawable-hdpi-v4/remote_xbox_next_up.png | Bin .../drawable-hdpi-v4/remote_xbox_pause.xml | 5 + .../remote_xbox_pause_down.png | Bin .../drawable-hdpi-v4/remote_xbox_pause_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_play.xml | 5 + .../remote_xbox_play_down.png | Bin .../drawable-hdpi-v4/remote_xbox_play_up.png | Bin .../drawable-hdpi-v4/remote_xbox_previous.xml | 5 + .../remote_xbox_previous_down.png | Bin .../remote_xbox_previous_up.png | Bin .../drawable-hdpi-v4/remote_xbox_right.xml | 5 + .../remote_xbox_right_down.png | Bin .../drawable-hdpi-v4/remote_xbox_right_up.png | Bin .../remote_xbox_seek_back.xml | 5 + .../remote_xbox_seek_back_down.png | Bin .../remote_xbox_seek_back_up.png | Bin .../remote_xbox_seek_forward.xml | 5 + .../remote_xbox_seek_forward_down.png | Bin .../remote_xbox_seek_forward_up.png | Bin .../drawable-hdpi-v4/remote_xbox_select.xml | 5 + .../remote_xbox_select_down.png | Bin .../remote_xbox_select_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_stop.xml | 5 + .../remote_xbox_stop_down.png | Bin .../drawable-hdpi-v4/remote_xbox_stop_up.png | Bin .../drawable-hdpi-v4/remote_xbox_title.xml | 5 + .../remote_xbox_title_down.png | Bin .../drawable-hdpi-v4/remote_xbox_title_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_tv.xml | 5 + .../drawable-hdpi-v4/remote_xbox_tv_down.png | Bin .../drawable-hdpi-v4/remote_xbox_tv_up.png | Bin .../res/drawable-hdpi-v4/remote_xbox_up.xml | 5 + .../drawable-hdpi-v4/remote_xbox_up_down.png | Bin .../drawable-hdpi-v4/remote_xbox_up_up.png | Bin .../drawable-hdpi-v4/remote_xbox_video.xml | 5 + .../remote_xbox_video_down.png | Bin .../drawable-hdpi-v4/remote_xbox_video_up.png | Bin .../remote_xbox_widget__top_left.png | Bin .../remote_xbox_widget__top_right.png | Bin .../remote_xbox_widget_back_down.png | Bin .../remote_xbox_widget_back_up.png | Bin .../remote_xbox_widget_display_down.png | Bin .../remote_xbox_widget_display_up.png | Bin .../remote_xbox_widget_down_down.png | Bin .../remote_xbox_widget_down_up.png | Bin .../remote_xbox_widget_info_down.png | Bin .../remote_xbox_widget_info_up.png | Bin .../remote_xbox_widget_left_down.png | Bin .../remote_xbox_widget_left_up.png | Bin .../remote_xbox_widget_menu_down.png | Bin .../remote_xbox_widget_menu_up.png | Bin .../remote_xbox_widget_next_down.png | Bin .../remote_xbox_widget_next_up.png | Bin .../remote_xbox_widget_pause_down.png | Bin .../remote_xbox_widget_pause_up.png | Bin .../remote_xbox_widget_play_down.png | Bin .../remote_xbox_widget_play_up.png | Bin .../remote_xbox_widget_previous_down.png | Bin .../remote_xbox_widget_previous_up.png | Bin .../remote_xbox_widget_right_down.png | Bin .../remote_xbox_widget_right_up.png | Bin .../remote_xbox_widget_seek_back_down.png | Bin .../remote_xbox_widget_seek_back_up.png | Bin .../remote_xbox_widget_seek_forward_down.png | Bin .../remote_xbox_widget_seek_forward_up.png | Bin .../remote_xbox_widget_select_down.png | Bin .../remote_xbox_widget_select_up.png | Bin .../remote_xbox_widget_stop_down.png | Bin .../remote_xbox_widget_stop_up.png | Bin .../remote_xbox_widget_title_down.png | Bin .../remote_xbox_widget_title_up.png | Bin .../remote_xbox_widget_up_down.png | Bin .../remote_xbox_widget_up_up.png | Bin .../drawable-hdpi-v4/scrollbar_handle.png | Bin .../drawable-hdpi-v4/shiny_black_back.png | Bin .../res}/drawable-hdpi-v4/st_actor_off.png | Bin .../res}/drawable-hdpi-v4/st_actor_on.png | Bin .../res}/drawable-hdpi-v4/st_actor_over.png | Bin .../res}/drawable-hdpi-v4/st_album_off.png | Bin .../res}/drawable-hdpi-v4/st_album_on.png | Bin .../res}/drawable-hdpi-v4/st_album_over.png | Bin .../res}/drawable-hdpi-v4/st_artist_off.png | Bin .../res}/drawable-hdpi-v4/st_artist_on.png | Bin .../res}/drawable-hdpi-v4/st_artist_over.png | Bin .../res}/drawable-hdpi-v4/st_background.png | Bin .../res}/drawable-hdpi-v4/st_filemode_off.png | Bin .../res}/drawable-hdpi-v4/st_filemode_on.png | Bin .../drawable-hdpi-v4/st_filemode_over.png | Bin .../res}/drawable-hdpi-v4/st_genre_off.png | Bin .../res}/drawable-hdpi-v4/st_genre_on.png | Bin .../res}/drawable-hdpi-v4/st_genre_over.png | Bin .../res}/drawable-hdpi-v4/st_movie_off.png | Bin .../res}/drawable-hdpi-v4/st_movie_on.png | Bin .../res}/drawable-hdpi-v4/st_movie_over.png | Bin .../res}/drawable-hdpi-v4/st_playlist_off.png | Bin .../res}/drawable-hdpi-v4/st_playlist_on.png | Bin .../drawable-hdpi-v4/st_playlist_over.png | Bin .../main/res}/drawable-hdpi-v4/st_slider.png | Bin .../res}/drawable-hdpi-v4/st_song_off.png | Bin .../main/res}/drawable-hdpi-v4/st_song_on.png | Bin .../res}/drawable-hdpi-v4/st_song_over.png | Bin .../main/res}/drawable-hdpi-v4/st_tv_off.png | Bin .../main/res}/drawable-hdpi-v4/st_tv_on.png | Bin .../main/res}/drawable-hdpi-v4/st_tv_over.png | Bin .../main/res}/drawable-hdpi-v4/st_va_off.png | Bin .../main/res}/drawable-hdpi-v4/st_va_on.png | Bin .../main/res}/drawable-hdpi-v4/st_va_over.png | Bin .../main/res}/drawable-hdpi-v4/stars_0.png | Bin .../main/res}/drawable-hdpi-v4/stars_1.png | Bin .../main/res}/drawable-hdpi-v4/stars_10.png | Bin .../main/res}/drawable-hdpi-v4/stars_2.png | Bin .../main/res}/drawable-hdpi-v4/stars_3.png | Bin .../main/res}/drawable-hdpi-v4/stars_4.png | Bin .../main/res}/drawable-hdpi-v4/stars_5.png | Bin .../main/res}/drawable-hdpi-v4/stars_6.png | Bin .../main/res}/drawable-hdpi-v4/stars_7.png | Bin .../main/res}/drawable-hdpi-v4/stars_8.png | Bin .../main/res}/drawable-hdpi-v4/stars_9.png | Bin .../res}/drawable-hdpi-v4/timeborder.9.png | Bin .../remote_xbox_back_down.png | Bin .../remote_xbox_back_up.png | Bin .../remote_xbox_display_down.png | Bin .../remote_xbox_display_up.png | Bin .../remote_xbox_down_down.png | Bin .../remote_xbox_down_up.png | Bin .../remote_xbox_images_down.png | Bin .../remote_xbox_images_up.png | Bin .../remote_xbox_info_down.png | Bin .../remote_xbox_info_up.png | Bin .../remote_xbox_left_down.png | Bin .../remote_xbox_left_up.png | Bin .../remote_xbox_menu_down.png | Bin .../remote_xbox_menu_up.png | Bin .../remote_xbox_music_down.png | Bin .../remote_xbox_music_up.png | Bin .../remote_xbox_next_down.png | Bin .../remote_xbox_next_up.png | Bin .../remote_xbox_pause_down.png | Bin .../remote_xbox_pause_up.png | Bin .../remote_xbox_play_down.png | Bin .../remote_xbox_play_up.png | Bin .../remote_xbox_power_down.png | Bin .../remote_xbox_power_up.png | Bin .../remote_xbox_previous_down.png | Bin .../remote_xbox_previous_up.png | Bin .../remote_xbox_right_down.png | Bin .../remote_xbox_right_up.png | Bin .../remote_xbox_seek_back_down.png | Bin .../remote_xbox_seek_back_up.png | Bin .../remote_xbox_seek_forward_down.png | Bin .../remote_xbox_seek_forward_up.png | Bin .../remote_xbox_select_down.png | Bin .../remote_xbox_select_up.png | Bin .../remote_xbox_stop_down.png | Bin .../remote_xbox_stop_up.png | Bin .../remote_xbox_title_down.png | Bin .../remote_xbox_title_up.png | Bin .../remote_xbox_tv_down.png | Bin .../remote_xbox_tv_up.png | Bin .../remote_xbox_up_down.png | Bin .../remote_xbox_up_up.png | Bin .../remote_xbox_video_down.png | Bin .../remote_xbox_video_up.png | Bin .../remote_xbox_back_down.png | Bin .../remote_xbox_back_up.png | Bin .../remote_xbox_down_down.png | Bin .../remote_xbox_down_up.png | Bin .../remote_xbox_info_down.png | Bin .../remote_xbox_info_up.png | Bin .../remote_xbox_left_down.png | Bin .../remote_xbox_left_up.png | Bin .../remote_xbox_menu_down.png | Bin .../remote_xbox_menu_up.png | Bin .../remote_xbox_next_down.png | Bin .../remote_xbox_next_up.png | Bin .../remote_xbox_pause_down.png | Bin .../remote_xbox_pause_up.png | Bin .../remote_xbox_play_down.png | Bin .../remote_xbox_play_up.png | Bin .../remote_xbox_power_down.png | Bin .../remote_xbox_power_up.png | Bin .../remote_xbox_previous_down.png | Bin .../remote_xbox_previous_up.png | Bin .../remote_xbox_right_down.png | Bin .../remote_xbox_right_up.png | Bin .../remote_xbox_seek_back_down.png | Bin .../remote_xbox_seek_back_up.png | Bin .../remote_xbox_seek_forward_down.png | Bin .../remote_xbox_seek_forward_up.png | Bin .../remote_xbox_select_down.png | Bin .../remote_xbox_select_up.png | Bin .../remote_xbox_stop_down.png | Bin .../remote_xbox_stop_up.png | Bin .../remote_xbox_title_down.png | Bin .../remote_xbox_title_up.png | Bin .../remote_xbox_up_down.png | Bin .../remote_xbox_up_up.png | Bin .../res/drawable-land/remote_xbox_back.xml | 5 + .../drawable-land/remote_xbox_back_down.png | Bin .../drawable-land/remote_xbox_back_up.png | Bin .../res/drawable-land/remote_xbox_display.xml | 5 + .../remote_xbox_display_down.png | Bin .../drawable-land/remote_xbox_display_up.png | Bin .../res/drawable-land/remote_xbox_down.xml | 5 + .../drawable-land/remote_xbox_down_down.png | Bin .../drawable-land/remote_xbox_down_up.png | Bin .../res/drawable-land/remote_xbox_images.xml | 5 + .../drawable-land/remote_xbox_images_down.png | Bin .../drawable-land/remote_xbox_images_up.png | Bin .../res/drawable-land/remote_xbox_info.xml | 5 + .../drawable-land/remote_xbox_info_down.png | Bin .../drawable-land/remote_xbox_info_up.png | Bin .../res/drawable-land/remote_xbox_left.xml | 5 + .../drawable-land/remote_xbox_left_down.png | Bin .../drawable-land/remote_xbox_left_up.png | Bin .../res/drawable-land/remote_xbox_menu.xml | 5 + .../drawable-land/remote_xbox_menu_down.png | Bin .../drawable-land/remote_xbox_menu_up.png | Bin .../res/drawable-land/remote_xbox_music.xml | 5 + .../drawable-land/remote_xbox_music_down.png | Bin .../drawable-land/remote_xbox_music_up.png | Bin .../res/drawable-land/remote_xbox_next.xml | 5 + .../drawable-land/remote_xbox_next_down.png | Bin .../drawable-land/remote_xbox_next_up.png | Bin .../res/drawable-land/remote_xbox_pause.xml | 5 + .../drawable-land/remote_xbox_pause_down.png | Bin .../drawable-land/remote_xbox_pause_up.png | Bin .../res/drawable-land/remote_xbox_play.xml | 5 + .../drawable-land/remote_xbox_play_down.png | Bin .../drawable-land/remote_xbox_play_up.png | Bin .../res/drawable-land/remote_xbox_power.xml | 5 + .../drawable-land/remote_xbox_power_down.png | Bin .../drawable-land/remote_xbox_power_up.png | Bin .../drawable-land/remote_xbox_previous.xml | 5 + .../remote_xbox_previous_down.png | Bin .../drawable-land/remote_xbox_previous_up.png | Bin .../res/drawable-land/remote_xbox_right.xml | 5 + .../drawable-land/remote_xbox_right_down.png | Bin .../drawable-land/remote_xbox_right_up.png | Bin .../drawable-land/remote_xbox_seek_back.xml | 5 + .../remote_xbox_seek_back_down.png | Bin .../remote_xbox_seek_back_up.png | Bin .../remote_xbox_seek_forward.xml | 5 + .../remote_xbox_seek_forward_down.png | Bin .../remote_xbox_seek_forward_up.png | Bin .../res/drawable-land/remote_xbox_select.xml | 5 + .../drawable-land/remote_xbox_select_down.png | Bin .../drawable-land/remote_xbox_select_up.png | Bin .../res/drawable-land/remote_xbox_stop.xml | 5 + .../drawable-land/remote_xbox_stop_down.png | Bin .../drawable-land/remote_xbox_stop_up.png | Bin .../res/drawable-land/remote_xbox_title.xml | 5 + .../drawable-land/remote_xbox_title_down.png | Bin .../drawable-land/remote_xbox_title_up.png | Bin .../main/res/drawable-land/remote_xbox_tv.xml | 5 + .../drawable-land/remote_xbox_tv_down.png | Bin .../res}/drawable-land/remote_xbox_tv_up.png | Bin .../main/res/drawable-land/remote_xbox_up.xml | 5 + .../drawable-land/remote_xbox_up_down.png | Bin .../res}/drawable-land/remote_xbox_up_up.png | Bin .../res/drawable-land/remote_xbox_video.xml | 5 + .../drawable-land/remote_xbox_video_down.png | Bin .../drawable-land/remote_xbox_video_up.png | Bin .../drawable-ldpi-v4/remote_gest_cursor.png | Bin .../remote_xbox__top_left.png | Bin .../remote_xbox__top_right.png | Bin .../remote_xbox_back_down.png | Bin .../drawable-ldpi-v4/remote_xbox_back_up.png | Bin .../remote_xbox_display_down.png | Bin .../remote_xbox_display_up.png | Bin .../remote_xbox_down_down.png | Bin .../drawable-ldpi-v4/remote_xbox_down_up.png | Bin .../remote_xbox_gesture_back_down.png | Bin .../remote_xbox_gesture_info_down.png | Bin .../remote_xbox_gesture_menu_down.png | Bin .../remote_xbox_gesture_title_down.png | Bin .../remote_xbox_gesturezone.png | Bin .../remote_xbox_gesturezone_dim.png | Bin .../remote_xbox_info_down.png | Bin .../drawable-ldpi-v4/remote_xbox_info_up.png | Bin .../remote_xbox_left_down.png | Bin .../drawable-ldpi-v4/remote_xbox_left_up.png | Bin .../remote_xbox_menu_down.png | Bin .../drawable-ldpi-v4/remote_xbox_menu_up.png | Bin .../remote_xbox_next_down.png | Bin .../drawable-ldpi-v4/remote_xbox_next_up.png | Bin .../remote_xbox_pause_down.png | Bin .../drawable-ldpi-v4/remote_xbox_pause_up.png | Bin .../remote_xbox_play_down.png | Bin .../drawable-ldpi-v4/remote_xbox_play_up.png | Bin .../remote_xbox_previous_down.png | Bin .../remote_xbox_previous_up.png | Bin .../remote_xbox_right_down.png | Bin .../drawable-ldpi-v4/remote_xbox_right_up.png | Bin .../remote_xbox_seek_back_down.png | Bin .../remote_xbox_seek_back_up.png | Bin .../remote_xbox_seek_forward_down.png | Bin .../remote_xbox_seek_forward_up.png | Bin .../remote_xbox_select_down.png | Bin .../remote_xbox_select_up.png | Bin .../remote_xbox_stop_down.png | Bin .../drawable-ldpi-v4/remote_xbox_stop_up.png | Bin .../remote_xbox_title_down.png | Bin .../drawable-ldpi-v4/remote_xbox_title_up.png | Bin .../drawable-ldpi-v4/remote_xbox_up_down.png | Bin .../drawable-ldpi-v4/remote_xbox_up_up.png | Bin .../src/main/res}/drawable/about_back.png | Bin .../drawable/bottom_controls_background.png | Bin app/src/main/res/drawable/bottom_logo.xml | 5 + .../main/res}/drawable/bottom_logo_down.png | Bin .../src/main/res}/drawable/bottom_logo_up.png | Bin app/src/main/res/drawable/bottom_text.xml | 5 + .../main/res}/drawable/bottom_text_down.9.png | Bin .../main/res}/drawable/bottom_text_up.9.png | Bin .../src/main/res}/drawable/bottombar_bg.png | Bin .../src/main/res}/drawable/bubble_add.png | Bin app/src/main/res/drawable/bubble_del.xml | 5 + .../main/res}/drawable/bubble_del_down.png | Bin .../src/main/res}/drawable/bubble_del_up.png | Bin .../src/main/res}/drawable/check_mark.png | Bin .../src/main/res}/drawable/coverbox_back.png | Bin .../src/main/res}/drawable/default_album.png | Bin .../src/main/res}/drawable/default_jewel.png | Bin .../src/main/res}/drawable/default_poster.png | Bin .../src/main/res}/drawable/default_season.png | Bin .../src/main/res}/drawable/default_tvshow.png | Bin .../main/res}/drawable/dialog_full_dark.9.png | Bin .../src/main/res}/drawable/home_bottom.9.png | Bin {res => app/src/main/res}/drawable/icon.png | Bin .../src/main/res}/drawable/icon_album.png | Bin .../src/main/res}/drawable/icon_album_big.png | Bin .../main/res}/drawable/icon_album_dark.png | Bin .../res}/drawable/icon_album_dark_big.png | Bin .../src/main/res}/drawable/icon_artist.png | Bin .../main/res}/drawable/icon_artist_dark.png | Bin .../src/main/res}/drawable/icon_file.png | Bin .../src/main/res}/drawable/icon_folder.png | Bin .../main/res}/drawable/icon_folder_dark.png | Bin .../src/main/res}/drawable/icon_genre.png | Bin .../main/res}/drawable/icon_genre_dark.png | Bin .../main/res}/drawable/icon_home_movie.png | Bin .../main/res}/drawable/icon_home_music.png | Bin .../main/res}/drawable/icon_home_picture.png | Bin .../main/res}/drawable/icon_home_playing.png | Bin .../main/res}/drawable/icon_home_power.png | Bin .../res}/drawable/icon_home_reconnect.png | Bin .../main/res}/drawable/icon_home_remote.png | Bin .../src/main/res}/drawable/icon_home_tv.png | Bin .../main/res}/drawable/icon_home_voice.png | Bin .../src/main/res}/drawable/icon_lastfm.png | Bin .../main/res}/drawable/icon_movie_dark.png | Bin .../src/main/res}/drawable/icon_picture.png | Bin .../src/main/res}/drawable/icon_play.png | Bin .../src/main/res}/drawable/icon_playing.png | Bin .../main/res}/drawable/icon_playlist_dark.png | Bin .../src/main/res}/drawable/icon_shoutcast.png | Bin .../src/main/res}/drawable/icon_song.png | Bin .../src/main/res}/drawable/icon_song_dark.png | Bin .../main/res}/drawable/icon_song_light.png | Bin .../src/main/res}/drawable/icon_va_dark.png | Bin .../src/main/res}/drawable/icon_video.png | Bin .../main/res}/drawable/icon_video_light.png | Bin .../src/main/res}/drawable/icon_zip.png | Bin .../src/main/res}/drawable/jewel_cd.9.png | Bin .../src/main/res}/drawable/jewel_dvd.9.png | Bin .../src/main/res}/drawable/jewel_tv.9.png | Bin .../main/res}/drawable/layout_top_bar.9.png | Bin app/src/main/res/drawable/listitem_bg.xml | 11 + .../drawable/listitem_bottom_rounded.9.png | Bin .../main/res/drawable/listitem_subtitle.xml | 5 + app/src/main/res/drawable/listitem_title.xml | 5 + .../src/main/res}/drawable/menu_about.png | Bin .../src/main/res}/drawable/menu_add_host.png | Bin .../src/main/res}/drawable/menu_album.png | Bin .../src/main/res}/drawable/menu_download.png | Bin .../src/main/res}/drawable/menu_exit.png | Bin .../main/res}/drawable/menu_gesture_mode.png | Bin .../main/res}/drawable/menu_hide_watched.png | Bin .../main/res}/drawable/menu_nowplaying.png | Bin .../src/main/res}/drawable/menu_qr_code.png | Bin .../src/main/res}/drawable/menu_refresh.png | Bin .../src/main/res}/drawable/menu_remote.png | Bin .../src/main/res}/drawable/menu_settings.png | Bin .../main/res}/drawable/menu_show_watched.png | Bin .../src/main/res}/drawable/menu_song.png | Bin .../src/main/res}/drawable/menu_sort.png | Bin .../src/main/res}/drawable/menu_switch.png | Bin .../main/res}/drawable/menu_text_entry.png | Bin .../src/main/res}/drawable/menu_view.png | Bin .../src/main/res}/drawable/menu_xbmc_exit.png | Bin .../src/main/res}/drawable/menu_xbmc_s.png | Bin .../src/main/res}/drawable/nocover.png | Bin .../src/main/res}/drawable/notif_pause.png | Bin .../src/main/res}/drawable/notif_pic.png | Bin .../src/main/res}/drawable/notif_play.png | Bin .../main/res/drawable/now_playing_next.xml | 5 + .../res}/drawable/now_playing_next_down.png | Bin .../res}/drawable/now_playing_next_up.png | Bin .../main/res/drawable/now_playing_pause.xml | 5 + .../res}/drawable/now_playing_pause_down.png | Bin .../res}/drawable/now_playing_pause_up.png | Bin .../main/res/drawable/now_playing_play.xml | 5 + .../res}/drawable/now_playing_play_down.png | Bin .../res}/drawable/now_playing_play_up.png | Bin .../res/drawable/now_playing_playlist.xml | 5 + .../drawable/now_playing_playlist_down.png | Bin .../res}/drawable/now_playing_playlist_up.png | Bin .../res/drawable/now_playing_previous.xml | 5 + .../drawable/now_playing_previous_down.png | Bin .../res}/drawable/now_playing_previous_up.png | Bin .../main/res/drawable/now_playing_stop.xml | 5 + .../res}/drawable/now_playing_stop_down.png | Bin .../res}/drawable/now_playing_stop_up.png | Bin {res => app/src/main/res}/drawable/person.png | Bin .../main/res}/drawable/person_black_small.png | Bin .../src/main/res}/drawable/person_small.png | Bin .../src/main/res}/drawable/pgbar_act.png | Bin .../src/main/res}/drawable/pgbar_inact.png | Bin .../src/main/res}/drawable/pgbar_thumb.png | Bin .../res}/drawable/playlist_rightboxes.png | Bin .../src/main/res}/drawable/poster_big.png | Bin .../src/main/res}/drawable/progressbar.xml | 65 +- .../res}/drawable/remote_gest_border_left.png | Bin .../drawable/remote_gest_border_right.png | Bin .../main/res}/drawable/remote_gest_cursor.png | Bin .../res}/drawable/remote_xbox__top_left.png | Bin .../res}/drawable/remote_xbox__top_right.png | Bin .../main/res/drawable/remote_xbox_back.xml | 5 + .../res}/drawable/remote_xbox_back_down.png | Bin .../res}/drawable/remote_xbox_back_up.png | Bin .../main/res/drawable/remote_xbox_display.xml | 5 + .../drawable/remote_xbox_display_down.png | Bin .../res}/drawable/remote_xbox_display_up.png | Bin .../main/res/drawable/remote_xbox_down.xml | 5 + .../res}/drawable/remote_xbox_down_down.png | Bin .../res}/drawable/remote_xbox_down_up.png | Bin .../remote_xbox_gesture_back_down.png | Bin .../remote_xbox_gesture_info_down.png | Bin .../remote_xbox_gesture_menu_down.png | Bin .../remote_xbox_gesture_title_down.png | Bin .../res}/drawable/remote_xbox_gesturezone.png | Bin .../drawable/remote_xbox_gesturezone_dim.png | Bin .../main/res/drawable/remote_xbox_info.xml | 5 + .../res}/drawable/remote_xbox_info_down.png | Bin .../res}/drawable/remote_xbox_info_up.png | Bin .../main/res/drawable/remote_xbox_left.xml | 5 + .../res}/drawable/remote_xbox_left_down.png | Bin .../res}/drawable/remote_xbox_left_up.png | Bin .../main/res/drawable/remote_xbox_menu.xml | 5 + .../res}/drawable/remote_xbox_menu_down.png | Bin .../res}/drawable/remote_xbox_menu_up.png | Bin .../main/res/drawable/remote_xbox_next.xml | 5 + .../res}/drawable/remote_xbox_next_down.png | Bin .../res}/drawable/remote_xbox_next_up.png | Bin .../main/res/drawable/remote_xbox_pause.xml | 5 + .../res}/drawable/remote_xbox_pause_down.png | Bin .../res}/drawable/remote_xbox_pause_up.png | Bin .../main/res/drawable/remote_xbox_play.xml | 5 + .../res}/drawable/remote_xbox_play_down.png | Bin .../res}/drawable/remote_xbox_play_up.png | Bin .../res/drawable/remote_xbox_previous.xml | 5 + .../drawable/remote_xbox_previous_down.png | Bin .../res}/drawable/remote_xbox_previous_up.png | Bin .../main/res/drawable/remote_xbox_right.xml | 5 + .../res}/drawable/remote_xbox_right_down.png | Bin .../res}/drawable/remote_xbox_right_up.png | Bin .../res/drawable/remote_xbox_seek_back.xml | 5 + .../drawable/remote_xbox_seek_back_down.png | Bin .../drawable/remote_xbox_seek_back_up.png | Bin .../res/drawable/remote_xbox_seek_forward.xml | 5 + .../remote_xbox_seek_forward_down.png | Bin .../drawable/remote_xbox_seek_forward_up.png | Bin .../main/res/drawable/remote_xbox_select.xml | 5 + .../res}/drawable/remote_xbox_select_down.png | Bin .../res}/drawable/remote_xbox_select_up.png | Bin .../main/res/drawable/remote_xbox_stop.xml | 5 + .../res}/drawable/remote_xbox_stop_down.png | Bin .../res}/drawable/remote_xbox_stop_up.png | Bin .../main/res/drawable/remote_xbox_title.xml | 5 + .../res}/drawable/remote_xbox_title_down.png | Bin .../res}/drawable/remote_xbox_title_up.png | Bin app/src/main/res/drawable/remote_xbox_up.xml | 5 + .../res}/drawable/remote_xbox_up_down.png | Bin .../main/res}/drawable/remote_xbox_up_up.png | Bin .../res/drawable/remote_xbox_widget_back.xml | 5 + .../drawable/remote_xbox_widget_back_down.png | Bin .../drawable/remote_xbox_widget_back_up.png | Bin .../drawable/remote_xbox_widget_display.xml | 5 + .../remote_xbox_widget_display_down.png | Bin .../remote_xbox_widget_display_up.png | Bin .../res/drawable/remote_xbox_widget_down.xml | 5 + .../drawable/remote_xbox_widget_down_down.png | Bin .../drawable/remote_xbox_widget_down_up.png | Bin .../res/drawable/remote_xbox_widget_info.xml | 5 + .../drawable/remote_xbox_widget_info_down.png | Bin .../drawable/remote_xbox_widget_info_up.png | Bin .../res/drawable/remote_xbox_widget_left.xml | 5 + .../drawable/remote_xbox_widget_left_down.png | Bin .../drawable/remote_xbox_widget_left_up.png | Bin .../res/drawable/remote_xbox_widget_menu.xml | 5 + .../drawable/remote_xbox_widget_menu_down.png | Bin .../drawable/remote_xbox_widget_menu_up.png | Bin .../res/drawable/remote_xbox_widget_next.xml | 5 + .../drawable/remote_xbox_widget_next_down.png | Bin .../drawable/remote_xbox_widget_next_up.png | Bin .../res/drawable/remote_xbox_widget_pause.xml | 5 + .../remote_xbox_widget_pause_down.png | Bin .../drawable/remote_xbox_widget_pause_up.png | Bin .../res/drawable/remote_xbox_widget_play.xml | 5 + .../drawable/remote_xbox_widget_play_down.png | Bin .../drawable/remote_xbox_widget_play_up.png | Bin .../drawable/remote_xbox_widget_preview.png | Bin .../drawable/remote_xbox_widget_previous.xml | 5 + .../remote_xbox_widget_previous_down.png | Bin .../remote_xbox_widget_previous_up.png | Bin .../res/drawable/remote_xbox_widget_right.xml | 5 + .../remote_xbox_widget_right_down.png | Bin .../drawable/remote_xbox_widget_right_up.png | Bin .../drawable/remote_xbox_widget_seek_back.xml | 5 + .../remote_xbox_widget_seek_back_down.png | Bin .../remote_xbox_widget_seek_back_up.png | Bin .../remote_xbox_widget_seek_forward.xml | 5 + .../remote_xbox_widget_seek_forward_down.png | Bin .../remote_xbox_widget_seek_forward_up.png | Bin .../drawable/remote_xbox_widget_select.xml | 5 + .../remote_xbox_widget_select_down.png | Bin .../drawable/remote_xbox_widget_select_up.png | Bin .../res/drawable/remote_xbox_widget_stop.xml | 5 + .../drawable/remote_xbox_widget_stop_down.png | Bin .../drawable/remote_xbox_widget_stop_up.png | Bin .../res/drawable/remote_xbox_widget_title.xml | 5 + .../remote_xbox_widget_title_down.png | Bin .../drawable/remote_xbox_widget_title_up.png | Bin .../res/drawable/remote_xbox_widget_up.xml | 5 + .../drawable/remote_xbox_widget_up_down.png | Bin .../drawable/remote_xbox_widget_up_up.png | Bin .../main/res}/drawable/scrollbar_handle.png | Bin .../scrollbar_handle_accelerated_anim2.9.png | Bin .../src/main/res}/drawable/selected.9.png | Bin .../main/res}/drawable/shiny_black_back.png | Bin .../src/main/res}/drawable/smallborder.9.png | Bin .../src/main/res}/drawable/st_actor_off.png | Bin .../src/main/res}/drawable/st_actor_on.png | Bin .../src/main/res}/drawable/st_actor_over.png | Bin .../src/main/res}/drawable/st_album_off.png | Bin .../src/main/res}/drawable/st_album_on.png | Bin .../src/main/res}/drawable/st_album_over.png | Bin .../src/main/res}/drawable/st_artist_off.png | Bin .../src/main/res}/drawable/st_artist_on.png | Bin .../src/main/res}/drawable/st_artist_over.png | Bin .../src/main/res}/drawable/st_background.png | Bin .../main/res}/drawable/st_filemode_off.png | Bin .../src/main/res}/drawable/st_filemode_on.png | Bin .../main/res}/drawable/st_filemode_over.png | Bin .../src/main/res}/drawable/st_genre_off.png | Bin .../src/main/res}/drawable/st_genre_on.png | Bin .../src/main/res}/drawable/st_genre_over.png | Bin .../src/main/res}/drawable/st_movie_off.png | Bin .../src/main/res}/drawable/st_movie_on.png | Bin .../src/main/res}/drawable/st_movie_over.png | Bin .../main/res}/drawable/st_playlist_off.png | Bin .../src/main/res}/drawable/st_playlist_on.png | Bin .../main/res}/drawable/st_playlist_over.png | Bin .../src/main/res}/drawable/st_slider.png | Bin .../src/main/res}/drawable/st_song_off.png | Bin .../src/main/res}/drawable/st_song_on.png | Bin .../src/main/res}/drawable/st_song_over.png | Bin .../src/main/res}/drawable/st_tv_off.png | Bin .../src/main/res}/drawable/st_tv_on.png | Bin .../src/main/res}/drawable/st_tv_over.png | Bin .../src/main/res}/drawable/st_va_off.png | Bin .../src/main/res}/drawable/st_va_on.png | Bin .../src/main/res}/drawable/st_va_over.png | Bin .../src/main/res}/drawable/stars_0.png | Bin .../src/main/res}/drawable/stars_1.png | Bin .../src/main/res}/drawable/stars_10.png | Bin .../src/main/res}/drawable/stars_2.png | Bin .../src/main/res}/drawable/stars_3.png | Bin .../src/main/res}/drawable/stars_4.png | Bin .../src/main/res}/drawable/stars_5.png | Bin .../src/main/res}/drawable/stars_6.png | Bin .../src/main/res}/drawable/stars_7.png | Bin .../src/main/res}/drawable/stars_8.png | Bin .../src/main/res}/drawable/stars_9.png | Bin .../src/main/res}/drawable/timeborder.9.png | Bin .../src/main/res}/drawable/waiting.png | Bin .../res/layout-land-hdpi-v4/remote_xbox.xml | 236 ++ .../remote_xbox_extended.xml | 236 ++ .../res/layout-land-ldpi-v4/remote_xbox.xml | 169 ++ app/src/main/res/layout-land/home.xml | 50 + app/src/main/res/layout-land/nowplaying.xml | 213 ++ app/src/main/res/layout-land/remote_xbox.xml | 236 ++ .../main/res/layout-ldpi-v4/remote_xbox.xml | 184 ++ .../res/layout-xhdpi/slidingtab_widget.xml | 44 + app/src/main/res/layout/about.xml | 56 + app/src/main/res/layout/actor_item.xml | 45 + app/src/main/res/layout/albumgrid.xml | 13 + app/src/main/res/layout/albuminfo.xml | 80 + app/src/main/res/layout/albumtracks.xml | 75 + app/src/main/res/layout/artistinfo.xml | 62 + app/src/main/res/layout/blankgrid.xml | 26 + app/src/main/res/layout/blanklist.xml | 24 + app/src/main/res/layout/home.xml | 50 + app/src/main/res/layout/home_item.xml | 38 + app/src/main/res/layout/listmessage.xml | 20 + app/src/main/res/layout/loading_message.xml | 23 + app/src/main/res/layout/loadinglistentry.xml | 27 + .../src/main/res}/layout/moviedetails.xml | 116 +- app/src/main/res/layout/movielibrary.xml | 117 + app/src/main/res/layout/musicartist.xml | 76 + app/src/main/res/layout/musicgenre.xml | 100 + app/src/main/res/layout/musiclibrary.xml | 160 ++ app/src/main/res/layout/nowplaying.xml | 208 ++ app/src/main/res/layout/playlist.xml | 106 + app/src/main/res/layout/preference_host.xml | 149 ++ app/src/main/res/layout/remote_gesture.xml | 128 + .../res/layout/remote_gesture_extended.xml | 174 ++ app/src/main/res/layout/remote_xbox.xml | 233 ++ .../main/res/layout/remote_xbox_extended.xml | 278 +++ app/src/main/res/layout/sendtext.xml | 63 + app/src/main/res/layout/setup_page_1.xml | 54 + .../src/main/res}/layout/setup_page_2.xml | 53 +- app/src/main/res/layout/setup_page_3.xml | 21 + app/src/main/res/layout/setup_page_login.xml | 43 + app/src/main/res/layout/setup_wizard.xml | 59 + .../main/res/layout/slidingtab_overlay.xml | 27 + app/src/main/res/layout/slidingtab_widget.xml | 44 + app/src/main/res/layout/titlebar.xml | 28 + app/src/main/res/layout/tvdetails.xml | 157 ++ .../src/main/res}/layout/tvepisodedetails.xml | 280 +-- app/src/main/res/layout/tvlibrary.xml | 117 + app/src/main/res/layout/widget_xbox.xml | 182 ++ app/src/main/res/layout/widget_xbox_small.xml | 98 + app/src/main/res/values-v14/dimens.xml | 3 + {res => app/src/main/res}/values/arrays.xml | 0 app/src/main/res/values/attrs.xml | 42 + .../src/main/res}/values/attrs_manifest.xml | 44 +- app/src/main/res/values/colors.xml | 8 + app/src/main/res/values/dimens.xml | 3 + app/src/main/res/values/ids.xml | 6 + {res => app/src/main/res}/values/public.xml | 72 +- {res => app/src/main/res}/values/strings.xml | 44 +- app/src/main/res/values/styles.xml | 45 + {res => app/src/main/res}/values/themes.xml | 56 +- app/src/main/res/xml/app_widget_remote.xml | 15 + {res => app/src/main/res}/xml/preferences.xml | 151 +- build.gradle | 19 + build.xml | 92 - gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++ gradlew.bat | 90 + .../org/codehaus/jackson/Base64Variant.java | 339 --- .../org/codehaus/jackson/Base64Variants.java | 90 - .../org/codehaus/jackson/JsonEncoding.java | 48 - lib-src/org/codehaus/jackson/JsonFactory.java | 581 ----- .../jackson/JsonGenerationException.java | 27 - .../org/codehaus/jackson/JsonGenerator.java | 875 ------- .../org/codehaus/jackson/JsonLocation.java | 141 -- lib-src/org/codehaus/jackson/JsonNode.java | 417 ---- .../codehaus/jackson/JsonParseException.java | 22 - lib-src/org/codehaus/jackson/JsonParser.java | 945 -------- .../jackson/JsonProcessingException.java | 80 - .../codehaus/jackson/JsonStreamContext.java | 112 - lib-src/org/codehaus/jackson/JsonToken.java | 160 -- lib-src/org/codehaus/jackson/ObjectCodec.java | 141 -- .../org/codehaus/jackson/PrettyPrinter.java | 166 -- .../jackson/annotate/JacksonAnnotation.java | 20 - .../jackson/annotate/JsonAnySetter.java | 24 - .../jackson/annotate/JsonAutoDetect.java | 148 -- .../codehaus/jackson/annotate/JsonClass.java | 41 - .../jackson/annotate/JsonContentClass.java | 42 - .../jackson/annotate/JsonCreator.java | 19 - .../codehaus/jackson/annotate/JsonGetter.java | 34 - .../codehaus/jackson/annotate/JsonIgnore.java | 50 - .../annotate/JsonIgnoreProperties.java | 48 - .../jackson/annotate/JsonKeyClass.java | 44 - .../codehaus/jackson/annotate/JsonMethod.java | 90 - .../jackson/annotate/JsonProperty.java | 38 - .../jackson/annotate/JsonPropertyOrder.java | 46 - .../codehaus/jackson/annotate/JsonSetter.java | 29 - .../jackson/annotate/JsonSubTypes.java | 45 - .../jackson/annotate/JsonTypeInfo.java | 174 -- .../jackson/annotate/JsonTypeName.java | 28 - .../codehaus/jackson/annotate/JsonValue.java | 46 - .../annotate/JsonWriteNullProperties.java | 29 - .../jackson/annotate/package-info.java | 16 - .../jackson/impl/ByteSourceBootstrapper.java | 351 --- .../jackson/impl/DefaultPrettyPrinter.java | 264 --- .../org/codehaus/jackson/impl/Indenter.java | 23 - .../jackson/impl/JsonGeneratorBase.java | 476 ---- .../jackson/impl/JsonNumericParserBase.java | 590 ----- .../codehaus/jackson/impl/JsonParserBase.java | 666 ------ .../jackson/impl/JsonReadContext.java | 176 -- .../jackson/impl/JsonWriteContext.java | 228 -- .../impl/ReaderBasedNumericParser.java | 302 --- .../jackson/impl/ReaderBasedParser.java | 1040 -------- .../jackson/impl/ReaderBasedParserBase.java | 134 -- .../jackson/impl/StreamBasedParserBase.java | 134 -- .../jackson/impl/Utf8NumericParser.java | 190 -- .../jackson/impl/Utf8StreamParser.java | 1826 -------------- .../jackson/impl/WriterBasedGenerator.java | 1019 -------- .../codehaus/jackson/impl/package-info.java | 6 - .../org/codehaus/jackson/io/BaseReader.java | 117 - .../org/codehaus/jackson/io/IOContext.java | 240 -- .../org/codehaus/jackson/io/MergedStream.java | 141 -- .../org/codehaus/jackson/io/NumberInput.java | 110 - .../org/codehaus/jackson/io/NumberOutput.java | 269 --- .../jackson/io/SegmentedStringWriter.java | 104 - .../org/codehaus/jackson/io/UTF32Reader.java | 214 -- .../org/codehaus/jackson/io/UTF8Writer.java | 385 --- lib-src/org/codehaus/jackson/io/package.html | 4 - .../jackson/map/AnnotationIntrospector.java | 1066 --------- .../codehaus/jackson/map/BeanDescription.java | 81 - .../jackson/map/ClassIntrospector.java | 84 - .../jackson/map/DeserializationConfig.java | 649 ----- .../jackson/map/DeserializationContext.java | 187 -- .../map/DeserializationProblemHandler.java | 56 - .../jackson/map/DeserializerFactory.java | 103 - .../jackson/map/DeserializerProvider.java | 112 - .../jackson/map/JsonDeserializer.java | 116 - .../jackson/map/JsonMappingException.java | 324 --- .../jackson/map/JsonSerializable.java | 31 - .../jackson/map/JsonSerializableWithType.java | 22 - .../codehaus/jackson/map/JsonSerializer.java | 80 - .../codehaus/jackson/map/KeyDeserializer.java | 28 - .../codehaus/jackson/map/MapperConfig.java | 109 - .../jackson/map/MappingJsonFactory.java | 49 - .../codehaus/jackson/map/ObjectMapper.java | 1668 ------------- .../codehaus/jackson/map/ObjectWriter.java | 289 --- .../jackson/map/ResolvableDeserializer.java | 23 - .../jackson/map/ResolvableSerializer.java | 23 - .../map/RuntimeJsonMappingException.java | 21 - .../jackson/map/SerializationConfig.java | 699 ------ .../jackson/map/SerializerFactory.java | 64 - .../jackson/map/SerializerProvider.java | 329 --- .../org/codehaus/jackson/map/TreeMapper.java | 179 -- .../jackson/map/TypeDeserializer.java | 107 - .../codehaus/jackson/map/TypeSerializer.java | 115 - .../jackson/map/annotate/JsonCachable.java | 32 - .../jackson/map/annotate/JsonDeserialize.java | 120 - .../jackson/map/annotate/JsonSerialize.java | 150 -- .../map/annotate/JsonTypeIdResolver.java | 28 - .../map/annotate/JsonTypeResolver.java | 15 - .../jackson/map/annotate/JsonView.java | 37 - .../jackson/map/annotate/NoClass.java | 19 - .../jackson/map/annotate/package-info.java | 5 - .../jackson/map/deser/ArrayDeserializer.java | 137 -- .../jackson/map/deser/ArrayDeserializers.java | 382 --- .../map/deser/BasicDeserializerFactory.java | 661 ------ .../jackson/map/deser/BeanDeserializer.java | 642 ----- .../map/deser/BeanDeserializerFactory.java | 652 ----- .../map/deser/CollectionDeserializer.java | 124 - .../codehaus/jackson/map/deser/Creator.java | 258 -- .../jackson/map/deser/CreatorContainer.java | 150 -- .../map/deser/CustomDeserializerFactory.java | 190 -- .../jackson/map/deser/DateDeserializer.java | 28 - .../jackson/map/deser/EnumDeserializer.java | 62 - .../map/deser/EnumMapDeserializer.java | 79 - .../jackson/map/deser/EnumResolver.java | 67 - .../map/deser/EnumSetDeserializer.java | 77 - .../map/deser/FromStringDeserializer.java | 113 - .../map/deser/JsonNodeDeserializer.java | 259 -- .../jackson/map/deser/MapDeserializer.java | 280 --- .../jackson/map/deser/PropertyValue.java | 111 - .../map/deser/PropertyValueBuffer.java | 70 - .../map/deser/SettableAnyProperty.java | 127 - .../map/deser/SettableBeanProperty.java | 394 ---- .../map/deser/StdDeserializationContext.java | 303 --- .../jackson/map/deser/StdDeserializer.java | 890 ------- .../map/deser/StdDeserializerProvider.java | 405 ---- .../jackson/map/deser/StdDeserializers.java | 122 - .../jackson/map/deser/StdKeyDeserializer.java | 248 -- .../map/deser/StdKeyDeserializers.java | 85 - .../map/deser/StdScalarDeserializer.java | 29 - .../map/deser/ThrowableDeserializer.java | 85 - .../map/deser/UntypedObjectDeserializer.java | 170 -- .../jackson/map/deser/package-info.java | 5 - .../jackson/map/introspect/Annotated.java | 61 - .../map/introspect/AnnotatedClass.java | 899 ------- .../map/introspect/AnnotatedConstructor.java | 95 - .../map/introspect/AnnotatedField.java | 95 - .../map/introspect/AnnotatedMember.java | 32 - .../map/introspect/AnnotatedMethod.java | 124 - .../map/introspect/AnnotatedMethodMap.java | 84 - .../map/introspect/AnnotatedParameter.java | 74 - .../map/introspect/AnnotatedWithParams.java | 108 - .../jackson/map/introspect/AnnotationMap.java | 74 - .../map/introspect/BasicBeanDescription.java | 837 ------- .../introspect/BasicClassIntrospector.java | 216 -- .../JacksonAnnotationIntrospector.java | 599 ----- .../jackson/map/introspect/MemberKey.java | 83 - .../jackson/map/introspect/MethodFilter.java | 12 - .../introspect/NopAnnotationIntrospector.java | 270 --- .../map/introspect/VisibilityChecker.java | 317 --- .../jackson/map/introspect/package-info.java | 12 - .../jackson/map/jsontype/NamedType.java | 53 - .../jackson/map/jsontype/TypeIdResolver.java | 64 - .../map/jsontype/TypeResolverBuilder.java | 110 - .../impl/AsArrayTypeDeserializer.java | 106 - .../jsontype/impl/AsArrayTypeSerializer.java | 79 - .../impl/AsPropertyTypeDeserializer.java | 92 - .../impl/AsPropertyTypeSerializer.java | 57 - .../impl/AsWrapperTypeDeserializer.java | 97 - .../impl/AsWrapperTypeSerializer.java | 88 - .../jsontype/impl/ClassNameIdResolver.java | 78 - .../impl/MinimalClassNameIdResolver.java | 64 - .../jsontype/impl/StdTypeResolverBuilder.java | 148 -- .../jsontype/impl/TypeDeserializerBase.java | 71 - .../map/jsontype/impl/TypeIdResolverBase.java | 21 - .../map/jsontype/impl/TypeNameIdResolver.java | 110 - .../map/jsontype/impl/TypeSerializerBase.java | 27 - .../map/jsontype/impl/package-info.java | 10 - .../jackson/map/jsontype/package-info.java | 10 - .../codehaus/jackson/map/package-info.java | 34 - .../jackson/map/ser/ArraySerializers.java | 614 ----- .../map/ser/BasicSerializerFactory.java | 581 ----- .../jackson/map/ser/BeanPropertyWriter.java | 309 --- .../jackson/map/ser/BeanSerializer.java | 260 -- .../map/ser/BeanSerializerFactory.java | 489 ---- .../map/ser/ContainerSerializerBase.java | 51 - .../jackson/map/ser/ContainerSerializers.java | 528 ----- .../map/ser/CustomSerializerFactory.java | 270 --- .../jackson/map/ser/EnumMapSerializer.java | 196 -- .../jackson/map/ser/EnumSerializer.java | 68 - .../jackson/map/ser/FailingSerializer.java | 40 - .../map/ser/FilteredBeanPropertyWriter.java | 83 - .../jackson/map/ser/JdkSerializers.java | 102 - .../jackson/map/ser/JsonValueSerializer.java | 142 -- .../jackson/map/ser/MapSerializer.java | 317 --- .../jackson/map/ser/NullSerializer.java | 36 - .../jackson/map/ser/PropertyBuilder.java | 184 -- .../map/ser/ReadOnlyClassToSerializerMap.java | 79 - .../jackson/map/ser/ScalarSerializerBase.java | 42 - .../jackson/map/ser/SerializerBase.java | 117 - .../jackson/map/ser/SerializerCache.java | 237 -- .../jackson/map/ser/StdKeySerializer.java | 39 - .../map/ser/StdSerializerProvider.java | 744 ------ .../jackson/map/ser/StdSerializers.java | 532 ----- .../jackson/map/ser/ToStringSerializer.java | 49 - .../jackson/map/ser/package-info.java | 5 - .../codehaus/jackson/map/type/ArrayType.java | 164 -- .../codehaus/jackson/map/type/ClassKey.java | 94 - .../jackson/map/type/CollectionType.java | 112 - .../codehaus/jackson/map/type/MapType.java | 138 -- .../codehaus/jackson/map/type/SimpleType.java | 178 -- .../codehaus/jackson/map/type/TypeBase.java | 34 - .../jackson/map/type/TypeBindings.java | 200 -- .../jackson/map/type/TypeFactory.java | 599 ----- .../codehaus/jackson/map/type/TypeParser.java | 129 - .../jackson/map/type/package-info.java | 10 - .../jackson/map/util/ArrayBuilders.java | 169 -- .../codehaus/jackson/map/util/ClassUtil.java | 466 ---- .../codehaus/jackson/map/util/EnumValues.java | 42 - .../jackson/map/util/JSONPObject.java | 97 - .../jackson/map/util/JSONWrappedObject.java | 109 - .../codehaus/jackson/map/util/LinkedNode.java | 45 - .../jackson/map/util/ObjectBuffer.java | 237 -- .../map/util/PrimitiveArrayBuilder.java | 180 -- .../codehaus/jackson/map/util/Provider.java | 21 - .../jackson/map/util/StdDateFormat.java | 329 --- .../jackson/map/util/SubTypeHelper.java | 95 - .../jackson/map/util/package-info.java | 4 - .../org/codehaus/jackson/node/ArrayNode.java | 520 ---- .../codehaus/jackson/node/BaseJsonNode.java | 100 - .../codehaus/jackson/node/BigIntegerNode.java | 92 - .../org/codehaus/jackson/node/BinaryNode.java | 176 -- .../codehaus/jackson/node/BooleanNode.java | 59 - .../codehaus/jackson/node/ContainerNode.java | 134 -- .../codehaus/jackson/node/DecimalNode.java | 94 - .../org/codehaus/jackson/node/DoubleNode.java | 104 - .../org/codehaus/jackson/node/IntNode.java | 115 - .../jackson/node/JsonNodeFactory.java | 150 -- .../org/codehaus/jackson/node/LongNode.java | 93 - .../codehaus/jackson/node/MissingNode.java | 67 - .../org/codehaus/jackson/node/NodeCursor.java | 200 -- .../org/codehaus/jackson/node/NullNode.java | 43 - .../codehaus/jackson/node/NumericNode.java | 31 - .../org/codehaus/jackson/node/ObjectNode.java | 417 ---- .../org/codehaus/jackson/node/POJONode.java | 93 - .../org/codehaus/jackson/node/TextNode.java | 240 -- .../jackson/node/TreeTraversingParser.java | 355 --- .../org/codehaus/jackson/node/ValueNode.java | 42 - .../codehaus/jackson/node/package-info.java | 8 - .../org/codehaus/jackson/package-info.java | 30 - .../codehaus/jackson/schema/JsonSchema.java | 80 - .../schema/JsonSerializableSchema.java | 46 - .../codehaus/jackson/schema/SchemaAware.java | 25 - .../codehaus/jackson/schema/package-info.java | 5 - .../jackson/sym/BytesToNameCanonicalizer.java | 958 -------- .../jackson/sym/CharsToNameCanonicalizer.java | 578 ----- lib-src/org/codehaus/jackson/sym/Name.java | 53 - lib-src/org/codehaus/jackson/sym/Name1.java | 41 - lib-src/org/codehaus/jackson/sym/Name2.java | 37 - lib-src/org/codehaus/jackson/sym/Name3.java | 36 - lib-src/org/codehaus/jackson/sym/NameN.java | 68 - .../codehaus/jackson/sym/package-info.java | 5 - .../org/codehaus/jackson/type/JavaType.java | 333 --- .../codehaus/jackson/type/TypeReference.java | 59 - .../codehaus/jackson/type/package-info.java | 8 - .../codehaus/jackson/util/BufferRecycler.java | 109 - .../jackson/util/ByteArrayBuilder.java | 233 -- .../org/codehaus/jackson/util/CharTypes.java | 193 -- .../codehaus/jackson/util/InternCache.java | 48 - .../jackson/util/JsonGeneratorDelegate.java | 225 -- .../jackson/util/JsonParserDelegate.java | 217 -- .../jackson/util/JsonParserSequence.java | 150 -- .../org/codehaus/jackson/util/TextBuffer.java | 634 ----- .../codehaus/jackson/util/TokenBuffer.java | 1235 ---------- .../codehaus/jackson/util/package-info.java | 4 - lib/jmdns.jar | Bin 90934 -> 0 bytes libs/acra-4.4.0.jar | Bin 99184 -> 0 bytes libs/jmdns.jar | Bin 90934 -> 0 bytes project.properties | 13 - res/anim/slide_left.xml | 8 - res/anim/slide_right.xml | 9 - res/drawable-hdpi-v4/remote_xbox_back.xml | 5 - res/drawable-hdpi-v4/remote_xbox_display.xml | 5 - res/drawable-hdpi-v4/remote_xbox_down.xml | 5 - res/drawable-hdpi-v4/remote_xbox_images.xml | 5 - res/drawable-hdpi-v4/remote_xbox_info.xml | 5 - res/drawable-hdpi-v4/remote_xbox_left.xml | 5 - res/drawable-hdpi-v4/remote_xbox_menu.xml | 5 - res/drawable-hdpi-v4/remote_xbox_music.xml | 5 - res/drawable-hdpi-v4/remote_xbox_next.xml | 5 - res/drawable-hdpi-v4/remote_xbox_pause.xml | 5 - res/drawable-hdpi-v4/remote_xbox_play.xml | 5 - res/drawable-hdpi-v4/remote_xbox_previous.xml | 5 - res/drawable-hdpi-v4/remote_xbox_right.xml | 5 - .../remote_xbox_seek_back.xml | 5 - .../remote_xbox_seek_forward.xml | 5 - res/drawable-hdpi-v4/remote_xbox_select.xml | 5 - res/drawable-hdpi-v4/remote_xbox_stop.xml | 5 - res/drawable-hdpi-v4/remote_xbox_title.xml | 5 - res/drawable-hdpi-v4/remote_xbox_tv.xml | 5 - res/drawable-hdpi-v4/remote_xbox_up.xml | 5 - res/drawable-hdpi-v4/remote_xbox_video.xml | 5 - res/drawable-land/remote_xbox_back.xml | 5 - res/drawable-land/remote_xbox_display.xml | 5 - res/drawable-land/remote_xbox_down.xml | 5 - res/drawable-land/remote_xbox_images.xml | 5 - res/drawable-land/remote_xbox_info.xml | 5 - res/drawable-land/remote_xbox_left.xml | 5 - res/drawable-land/remote_xbox_menu.xml | 5 - res/drawable-land/remote_xbox_music.xml | 5 - res/drawable-land/remote_xbox_next.xml | 5 - res/drawable-land/remote_xbox_pause.xml | 5 - res/drawable-land/remote_xbox_play.xml | 5 - res/drawable-land/remote_xbox_power.xml | 5 - res/drawable-land/remote_xbox_previous.xml | 5 - res/drawable-land/remote_xbox_right.xml | 5 - res/drawable-land/remote_xbox_seek_back.xml | 5 - .../remote_xbox_seek_forward.xml | 5 - res/drawable-land/remote_xbox_select.xml | 5 - res/drawable-land/remote_xbox_stop.xml | 5 - res/drawable-land/remote_xbox_title.xml | 5 - res/drawable-land/remote_xbox_tv.xml | 5 - res/drawable-land/remote_xbox_up.xml | 5 - res/drawable-land/remote_xbox_video.xml | 5 - res/drawable/bottom_logo.xml | 5 - res/drawable/bottom_text.xml | 5 - res/drawable/bubble_del.xml | 5 - res/drawable/listitem_bg.xml | 11 - res/drawable/listitem_subtitle.xml | 5 - res/drawable/listitem_title.xml | 5 - res/drawable/now_playing_next.xml | 5 - res/drawable/now_playing_pause.xml | 5 - res/drawable/now_playing_play.xml | 5 - res/drawable/now_playing_playlist.xml | 5 - res/drawable/now_playing_previous.xml | 5 - res/drawable/now_playing_stop.xml | 5 - res/drawable/remote_xbox_back.xml | 5 - res/drawable/remote_xbox_display.xml | 5 - res/drawable/remote_xbox_down.xml | 5 - res/drawable/remote_xbox_info.xml | 5 - res/drawable/remote_xbox_left.xml | 5 - res/drawable/remote_xbox_menu.xml | 5 - res/drawable/remote_xbox_next.xml | 5 - res/drawable/remote_xbox_pause.xml | 5 - res/drawable/remote_xbox_play.xml | 5 - res/drawable/remote_xbox_previous.xml | 5 - res/drawable/remote_xbox_right.xml | 5 - res/drawable/remote_xbox_seek_back.xml | 5 - res/drawable/remote_xbox_seek_forward.xml | 5 - res/drawable/remote_xbox_select.xml | 5 - res/drawable/remote_xbox_stop.xml | 5 - res/drawable/remote_xbox_title.xml | 5 - res/drawable/remote_xbox_up.xml | 5 - res/drawable/remote_xbox_widget_back.xml | 5 - res/drawable/remote_xbox_widget_display.xml | 5 - res/drawable/remote_xbox_widget_down.xml | 5 - res/drawable/remote_xbox_widget_info.xml | 5 - res/drawable/remote_xbox_widget_left.xml | 5 - res/drawable/remote_xbox_widget_menu.xml | 5 - res/drawable/remote_xbox_widget_next.xml | 5 - res/drawable/remote_xbox_widget_pause.xml | 5 - res/drawable/remote_xbox_widget_play.xml | 5 - res/drawable/remote_xbox_widget_previous.xml | 5 - res/drawable/remote_xbox_widget_right.xml | 5 - res/drawable/remote_xbox_widget_seek_back.xml | 5 - .../remote_xbox_widget_seek_forward.xml | 5 - res/drawable/remote_xbox_widget_select.xml | 5 - res/drawable/remote_xbox_widget_stop.xml | 5 - res/drawable/remote_xbox_widget_title.xml | 5 - res/drawable/remote_xbox_widget_up.xml | 5 - res/layout-land-hdpi-v4/remote_xbox.xml | 45 - .../remote_xbox_extended.xml | 45 - res/layout-land-ldpi-v4/remote_xbox.xml | 41 - res/layout-land/home.xml | 43 - res/layout-land/nowplaying.xml | 138 -- res/layout-land/remote_xbox.xml | 45 - res/layout-ldpi-v4/remote_xbox.xml | 79 - res/layout-xhdpi/slidingtab_widget.xml | 40 - res/layout/about.xml | 49 - res/layout/actor_item.xml | 41 - res/layout/albumgrid.xml | 9 - res/layout/albuminfo.xml | 35 - res/layout/albumtracks.xml | 40 - res/layout/artistinfo.xml | 31 - res/layout/blankgrid.xml | 19 - res/layout/blanklist.xml | 17 - res/layout/home.xml | 43 - res/layout/home_item.xml | 16 - res/layout/listmessage.xml | 19 - res/layout/loading_message.xml | 21 - res/layout/loadinglistentry.xml | 21 - res/layout/movielibrary.xml | 96 - res/layout/musicartist.xml | 58 - res/layout/musicgenre.xml | 76 - res/layout/musiclibrary.xml | 122 - res/layout/nowplaying.xml | 176 -- res/layout/playlist.xml | 75 - res/layout/preference_host.xml | 135 -- res/layout/remote_gesture.xml | 46 - res/layout/remote_gesture_extended.xml | 58 - res/layout/remote_xbox.xml | 75 - res/layout/remote_xbox_extended.xml | 86 - res/layout/sendtext.xml | 54 - res/layout/setup_page_1.xml | 34 - res/layout/setup_page_3.xml | 18 - res/layout/setup_page_login.xml | 27 - res/layout/setup_wizard.xml | 47 - res/layout/slidingtab_overlay.xml | 13 - res/layout/slidingtab_widget.xml | 40 - res/layout/titlebar.xml | 22 - res/layout/tvdetails.xml | 86 - res/layout/tvlibrary.xml | 96 - res/layout/widget_xbox.xml | 182 -- res/layout/widget_xbox_small.xml | 98 - res/values-v14/dimens.xml | 3 - res/values/attrs.xml | 42 - res/values/colors.xml | 8 - res/values/dimens.xml | 4 - res/values/ids.xml | 6 - res/values/styles.xml | 42 - res/xml/app_widget_remote.xml | 15 - settings.gradle | 1 + .../drawable/CrossFadeDrawable.java | 289 --- .../BigPictureNotificationBuilder.java | 38 - .../LargeIconNotificationBuilder.java | 52 - .../notification/NotificationBuilder.java | 60 - .../NowPlayingNotificationManager.java | 164 -- src/org/xbmc/android/util/Base64.java | 2051 ---------------- src/org/xbmc/android/util/IOUtilities.java | 67 - src/org/xbmc/android/util/KeyTracker.java | 107 - .../util/OnLongPressBackKeyTracker.java | 38 - src/org/xbmc/android/util/WakeOnLan.java | 81 - .../api/business/IEventClientManager.java | 119 - src/org/xbmc/api/info/GuiActions.java | 221 -- src/org/xbmc/api/info/MusicInfo.java | 48 - src/org/xbmc/api/info/SystemInfo.java | 73 - src/org/xbmc/api/info/VideoInfo.java | 61 - src/org/xbmc/eventclient/PacketBUTTON.java | 139 -- 1422 files changed, 36436 insertions(+), 83959 deletions(-) delete mode 100644 .classpath create mode 100644 .idea/.name create mode 100644 .idea/codeStyleSettings.xml create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/libraries/acra_4_4_0.xml create mode 100644 .idea/libraries/jackson_core_lgpl_1_9_13.xml create mode 100644 .idea/libraries/jackson_mapper_lgpl_1_9_13.xml create mode 100644 .idea/libraries/jmdns_3_4_1.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml delete mode 100644 .project delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 AndroidManifest.xml create mode 100644 android-xbmcremote.iml delete mode 100644 ant.properties create mode 100644 app/.gitignore create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/main/AndroidManifest.xml rename {src => app/src/main/java}/org/xbmc/android/remote/business/AbstractManager.java (84%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/AbstractThread.java (89%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/CacheManager.java (80%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/Command.java (91%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/ControlManager.java (76%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/DiskCacheThread.java (72%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/DownloadThread.java (81%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/EventClientManager.java (91%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/InfoManager.java (81%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/ManagerFactory.java (97%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/ManagerThread.java (96%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/MemCacheThread.java (76%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/MusicManager.java (81%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/NowPlayingPollerThread.java (92%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/TvShowManager.java (81%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/VideoManager.java (82%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/provider/HostProvider.java (73%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java (87%) rename {src => app/src/main/java}/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java (96%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/AboutActivity.java (80%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/AbsListActivity.java (87%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java (94%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/DialogFactory.java (78%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java (67%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java (94%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/GridActivity.java (96%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/HomeActivity.java (74%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java (93%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/ListActivity.java (96%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java (93%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java (69%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java (80%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java (75%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java (74%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java (75%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java (85%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java (90%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/RemoteActivity.java (95%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/SettingsActivity.java (91%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java (67%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java (79%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java (85%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java (98%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/AbstractController.java (64%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/ActorListController.java (93%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/AlbumListController.java (67%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java (52%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/ArtistListController.java (85%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/EpisodeListController.java (66%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/FileListController.java (83%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/GestureController.java (80%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/HomeController.java (85%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/HostPreference.java (78%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/IController.java (97%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/ListController.java (88%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java (67%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/MediaIntentController.java (88%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java (90%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/MovieListController.java (65%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java (88%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java (80%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/NowPlayingController.java (84%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/PlaylistController.java (64%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/RemoteController.java (73%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/SeasonListController.java (90%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/SettingsController.java (91%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/SongListController.java (58%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/TvShowListController.java (68%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/controller/UrlIntentController.java (88%) create mode 100644 app/src/main/java/org/xbmc/android/remote/presentation/drawable/CrossFadeDrawable.java rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java (51%) create mode 100644 app/src/main/java/org/xbmc/android/remote/presentation/notification/BigPictureNotificationBuilder.java create mode 100644 app/src/main/java/org/xbmc/android/remote/presentation/notification/LargeIconNotificationBuilder.java create mode 100644 app/src/main/java/org/xbmc/android/remote/presentation/notification/NotificationBuilder.java create mode 100644 app/src/main/java/org/xbmc/android/remote/presentation/notification/NowPlayingNotificationManager.java rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/AbstractItemView.java (72%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java (86%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java (84%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java (88%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/JewelView.java (81%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java (92%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java (92%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/Wizard.java (82%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/WizardPage.java (90%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java (95%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java (95%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java (96%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java (89%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java (93%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java (92%) rename {src => app/src/main/java}/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java (85%) create mode 100644 app/src/main/java/org/xbmc/android/util/Base64.java rename {src => app/src/main/java}/org/xbmc/android/util/ClientFactory.java (87%) rename {src => app/src/main/java}/org/xbmc/android/util/ConnectionFactory.java (57%) rename {src => app/src/main/java}/org/xbmc/android/util/Crc32.java (85%) rename {src => app/src/main/java}/org/xbmc/android/util/HostFactory.java (88%) create mode 100644 app/src/main/java/org/xbmc/android/util/IOUtilities.java rename {src => app/src/main/java}/org/xbmc/android/util/ImportUtilities.java (50%) create mode 100644 app/src/main/java/org/xbmc/android/util/KeyTracker.java rename {src => app/src/main/java}/org/xbmc/android/util/MacAddressResolver.java (89%) create mode 100644 app/src/main/java/org/xbmc/android/util/OnLongPressBackKeyTracker.java rename {src => app/src/main/java}/org/xbmc/android/util/PowerDown.java (97%) rename {src => app/src/main/java}/org/xbmc/android/util/SMSConstants.java (86%) rename {src => app/src/main/java}/org/xbmc/android/util/SmsMmsMessage.java (92%) rename {src => app/src/main/java}/org/xbmc/android/util/SmsPopupUtils.java (85%) create mode 100644 app/src/main/java/org/xbmc/android/util/WakeOnLan.java rename {src => app/src/main/java}/org/xbmc/android/util/WifiHelper.java (65%) rename {src => app/src/main/java}/org/xbmc/android/util/YoutubeURLParser.java (78%) rename {src => app/src/main/java}/org/xbmc/android/widget/FastScrollView.java (98%) rename {src => app/src/main/java}/org/xbmc/android/widget/IdleListDetector.java (93%) rename {src => app/src/main/java}/org/xbmc/android/widget/IdleListener.java (86%) rename {src => app/src/main/java}/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java (83%) rename {src => app/src/main/java}/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java (92%) rename {src => app/src/main/java}/org/xbmc/android/widget/gestureremote/GestureRemoteView.java (82%) rename {src => app/src/main/java}/org/xbmc/android/widget/gestureremote/IGestureListener.java (97%) rename {src => app/src/main/java}/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java (87%) rename {src => app/src/main/java}/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java (91%) rename {src => app/src/main/java}/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java (85%) rename {src => app/src/main/java}/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java (77%) rename {src => app/src/main/java}/org/xbmc/android/widget/slidingtabs/SnapAnimation.java (84%) rename {src => app/src/main/java}/org/xbmc/api/business/CoverResponse.java (94%) rename {src => app/src/main/java}/org/xbmc/api/business/DataResponse.java (86%) rename {src => app/src/main/java}/org/xbmc/api/business/IControlManager.java (70%) create mode 100644 app/src/main/java/org/xbmc/api/business/IEventClientManager.java rename {src => app/src/main/java}/org/xbmc/api/business/IInfoManager.java (78%) rename {src => app/src/main/java}/org/xbmc/api/business/IManager.java (90%) rename {src => app/src/main/java}/org/xbmc/api/business/IMusicManager.java (85%) rename {src => app/src/main/java}/org/xbmc/api/business/INotifiableManager.java (97%) rename {src => app/src/main/java}/org/xbmc/api/business/ISortableManager.java (96%) rename {src => app/src/main/java}/org/xbmc/api/business/ITvShowManager.java (87%) rename {src => app/src/main/java}/org/xbmc/api/business/IVideoManager.java (89%) rename {src => app/src/main/java}/org/xbmc/api/data/IClient.java (95%) rename {src => app/src/main/java}/org/xbmc/api/data/IControlClient.java (81%) rename {src => app/src/main/java}/org/xbmc/api/data/IEventClient.java (50%) rename {src => app/src/main/java}/org/xbmc/api/data/IInfoClient.java (83%) rename {src => app/src/main/java}/org/xbmc/api/data/IMusicClient.java (84%) rename {src => app/src/main/java}/org/xbmc/api/data/IPictureClient.java (96%) rename {src => app/src/main/java}/org/xbmc/api/data/ITvShowClient.java (82%) rename {src => app/src/main/java}/org/xbmc/api/data/IVideoClient.java (78%) rename {src => app/src/main/java}/org/xbmc/api/info/FileTypes.java (85%) create mode 100644 app/src/main/java/org/xbmc/api/info/GuiActions.java rename {src => app/src/main/java}/org/xbmc/api/info/GuiSettings.java (78%) create mode 100644 app/src/main/java/org/xbmc/api/info/MusicInfo.java rename {src => app/src/main/java}/org/xbmc/api/info/PlayStatus.java (92%) create mode 100644 app/src/main/java/org/xbmc/api/info/SystemInfo.java create mode 100644 app/src/main/java/org/xbmc/api/info/VideoInfo.java rename {src => app/src/main/java}/org/xbmc/api/object/Actor.java (99%) rename {src => app/src/main/java}/org/xbmc/api/object/Album.java (90%) rename {src => app/src/main/java}/org/xbmc/api/object/Artist.java (96%) rename {src => app/src/main/java}/org/xbmc/api/object/Episode.java (82%) rename {src => app/src/main/java}/org/xbmc/api/object/FileLocation.java (93%) rename {src => app/src/main/java}/org/xbmc/api/object/Genre.java (94%) rename {src => app/src/main/java}/org/xbmc/api/object/Host.java (95%) rename {src => app/src/main/java}/org/xbmc/api/object/ICoverArt.java (97%) rename {src => app/src/main/java}/org/xbmc/api/object/INamedResource.java (100%) rename {src => app/src/main/java}/org/xbmc/api/object/Movie.java (91%) rename {src => app/src/main/java}/org/xbmc/api/object/Season.java (96%) rename {src => app/src/main/java}/org/xbmc/api/object/Song.java (87%) rename {src => app/src/main/java}/org/xbmc/api/object/TvShow.java (91%) rename {src => app/src/main/java}/org/xbmc/api/presentation/INotifiableController.java (97%) rename {src => app/src/main/java}/org/xbmc/api/type/CacheType.java (99%) rename {src => app/src/main/java}/org/xbmc/api/type/DirectoryMask.java (85%) rename {src => app/src/main/java}/org/xbmc/api/type/ListType.java (99%) rename {src => app/src/main/java}/org/xbmc/api/type/LogType.java (100%) rename {src => app/src/main/java}/org/xbmc/api/type/MediaType.java (89%) rename {src => app/src/main/java}/org/xbmc/api/type/SeekType.java (100%) rename {src => app/src/main/java}/org/xbmc/api/type/SortType.java (99%) rename {src => app/src/main/java}/org/xbmc/api/type/ThumbSize.java (60%) rename {src => app/src/main/java}/org/xbmc/eventclient/ButtonCodes.java (98%) rename {src => app/src/main/java}/org/xbmc/eventclient/EventClient.java (70%) rename {src => app/src/main/java}/org/xbmc/eventclient/Packet.java (70%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketACTION.java (81%) create mode 100644 app/src/main/java/org/xbmc/eventclient/PacketBUTTON.java rename {src => app/src/main/java}/org/xbmc/eventclient/PacketBYE.java (76%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketHELO.java (76%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketLOG.java (50%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketMOUSE.java (82%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketNOTIFICATION.java (77%) rename {src => app/src/main/java}/org/xbmc/eventclient/PacketPING.java (92%) rename {src => app/src/main/java}/org/xbmc/httpapi/BroadcastListener.java (76%) rename {src => app/src/main/java}/org/xbmc/httpapi/Connection.java (85%) rename {src => app/src/main/java}/org/xbmc/httpapi/HttpApi.java (99%) rename {src => app/src/main/java}/org/xbmc/httpapi/NoNetworkException.java (96%) rename {src => app/src/main/java}/org/xbmc/httpapi/NoSettingsException.java (92%) rename {src => app/src/main/java}/org/xbmc/httpapi/WifiStateException.java (98%) rename {src => app/src/main/java}/org/xbmc/httpapi/WrongDataFormatException.java (96%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/Client.java (84%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/ControlClient.java (81%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/InfoClient.java (81%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/MusicClient.java (84%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/PictureClient.java (95%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/TvShowClient.java (87%) rename {src => app/src/main/java}/org/xbmc/httpapi/client/VideoClient.java (80%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/Connection.java (85%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/JsonRpc.java (99%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/Client.java (91%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/ControlClient.java (70%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/InfoClient.java (72%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/MusicClient.java (73%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/TvShowClient.java (63%) rename {src => app/src/main/java}/org/xbmc/jsonrpc/client/VideoClient.java (74%) create mode 100644 app/src/main/res/anim/slide_left.xml create mode 100644 app/src/main/res/anim/slide_right.xml rename {res => app/src/main/res}/drawable-hdpi-v4/about_back.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bottom_logo_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bottom_logo_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bottom_text_down.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bottom_text_up.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bottombar_bg.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bubble_add.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bubble_del_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/bubble_del_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/coverbox_back.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/default_album.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/default_jewel.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/default_poster.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/default_season.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/default_tvshow.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_album.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_album_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_album_dark_big.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_artist.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_artist_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_file.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_folder.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_folder_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_genre.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_genre_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_movie.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_music.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_picture.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_playing.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_power.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_reconnect.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_remote.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_home_tv.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_lastfm.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_movie_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_picture.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_play.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_playlist_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_shoutcast.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_song.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_song_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_song_light.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_va_dark.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/icon_video.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/jewel_cd.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/jewel_dvd.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/jewel_tv.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/layout_top_bar.9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_about.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_add_host.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_album.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_download.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_exit.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_gesture_mode.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_hide_watched.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_nowplaying.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_qr_code.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_refresh.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_remote.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_settings.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_show_watched.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_song.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_sort.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_switch.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_text_entry.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_view.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_xbmc_exit.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/menu_xbmc_s.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_next_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_next_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_pause_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_pause_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_play_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_play_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_playlist_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_playlist_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_previous_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_previous_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_stop_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/now_playing_stop_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/pgbar_act.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/pgbar_thumb.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/playlist_rightboxes.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_gest_cursor.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox__top_left.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox__top_right.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_back.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_back_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_display.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_display_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_display_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_down.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_down_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesture_back_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesture_info_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesture_menu_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesture_title_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesturezone.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_gesturezone_dim.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_images.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_images_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_images_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_info.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_info_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_left.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_left_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_menu.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_menu_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_music.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_music_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_music_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_next.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_next_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_pause.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_pause_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_play.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_play_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_previous.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_previous_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_right.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_right_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_seek_back_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_seek_forward_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_select.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_select_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_stop.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_stop_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_title.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_title_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_tv.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_tv_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_tv_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_up.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_up_up.png (100%) create mode 100644 app/src/main/res/drawable-hdpi-v4/remote_xbox_video.xml rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_video_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_video_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget__top_left.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget__top_right.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_back_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_back_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_display_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_display_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_down_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_down_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_info_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_info_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_left_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_left_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_menu_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_menu_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_next_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_next_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_pause_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_pause_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_play_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_play_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_previous_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_previous_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_right_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_right_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_seek_back_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_seek_forward_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_select_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_select_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_stop_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_stop_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_title_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_title_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_up_down.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/remote_xbox_widget_up_up.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/scrollbar_handle.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/shiny_black_back.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_actor_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_actor_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_actor_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_album_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_album_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_album_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_artist_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_artist_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_artist_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_background.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_filemode_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_filemode_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_filemode_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_genre_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_genre_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_genre_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_movie_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_movie_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_movie_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_playlist_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_playlist_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_playlist_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_slider.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_song_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_song_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_song_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_tv_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_tv_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_tv_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_va_off.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_va_on.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/st_va_over.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_0.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_1.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_10.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_2.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_3.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_4.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_5.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_6.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_7.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_8.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/stars_9.png (100%) rename {res => app/src/main/res}/drawable-hdpi-v4/timeborder.9.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_back_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_display_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_display_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_down_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_images_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_images_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_info_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_left_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_menu_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_music_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_music_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_next_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_pause_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_play_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_power_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_power_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_previous_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_right_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_seek_back_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_seek_forward_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_select_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_stop_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_title_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_tv_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_tv_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_up_up.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_video_down.png (100%) rename {res => app/src/main/res}/drawable-land-hdpi-v4/remote_xbox_video_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_back_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_down_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_info_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_left_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_menu_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_next_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_pause_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_play_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_power_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_power_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_previous_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_right_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_seek_back_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_seek_forward_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_select_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_stop_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_title_up.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable-land-ldpi-v4/remote_xbox_up_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_back.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_back_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_display.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_display_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_display_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_down.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_down_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_images.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_images_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_images_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_info.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_info_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_left.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_left_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_menu.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_menu_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_music.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_music_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_music_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_next.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_next_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_pause.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_pause_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_play.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_play_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_power.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_power_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_power_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_previous.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_previous_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_right.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_right_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_seek_back.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_seek_back_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_seek_forward.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_seek_forward_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_select.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_select_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_stop.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_stop_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_title.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_title_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_tv.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_tv_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_tv_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_up.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_up_up.png (100%) create mode 100644 app/src/main/res/drawable-land/remote_xbox_video.xml rename {res => app/src/main/res}/drawable-land/remote_xbox_video_down.png (100%) rename {res => app/src/main/res}/drawable-land/remote_xbox_video_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_gest_cursor.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox__top_left.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox__top_right.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_back_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_display_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_display_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_down_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesture_back_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesture_info_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesture_menu_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesture_title_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesturezone.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_gesturezone_dim.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_info_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_left_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_menu_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_next_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_pause_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_play_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_previous_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_right_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_seek_back_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_seek_forward_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_select_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_stop_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_title_up.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable-ldpi-v4/remote_xbox_up_up.png (100%) rename {res => app/src/main/res}/drawable/about_back.png (100%) rename {res => app/src/main/res}/drawable/bottom_controls_background.png (100%) create mode 100644 app/src/main/res/drawable/bottom_logo.xml rename {res => app/src/main/res}/drawable/bottom_logo_down.png (100%) rename {res => app/src/main/res}/drawable/bottom_logo_up.png (100%) create mode 100644 app/src/main/res/drawable/bottom_text.xml rename {res => app/src/main/res}/drawable/bottom_text_down.9.png (100%) rename {res => app/src/main/res}/drawable/bottom_text_up.9.png (100%) rename {res => app/src/main/res}/drawable/bottombar_bg.png (100%) rename {res => app/src/main/res}/drawable/bubble_add.png (100%) create mode 100644 app/src/main/res/drawable/bubble_del.xml rename {res => app/src/main/res}/drawable/bubble_del_down.png (100%) rename {res => app/src/main/res}/drawable/bubble_del_up.png (100%) rename {res => app/src/main/res}/drawable/check_mark.png (100%) rename {res => app/src/main/res}/drawable/coverbox_back.png (100%) rename {res => app/src/main/res}/drawable/default_album.png (100%) rename {res => app/src/main/res}/drawable/default_jewel.png (100%) rename {res => app/src/main/res}/drawable/default_poster.png (100%) rename {res => app/src/main/res}/drawable/default_season.png (100%) rename {res => app/src/main/res}/drawable/default_tvshow.png (100%) rename {res => app/src/main/res}/drawable/dialog_full_dark.9.png (100%) rename {res => app/src/main/res}/drawable/home_bottom.9.png (100%) rename {res => app/src/main/res}/drawable/icon.png (100%) rename {res => app/src/main/res}/drawable/icon_album.png (100%) rename {res => app/src/main/res}/drawable/icon_album_big.png (100%) rename {res => app/src/main/res}/drawable/icon_album_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_album_dark_big.png (100%) rename {res => app/src/main/res}/drawable/icon_artist.png (100%) rename {res => app/src/main/res}/drawable/icon_artist_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_file.png (100%) rename {res => app/src/main/res}/drawable/icon_folder.png (100%) rename {res => app/src/main/res}/drawable/icon_folder_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_genre.png (100%) rename {res => app/src/main/res}/drawable/icon_genre_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_home_movie.png (100%) rename {res => app/src/main/res}/drawable/icon_home_music.png (100%) rename {res => app/src/main/res}/drawable/icon_home_picture.png (100%) rename {res => app/src/main/res}/drawable/icon_home_playing.png (100%) rename {res => app/src/main/res}/drawable/icon_home_power.png (100%) rename {res => app/src/main/res}/drawable/icon_home_reconnect.png (100%) rename {res => app/src/main/res}/drawable/icon_home_remote.png (100%) rename {res => app/src/main/res}/drawable/icon_home_tv.png (100%) rename {res => app/src/main/res}/drawable/icon_home_voice.png (100%) rename {res => app/src/main/res}/drawable/icon_lastfm.png (100%) rename {res => app/src/main/res}/drawable/icon_movie_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_picture.png (100%) rename {res => app/src/main/res}/drawable/icon_play.png (100%) rename {res => app/src/main/res}/drawable/icon_playing.png (100%) rename {res => app/src/main/res}/drawable/icon_playlist_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_shoutcast.png (100%) rename {res => app/src/main/res}/drawable/icon_song.png (100%) rename {res => app/src/main/res}/drawable/icon_song_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_song_light.png (100%) rename {res => app/src/main/res}/drawable/icon_va_dark.png (100%) rename {res => app/src/main/res}/drawable/icon_video.png (100%) rename {res => app/src/main/res}/drawable/icon_video_light.png (100%) rename {res => app/src/main/res}/drawable/icon_zip.png (100%) rename {res => app/src/main/res}/drawable/jewel_cd.9.png (100%) rename {res => app/src/main/res}/drawable/jewel_dvd.9.png (100%) rename {res => app/src/main/res}/drawable/jewel_tv.9.png (100%) rename {res => app/src/main/res}/drawable/layout_top_bar.9.png (100%) create mode 100644 app/src/main/res/drawable/listitem_bg.xml rename {res => app/src/main/res}/drawable/listitem_bottom_rounded.9.png (100%) create mode 100644 app/src/main/res/drawable/listitem_subtitle.xml create mode 100644 app/src/main/res/drawable/listitem_title.xml rename {res => app/src/main/res}/drawable/menu_about.png (100%) rename {res => app/src/main/res}/drawable/menu_add_host.png (100%) rename {res => app/src/main/res}/drawable/menu_album.png (100%) rename {res => app/src/main/res}/drawable/menu_download.png (100%) rename {res => app/src/main/res}/drawable/menu_exit.png (100%) rename {res => app/src/main/res}/drawable/menu_gesture_mode.png (100%) rename {res => app/src/main/res}/drawable/menu_hide_watched.png (100%) rename {res => app/src/main/res}/drawable/menu_nowplaying.png (100%) rename {res => app/src/main/res}/drawable/menu_qr_code.png (100%) rename {res => app/src/main/res}/drawable/menu_refresh.png (100%) rename {res => app/src/main/res}/drawable/menu_remote.png (100%) rename {res => app/src/main/res}/drawable/menu_settings.png (100%) rename {res => app/src/main/res}/drawable/menu_show_watched.png (100%) rename {res => app/src/main/res}/drawable/menu_song.png (100%) rename {res => app/src/main/res}/drawable/menu_sort.png (100%) rename {res => app/src/main/res}/drawable/menu_switch.png (100%) rename {res => app/src/main/res}/drawable/menu_text_entry.png (100%) rename {res => app/src/main/res}/drawable/menu_view.png (100%) rename {res => app/src/main/res}/drawable/menu_xbmc_exit.png (100%) rename {res => app/src/main/res}/drawable/menu_xbmc_s.png (100%) rename {res => app/src/main/res}/drawable/nocover.png (100%) rename {res => app/src/main/res}/drawable/notif_pause.png (100%) rename {res => app/src/main/res}/drawable/notif_pic.png (100%) rename {res => app/src/main/res}/drawable/notif_play.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_next.xml rename {res => app/src/main/res}/drawable/now_playing_next_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_next_up.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_pause.xml rename {res => app/src/main/res}/drawable/now_playing_pause_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_pause_up.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_play.xml rename {res => app/src/main/res}/drawable/now_playing_play_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_play_up.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_playlist.xml rename {res => app/src/main/res}/drawable/now_playing_playlist_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_playlist_up.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_previous.xml rename {res => app/src/main/res}/drawable/now_playing_previous_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_previous_up.png (100%) create mode 100644 app/src/main/res/drawable/now_playing_stop.xml rename {res => app/src/main/res}/drawable/now_playing_stop_down.png (100%) rename {res => app/src/main/res}/drawable/now_playing_stop_up.png (100%) rename {res => app/src/main/res}/drawable/person.png (100%) rename {res => app/src/main/res}/drawable/person_black_small.png (100%) rename {res => app/src/main/res}/drawable/person_small.png (100%) rename {res => app/src/main/res}/drawable/pgbar_act.png (100%) rename {res => app/src/main/res}/drawable/pgbar_inact.png (100%) rename {res => app/src/main/res}/drawable/pgbar_thumb.png (100%) rename {res => app/src/main/res}/drawable/playlist_rightboxes.png (100%) rename {res => app/src/main/res}/drawable/poster_big.png (100%) rename {res => app/src/main/res}/drawable/progressbar.xml (59%) rename {res => app/src/main/res}/drawable/remote_gest_border_left.png (100%) rename {res => app/src/main/res}/drawable/remote_gest_border_right.png (100%) rename {res => app/src/main/res}/drawable/remote_gest_cursor.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox__top_left.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox__top_right.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_back.xml rename {res => app/src/main/res}/drawable/remote_xbox_back_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_back_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_display.xml rename {res => app/src/main/res}/drawable/remote_xbox_display_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_display_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_down.xml rename {res => app/src/main/res}/drawable/remote_xbox_down_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_down_up.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesture_back_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesture_info_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesture_menu_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesture_title_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesturezone.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_gesturezone_dim.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_info.xml rename {res => app/src/main/res}/drawable/remote_xbox_info_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_info_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_left.xml rename {res => app/src/main/res}/drawable/remote_xbox_left_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_left_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_menu.xml rename {res => app/src/main/res}/drawable/remote_xbox_menu_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_menu_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_next.xml rename {res => app/src/main/res}/drawable/remote_xbox_next_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_next_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_pause.xml rename {res => app/src/main/res}/drawable/remote_xbox_pause_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_pause_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_play.xml rename {res => app/src/main/res}/drawable/remote_xbox_play_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_play_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_previous.xml rename {res => app/src/main/res}/drawable/remote_xbox_previous_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_previous_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_right.xml rename {res => app/src/main/res}/drawable/remote_xbox_right_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_right_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_seek_back.xml rename {res => app/src/main/res}/drawable/remote_xbox_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_seek_back_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_seek_forward.xml rename {res => app/src/main/res}/drawable/remote_xbox_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_seek_forward_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_select.xml rename {res => app/src/main/res}/drawable/remote_xbox_select_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_select_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_stop.xml rename {res => app/src/main/res}/drawable/remote_xbox_stop_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_stop_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_title.xml rename {res => app/src/main/res}/drawable/remote_xbox_title_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_title_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_up.xml rename {res => app/src/main/res}/drawable/remote_xbox_up_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_up_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_back.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_back_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_back_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_display.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_display_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_display_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_down.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_down_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_down_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_info.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_info_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_info_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_left.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_left_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_left_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_menu.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_menu_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_menu_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_next.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_next_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_next_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_pause.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_pause_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_pause_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_play.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_play_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_play_up.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_preview.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_previous.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_previous_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_previous_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_right.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_right_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_right_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_seek_back.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_seek_back_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_seek_back_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_seek_forward.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_seek_forward_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_seek_forward_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_select.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_select_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_select_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_stop.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_stop_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_stop_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_title.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_title_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_title_up.png (100%) create mode 100644 app/src/main/res/drawable/remote_xbox_widget_up.xml rename {res => app/src/main/res}/drawable/remote_xbox_widget_up_down.png (100%) rename {res => app/src/main/res}/drawable/remote_xbox_widget_up_up.png (100%) rename {res => app/src/main/res}/drawable/scrollbar_handle.png (100%) rename {res => app/src/main/res}/drawable/scrollbar_handle_accelerated_anim2.9.png (100%) rename {res => app/src/main/res}/drawable/selected.9.png (100%) rename {res => app/src/main/res}/drawable/shiny_black_back.png (100%) rename {res => app/src/main/res}/drawable/smallborder.9.png (100%) rename {res => app/src/main/res}/drawable/st_actor_off.png (100%) rename {res => app/src/main/res}/drawable/st_actor_on.png (100%) rename {res => app/src/main/res}/drawable/st_actor_over.png (100%) rename {res => app/src/main/res}/drawable/st_album_off.png (100%) rename {res => app/src/main/res}/drawable/st_album_on.png (100%) rename {res => app/src/main/res}/drawable/st_album_over.png (100%) rename {res => app/src/main/res}/drawable/st_artist_off.png (100%) rename {res => app/src/main/res}/drawable/st_artist_on.png (100%) rename {res => app/src/main/res}/drawable/st_artist_over.png (100%) rename {res => app/src/main/res}/drawable/st_background.png (100%) rename {res => app/src/main/res}/drawable/st_filemode_off.png (100%) rename {res => app/src/main/res}/drawable/st_filemode_on.png (100%) rename {res => app/src/main/res}/drawable/st_filemode_over.png (100%) rename {res => app/src/main/res}/drawable/st_genre_off.png (100%) rename {res => app/src/main/res}/drawable/st_genre_on.png (100%) rename {res => app/src/main/res}/drawable/st_genre_over.png (100%) rename {res => app/src/main/res}/drawable/st_movie_off.png (100%) rename {res => app/src/main/res}/drawable/st_movie_on.png (100%) rename {res => app/src/main/res}/drawable/st_movie_over.png (100%) rename {res => app/src/main/res}/drawable/st_playlist_off.png (100%) rename {res => app/src/main/res}/drawable/st_playlist_on.png (100%) rename {res => app/src/main/res}/drawable/st_playlist_over.png (100%) rename {res => app/src/main/res}/drawable/st_slider.png (100%) rename {res => app/src/main/res}/drawable/st_song_off.png (100%) rename {res => app/src/main/res}/drawable/st_song_on.png (100%) rename {res => app/src/main/res}/drawable/st_song_over.png (100%) rename {res => app/src/main/res}/drawable/st_tv_off.png (100%) rename {res => app/src/main/res}/drawable/st_tv_on.png (100%) rename {res => app/src/main/res}/drawable/st_tv_over.png (100%) rename {res => app/src/main/res}/drawable/st_va_off.png (100%) rename {res => app/src/main/res}/drawable/st_va_on.png (100%) rename {res => app/src/main/res}/drawable/st_va_over.png (100%) rename {res => app/src/main/res}/drawable/stars_0.png (100%) rename {res => app/src/main/res}/drawable/stars_1.png (100%) rename {res => app/src/main/res}/drawable/stars_10.png (100%) rename {res => app/src/main/res}/drawable/stars_2.png (100%) rename {res => app/src/main/res}/drawable/stars_3.png (100%) rename {res => app/src/main/res}/drawable/stars_4.png (100%) rename {res => app/src/main/res}/drawable/stars_5.png (100%) rename {res => app/src/main/res}/drawable/stars_6.png (100%) rename {res => app/src/main/res}/drawable/stars_7.png (100%) rename {res => app/src/main/res}/drawable/stars_8.png (100%) rename {res => app/src/main/res}/drawable/stars_9.png (100%) rename {res => app/src/main/res}/drawable/timeborder.9.png (100%) rename {res => app/src/main/res}/drawable/waiting.png (100%) create mode 100644 app/src/main/res/layout-land-hdpi-v4/remote_xbox.xml create mode 100644 app/src/main/res/layout-land-hdpi-v4/remote_xbox_extended.xml create mode 100644 app/src/main/res/layout-land-ldpi-v4/remote_xbox.xml create mode 100644 app/src/main/res/layout-land/home.xml create mode 100644 app/src/main/res/layout-land/nowplaying.xml create mode 100644 app/src/main/res/layout-land/remote_xbox.xml create mode 100644 app/src/main/res/layout-ldpi-v4/remote_xbox.xml create mode 100644 app/src/main/res/layout-xhdpi/slidingtab_widget.xml create mode 100644 app/src/main/res/layout/about.xml create mode 100644 app/src/main/res/layout/actor_item.xml create mode 100644 app/src/main/res/layout/albumgrid.xml create mode 100644 app/src/main/res/layout/albuminfo.xml create mode 100644 app/src/main/res/layout/albumtracks.xml create mode 100644 app/src/main/res/layout/artistinfo.xml create mode 100644 app/src/main/res/layout/blankgrid.xml create mode 100644 app/src/main/res/layout/blanklist.xml create mode 100644 app/src/main/res/layout/home.xml create mode 100644 app/src/main/res/layout/home_item.xml create mode 100644 app/src/main/res/layout/listmessage.xml create mode 100644 app/src/main/res/layout/loading_message.xml create mode 100644 app/src/main/res/layout/loadinglistentry.xml rename {res => app/src/main/res}/layout/moviedetails.xml (68%) create mode 100644 app/src/main/res/layout/movielibrary.xml create mode 100644 app/src/main/res/layout/musicartist.xml create mode 100644 app/src/main/res/layout/musicgenre.xml create mode 100644 app/src/main/res/layout/musiclibrary.xml create mode 100644 app/src/main/res/layout/nowplaying.xml create mode 100644 app/src/main/res/layout/playlist.xml create mode 100644 app/src/main/res/layout/preference_host.xml create mode 100644 app/src/main/res/layout/remote_gesture.xml create mode 100644 app/src/main/res/layout/remote_gesture_extended.xml create mode 100644 app/src/main/res/layout/remote_xbox.xml create mode 100644 app/src/main/res/layout/remote_xbox_extended.xml create mode 100644 app/src/main/res/layout/sendtext.xml create mode 100644 app/src/main/res/layout/setup_page_1.xml rename {res => app/src/main/res}/layout/setup_page_2.xml (51%) create mode 100644 app/src/main/res/layout/setup_page_3.xml create mode 100644 app/src/main/res/layout/setup_page_login.xml create mode 100644 app/src/main/res/layout/setup_wizard.xml create mode 100644 app/src/main/res/layout/slidingtab_overlay.xml create mode 100644 app/src/main/res/layout/slidingtab_widget.xml create mode 100644 app/src/main/res/layout/titlebar.xml create mode 100644 app/src/main/res/layout/tvdetails.xml rename {res => app/src/main/res}/layout/tvepisodedetails.xml (68%) create mode 100644 app/src/main/res/layout/tvlibrary.xml create mode 100644 app/src/main/res/layout/widget_xbox.xml create mode 100644 app/src/main/res/layout/widget_xbox_small.xml create mode 100644 app/src/main/res/values-v14/dimens.xml rename {res => app/src/main/res}/values/arrays.xml (100%) create mode 100644 app/src/main/res/values/attrs.xml rename {res => app/src/main/res}/values/attrs_manifest.xml (97%) create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/ids.xml rename {res => app/src/main/res}/values/public.xml (54%) rename {res => app/src/main/res}/values/strings.xml (73%) create mode 100644 app/src/main/res/values/styles.xml rename {res => app/src/main/res}/values/themes.xml (71%) create mode 100644 app/src/main/res/xml/app_widget_remote.xml rename {res => app/src/main/res}/xml/preferences.xml (55%) create mode 100644 build.gradle delete mode 100755 build.xml create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat delete mode 100644 lib-src/org/codehaus/jackson/Base64Variant.java delete mode 100644 lib-src/org/codehaus/jackson/Base64Variants.java delete mode 100644 lib-src/org/codehaus/jackson/JsonEncoding.java delete mode 100644 lib-src/org/codehaus/jackson/JsonFactory.java delete mode 100644 lib-src/org/codehaus/jackson/JsonGenerationException.java delete mode 100644 lib-src/org/codehaus/jackson/JsonGenerator.java delete mode 100644 lib-src/org/codehaus/jackson/JsonLocation.java delete mode 100644 lib-src/org/codehaus/jackson/JsonNode.java delete mode 100644 lib-src/org/codehaus/jackson/JsonParseException.java delete mode 100644 lib-src/org/codehaus/jackson/JsonParser.java delete mode 100644 lib-src/org/codehaus/jackson/JsonProcessingException.java delete mode 100644 lib-src/org/codehaus/jackson/JsonStreamContext.java delete mode 100644 lib-src/org/codehaus/jackson/JsonToken.java delete mode 100644 lib-src/org/codehaus/jackson/ObjectCodec.java delete mode 100644 lib-src/org/codehaus/jackson/PrettyPrinter.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JacksonAnnotation.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonAnySetter.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonAutoDetect.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonClass.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonContentClass.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonCreator.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonGetter.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonIgnore.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonIgnoreProperties.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonKeyClass.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonMethod.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonProperty.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonPropertyOrder.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonSetter.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonSubTypes.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonTypeInfo.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonTypeName.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonValue.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/JsonWriteNullProperties.java delete mode 100644 lib-src/org/codehaus/jackson/annotate/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/impl/ByteSourceBootstrapper.java delete mode 100644 lib-src/org/codehaus/jackson/impl/DefaultPrettyPrinter.java delete mode 100644 lib-src/org/codehaus/jackson/impl/Indenter.java delete mode 100644 lib-src/org/codehaus/jackson/impl/JsonGeneratorBase.java delete mode 100644 lib-src/org/codehaus/jackson/impl/JsonNumericParserBase.java delete mode 100644 lib-src/org/codehaus/jackson/impl/JsonParserBase.java delete mode 100644 lib-src/org/codehaus/jackson/impl/JsonReadContext.java delete mode 100644 lib-src/org/codehaus/jackson/impl/JsonWriteContext.java delete mode 100644 lib-src/org/codehaus/jackson/impl/ReaderBasedNumericParser.java delete mode 100644 lib-src/org/codehaus/jackson/impl/ReaderBasedParser.java delete mode 100644 lib-src/org/codehaus/jackson/impl/ReaderBasedParserBase.java delete mode 100644 lib-src/org/codehaus/jackson/impl/StreamBasedParserBase.java delete mode 100644 lib-src/org/codehaus/jackson/impl/Utf8NumericParser.java delete mode 100644 lib-src/org/codehaus/jackson/impl/Utf8StreamParser.java delete mode 100644 lib-src/org/codehaus/jackson/impl/WriterBasedGenerator.java delete mode 100644 lib-src/org/codehaus/jackson/impl/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/io/BaseReader.java delete mode 100644 lib-src/org/codehaus/jackson/io/IOContext.java delete mode 100644 lib-src/org/codehaus/jackson/io/MergedStream.java delete mode 100644 lib-src/org/codehaus/jackson/io/NumberInput.java delete mode 100644 lib-src/org/codehaus/jackson/io/NumberOutput.java delete mode 100644 lib-src/org/codehaus/jackson/io/SegmentedStringWriter.java delete mode 100644 lib-src/org/codehaus/jackson/io/UTF32Reader.java delete mode 100644 lib-src/org/codehaus/jackson/io/UTF8Writer.java delete mode 100644 lib-src/org/codehaus/jackson/io/package.html delete mode 100644 lib-src/org/codehaus/jackson/map/AnnotationIntrospector.java delete mode 100644 lib-src/org/codehaus/jackson/map/BeanDescription.java delete mode 100644 lib-src/org/codehaus/jackson/map/ClassIntrospector.java delete mode 100644 lib-src/org/codehaus/jackson/map/DeserializationConfig.java delete mode 100644 lib-src/org/codehaus/jackson/map/DeserializationContext.java delete mode 100644 lib-src/org/codehaus/jackson/map/DeserializationProblemHandler.java delete mode 100644 lib-src/org/codehaus/jackson/map/DeserializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/DeserializerProvider.java delete mode 100644 lib-src/org/codehaus/jackson/map/JsonDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/JsonMappingException.java delete mode 100644 lib-src/org/codehaus/jackson/map/JsonSerializable.java delete mode 100644 lib-src/org/codehaus/jackson/map/JsonSerializableWithType.java delete mode 100644 lib-src/org/codehaus/jackson/map/JsonSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/KeyDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/MapperConfig.java delete mode 100644 lib-src/org/codehaus/jackson/map/MappingJsonFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/ObjectMapper.java delete mode 100644 lib-src/org/codehaus/jackson/map/ObjectWriter.java delete mode 100644 lib-src/org/codehaus/jackson/map/ResolvableDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ResolvableSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/RuntimeJsonMappingException.java delete mode 100644 lib-src/org/codehaus/jackson/map/SerializationConfig.java delete mode 100644 lib-src/org/codehaus/jackson/map/SerializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/SerializerProvider.java delete mode 100644 lib-src/org/codehaus/jackson/map/TreeMapper.java delete mode 100644 lib-src/org/codehaus/jackson/map/TypeDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/TypeSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonCachable.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonDeserialize.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonSerialize.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonTypeIdResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonTypeResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/JsonView.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/NoClass.java delete mode 100644 lib-src/org/codehaus/jackson/map/annotate/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/ArrayDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/ArrayDeserializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/BasicDeserializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/BeanDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/BeanDeserializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/CollectionDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/Creator.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/CreatorContainer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/CustomDeserializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/DateDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/EnumDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/EnumMapDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/EnumResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/EnumSetDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/FromStringDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/JsonNodeDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/MapDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/PropertyValue.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/PropertyValueBuffer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/SettableAnyProperty.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/SettableBeanProperty.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdDeserializationContext.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdDeserializerProvider.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdDeserializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdKeyDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdKeyDeserializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/StdScalarDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/ThrowableDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/UntypedObjectDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/deser/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/Annotated.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedClass.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedConstructor.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedField.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedMember.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedMethod.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedMethodMap.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedParameter.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotatedWithParams.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/AnnotationMap.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/BasicBeanDescription.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/BasicClassIntrospector.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/JacksonAnnotationIntrospector.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/MemberKey.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/MethodFilter.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/NopAnnotationIntrospector.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/VisibilityChecker.java delete mode 100644 lib-src/org/codehaus/jackson/map/introspect/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/NamedType.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/TypeIdResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/TypeResolverBuilder.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsArrayTypeDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsArrayTypeSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsPropertyTypeSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeDeserializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/AsWrapperTypeSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/ClassNameIdResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/MinimalClassNameIdResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/StdTypeResolverBuilder.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/TypeDeserializerBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/TypeIdResolverBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/TypeNameIdResolver.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/TypeSerializerBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/impl/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/jsontype/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ArraySerializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/BasicSerializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/BeanPropertyWriter.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/BeanSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/BeanSerializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ContainerSerializerBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ContainerSerializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/CustomSerializerFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/EnumMapSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/EnumSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/FailingSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/FilteredBeanPropertyWriter.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/JdkSerializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/JsonValueSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/MapSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/NullSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/PropertyBuilder.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ReadOnlyClassToSerializerMap.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ScalarSerializerBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/SerializerBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/SerializerCache.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/StdKeySerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/StdSerializerProvider.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/StdSerializers.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/ToStringSerializer.java delete mode 100644 lib-src/org/codehaus/jackson/map/ser/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/ArrayType.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/ClassKey.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/CollectionType.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/MapType.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/SimpleType.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/TypeBase.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/TypeBindings.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/TypeFactory.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/TypeParser.java delete mode 100644 lib-src/org/codehaus/jackson/map/type/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/ArrayBuilders.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/ClassUtil.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/EnumValues.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/JSONPObject.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/JSONWrappedObject.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/LinkedNode.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/ObjectBuffer.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/PrimitiveArrayBuilder.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/Provider.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/StdDateFormat.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/SubTypeHelper.java delete mode 100644 lib-src/org/codehaus/jackson/map/util/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/node/ArrayNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/BaseJsonNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/BigIntegerNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/BinaryNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/BooleanNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/ContainerNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/DecimalNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/DoubleNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/IntNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/JsonNodeFactory.java delete mode 100644 lib-src/org/codehaus/jackson/node/LongNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/MissingNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/NodeCursor.java delete mode 100644 lib-src/org/codehaus/jackson/node/NullNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/NumericNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/ObjectNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/POJONode.java delete mode 100644 lib-src/org/codehaus/jackson/node/TextNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/TreeTraversingParser.java delete mode 100644 lib-src/org/codehaus/jackson/node/ValueNode.java delete mode 100644 lib-src/org/codehaus/jackson/node/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/schema/JsonSchema.java delete mode 100644 lib-src/org/codehaus/jackson/schema/JsonSerializableSchema.java delete mode 100644 lib-src/org/codehaus/jackson/schema/SchemaAware.java delete mode 100644 lib-src/org/codehaus/jackson/schema/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/sym/BytesToNameCanonicalizer.java delete mode 100644 lib-src/org/codehaus/jackson/sym/CharsToNameCanonicalizer.java delete mode 100644 lib-src/org/codehaus/jackson/sym/Name.java delete mode 100644 lib-src/org/codehaus/jackson/sym/Name1.java delete mode 100644 lib-src/org/codehaus/jackson/sym/Name2.java delete mode 100644 lib-src/org/codehaus/jackson/sym/Name3.java delete mode 100644 lib-src/org/codehaus/jackson/sym/NameN.java delete mode 100644 lib-src/org/codehaus/jackson/sym/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/type/JavaType.java delete mode 100644 lib-src/org/codehaus/jackson/type/TypeReference.java delete mode 100644 lib-src/org/codehaus/jackson/type/package-info.java delete mode 100644 lib-src/org/codehaus/jackson/util/BufferRecycler.java delete mode 100644 lib-src/org/codehaus/jackson/util/ByteArrayBuilder.java delete mode 100644 lib-src/org/codehaus/jackson/util/CharTypes.java delete mode 100644 lib-src/org/codehaus/jackson/util/InternCache.java delete mode 100644 lib-src/org/codehaus/jackson/util/JsonGeneratorDelegate.java delete mode 100644 lib-src/org/codehaus/jackson/util/JsonParserDelegate.java delete mode 100644 lib-src/org/codehaus/jackson/util/JsonParserSequence.java delete mode 100644 lib-src/org/codehaus/jackson/util/TextBuffer.java delete mode 100644 lib-src/org/codehaus/jackson/util/TokenBuffer.java delete mode 100644 lib-src/org/codehaus/jackson/util/package-info.java delete mode 100644 lib/jmdns.jar delete mode 100644 libs/acra-4.4.0.jar delete mode 100644 libs/jmdns.jar delete mode 100755 project.properties delete mode 100644 res/anim/slide_left.xml delete mode 100644 res/anim/slide_right.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_back.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_display.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_down.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_images.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_info.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_left.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_menu.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_music.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_next.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_pause.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_play.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_previous.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_right.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_seek_back.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_seek_forward.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_select.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_stop.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_title.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_tv.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_up.xml delete mode 100644 res/drawable-hdpi-v4/remote_xbox_video.xml delete mode 100644 res/drawable-land/remote_xbox_back.xml delete mode 100644 res/drawable-land/remote_xbox_display.xml delete mode 100644 res/drawable-land/remote_xbox_down.xml delete mode 100644 res/drawable-land/remote_xbox_images.xml delete mode 100644 res/drawable-land/remote_xbox_info.xml delete mode 100644 res/drawable-land/remote_xbox_left.xml delete mode 100644 res/drawable-land/remote_xbox_menu.xml delete mode 100644 res/drawable-land/remote_xbox_music.xml delete mode 100644 res/drawable-land/remote_xbox_next.xml delete mode 100644 res/drawable-land/remote_xbox_pause.xml delete mode 100644 res/drawable-land/remote_xbox_play.xml delete mode 100644 res/drawable-land/remote_xbox_power.xml delete mode 100644 res/drawable-land/remote_xbox_previous.xml delete mode 100644 res/drawable-land/remote_xbox_right.xml delete mode 100644 res/drawable-land/remote_xbox_seek_back.xml delete mode 100644 res/drawable-land/remote_xbox_seek_forward.xml delete mode 100644 res/drawable-land/remote_xbox_select.xml delete mode 100644 res/drawable-land/remote_xbox_stop.xml delete mode 100644 res/drawable-land/remote_xbox_title.xml delete mode 100644 res/drawable-land/remote_xbox_tv.xml delete mode 100644 res/drawable-land/remote_xbox_up.xml delete mode 100644 res/drawable-land/remote_xbox_video.xml delete mode 100644 res/drawable/bottom_logo.xml delete mode 100644 res/drawable/bottom_text.xml delete mode 100644 res/drawable/bubble_del.xml delete mode 100644 res/drawable/listitem_bg.xml delete mode 100644 res/drawable/listitem_subtitle.xml delete mode 100644 res/drawable/listitem_title.xml delete mode 100644 res/drawable/now_playing_next.xml delete mode 100644 res/drawable/now_playing_pause.xml delete mode 100644 res/drawable/now_playing_play.xml delete mode 100644 res/drawable/now_playing_playlist.xml delete mode 100644 res/drawable/now_playing_previous.xml delete mode 100644 res/drawable/now_playing_stop.xml delete mode 100644 res/drawable/remote_xbox_back.xml delete mode 100644 res/drawable/remote_xbox_display.xml delete mode 100644 res/drawable/remote_xbox_down.xml delete mode 100644 res/drawable/remote_xbox_info.xml delete mode 100644 res/drawable/remote_xbox_left.xml delete mode 100644 res/drawable/remote_xbox_menu.xml delete mode 100644 res/drawable/remote_xbox_next.xml delete mode 100644 res/drawable/remote_xbox_pause.xml delete mode 100644 res/drawable/remote_xbox_play.xml delete mode 100644 res/drawable/remote_xbox_previous.xml delete mode 100644 res/drawable/remote_xbox_right.xml delete mode 100644 res/drawable/remote_xbox_seek_back.xml delete mode 100644 res/drawable/remote_xbox_seek_forward.xml delete mode 100644 res/drawable/remote_xbox_select.xml delete mode 100644 res/drawable/remote_xbox_stop.xml delete mode 100644 res/drawable/remote_xbox_title.xml delete mode 100644 res/drawable/remote_xbox_up.xml delete mode 100644 res/drawable/remote_xbox_widget_back.xml delete mode 100644 res/drawable/remote_xbox_widget_display.xml delete mode 100644 res/drawable/remote_xbox_widget_down.xml delete mode 100644 res/drawable/remote_xbox_widget_info.xml delete mode 100644 res/drawable/remote_xbox_widget_left.xml delete mode 100644 res/drawable/remote_xbox_widget_menu.xml delete mode 100644 res/drawable/remote_xbox_widget_next.xml delete mode 100644 res/drawable/remote_xbox_widget_pause.xml delete mode 100644 res/drawable/remote_xbox_widget_play.xml delete mode 100644 res/drawable/remote_xbox_widget_previous.xml delete mode 100644 res/drawable/remote_xbox_widget_right.xml delete mode 100644 res/drawable/remote_xbox_widget_seek_back.xml delete mode 100644 res/drawable/remote_xbox_widget_seek_forward.xml delete mode 100644 res/drawable/remote_xbox_widget_select.xml delete mode 100644 res/drawable/remote_xbox_widget_stop.xml delete mode 100644 res/drawable/remote_xbox_widget_title.xml delete mode 100644 res/drawable/remote_xbox_widget_up.xml delete mode 100644 res/layout-land-hdpi-v4/remote_xbox.xml delete mode 100644 res/layout-land-hdpi-v4/remote_xbox_extended.xml delete mode 100644 res/layout-land-ldpi-v4/remote_xbox.xml delete mode 100644 res/layout-land/home.xml delete mode 100644 res/layout-land/nowplaying.xml delete mode 100644 res/layout-land/remote_xbox.xml delete mode 100644 res/layout-ldpi-v4/remote_xbox.xml delete mode 100644 res/layout-xhdpi/slidingtab_widget.xml delete mode 100644 res/layout/about.xml delete mode 100644 res/layout/actor_item.xml delete mode 100644 res/layout/albumgrid.xml delete mode 100644 res/layout/albuminfo.xml delete mode 100644 res/layout/albumtracks.xml delete mode 100644 res/layout/artistinfo.xml delete mode 100644 res/layout/blankgrid.xml delete mode 100644 res/layout/blanklist.xml delete mode 100644 res/layout/home.xml delete mode 100644 res/layout/home_item.xml delete mode 100644 res/layout/listmessage.xml delete mode 100644 res/layout/loading_message.xml delete mode 100644 res/layout/loadinglistentry.xml delete mode 100644 res/layout/movielibrary.xml delete mode 100644 res/layout/musicartist.xml delete mode 100644 res/layout/musicgenre.xml delete mode 100644 res/layout/musiclibrary.xml delete mode 100644 res/layout/nowplaying.xml delete mode 100644 res/layout/playlist.xml delete mode 100644 res/layout/preference_host.xml delete mode 100644 res/layout/remote_gesture.xml delete mode 100644 res/layout/remote_gesture_extended.xml delete mode 100644 res/layout/remote_xbox.xml delete mode 100644 res/layout/remote_xbox_extended.xml delete mode 100644 res/layout/sendtext.xml delete mode 100644 res/layout/setup_page_1.xml delete mode 100644 res/layout/setup_page_3.xml delete mode 100644 res/layout/setup_page_login.xml delete mode 100644 res/layout/setup_wizard.xml delete mode 100644 res/layout/slidingtab_overlay.xml delete mode 100644 res/layout/slidingtab_widget.xml delete mode 100644 res/layout/titlebar.xml delete mode 100644 res/layout/tvdetails.xml delete mode 100644 res/layout/tvlibrary.xml delete mode 100644 res/layout/widget_xbox.xml delete mode 100644 res/layout/widget_xbox_small.xml delete mode 100644 res/values-v14/dimens.xml delete mode 100644 res/values/attrs.xml delete mode 100644 res/values/colors.xml delete mode 100644 res/values/dimens.xml delete mode 100644 res/values/ids.xml delete mode 100644 res/values/styles.xml delete mode 100644 res/xml/app_widget_remote.xml create mode 100644 settings.gradle delete mode 100644 src/org/xbmc/android/remote/presentation/drawable/CrossFadeDrawable.java delete mode 100644 src/org/xbmc/android/remote/presentation/notification/BigPictureNotificationBuilder.java delete mode 100644 src/org/xbmc/android/remote/presentation/notification/LargeIconNotificationBuilder.java delete mode 100644 src/org/xbmc/android/remote/presentation/notification/NotificationBuilder.java delete mode 100644 src/org/xbmc/android/remote/presentation/notification/NowPlayingNotificationManager.java delete mode 100644 src/org/xbmc/android/util/Base64.java delete mode 100644 src/org/xbmc/android/util/IOUtilities.java delete mode 100644 src/org/xbmc/android/util/KeyTracker.java delete mode 100644 src/org/xbmc/android/util/OnLongPressBackKeyTracker.java delete mode 100644 src/org/xbmc/android/util/WakeOnLan.java delete mode 100644 src/org/xbmc/api/business/IEventClientManager.java delete mode 100644 src/org/xbmc/api/info/GuiActions.java delete mode 100644 src/org/xbmc/api/info/MusicInfo.java delete mode 100644 src/org/xbmc/api/info/SystemInfo.java delete mode 100644 src/org/xbmc/api/info/VideoInfo.java delete mode 100644 src/org/xbmc/eventclient/PacketBUTTON.java diff --git a/.classpath b/.classpath deleted file mode 100644 index 5777aed3..00000000 --- a/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.gitignore b/.gitignore index d84c1295..1e0a7fcd 100755 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ -/gen -/bin -*.apk -local.properties +.gradle +/local.properties +/.idea/workspace.xml +.DS_Store +/build \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..8a17bd55 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +android-xbmcremote \ No newline at end of file diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 00000000..5cb93b26 --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,202 @@ + + + + + + + diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..217af471 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..e7bedf33 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..736c7b5c --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/.idea/libraries/acra_4_4_0.xml b/.idea/libraries/acra_4_4_0.xml new file mode 100644 index 00000000..3e67ac57 --- /dev/null +++ b/.idea/libraries/acra_4_4_0.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/jackson_core_lgpl_1_9_13.xml b/.idea/libraries/jackson_core_lgpl_1_9_13.xml new file mode 100644 index 00000000..39985262 --- /dev/null +++ b/.idea/libraries/jackson_core_lgpl_1_9_13.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/jackson_mapper_lgpl_1_9_13.xml b/.idea/libraries/jackson_mapper_lgpl_1_9_13.xml new file mode 100644 index 00000000..8da6e791 --- /dev/null +++ b/.idea/libraries/jackson_mapper_lgpl_1_9_13.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/jmdns_3_4_1.xml b/.idea/libraries/jmdns_3_4_1.xml new file mode 100644 index 00000000..c24aae9e --- /dev/null +++ b/.idea/libraries/jmdns_3_4_1.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..2d2cdecb --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..01e94f1d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..275077f8 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.project b/.project deleted file mode 100644 index 585c36d0..00000000 --- a/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - XBMC Remote - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index a2baabdb..00000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -#Fri Aug 07 00:12:07 CEST 2009 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.source=1.5 diff --git a/AndroidManifest.xml b/AndroidManifest.xml deleted file mode 100644 index fe7d7828..00000000 --- a/AndroidManifest.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android-xbmcremote.iml b/android-xbmcremote.iml new file mode 100644 index 00000000..0bb6048a --- /dev/null +++ b/android-xbmcremote.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/ant.properties b/ant.properties deleted file mode 100644 index e8ad521b..00000000 --- a/ant.properties +++ /dev/null @@ -1 +0,0 @@ -source.dir=src; lib-src \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..42afabfd --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 00000000..f60116a4 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..c13834a4 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 20 + buildToolsVersion '20.0.0' + + defaultConfig { + applicationId "org.xbmc.android.remote" + minSdkVersion 8 + targetSdkVersion 20 + versionCode 1009 + versionName "1.0.9" + } + buildTypes { + release { + runProguard false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + packagingOptions { + exclude 'META-INF/LGPL2.1' + exclude 'META-INF/LICENSE' + exclude 'META-INF/NOTICE' + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'org.codehaus.jackson:jackson-mapper-lgpl:1.9.13' + compile 'ch.acra:acra:4.4.0' + compile 'javax.jmdns:jmdns:3.4.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 00000000..0e133975 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /opt/android-studio/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..728ff376 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/org/xbmc/android/remote/business/AbstractManager.java b/app/src/main/java/org/xbmc/android/remote/business/AbstractManager.java similarity index 84% rename from src/org/xbmc/android/remote/business/AbstractManager.java rename to app/src/main/java/org/xbmc/android/remote/business/AbstractManager.java index a73c8259..44c1f5d7 100644 --- a/src/org/xbmc/android/remote/business/AbstractManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/AbstractManager.java @@ -1,385 +1,406 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.util.ArrayList; -import java.util.List; - -import org.xbmc.android.util.ClientFactory; -import org.xbmc.android.util.Crc32; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IInfoClient; -import org.xbmc.api.data.IMusicClient; -import org.xbmc.api.data.ITvShowClient; -import org.xbmc.api.data.IVideoClient; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.CacheType; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.httpapi.WifiStateException; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.os.Handler; -import android.util.Log; - -/** - * Super class of the wrappers, keeps common code. - * - * @author Team XBMC - */ -public abstract class AbstractManager implements INotifiableManager { - - public static final Boolean DEBUG = false; - - protected static final String TAG = "AbstractManager"; - - public static final String PREF_SORT_BY_PREFIX = "sort_by_"; - public static final String PREF_SORT_ORDER_PREFIX = "sort_order_"; - - /* The idea of the sort keys is to remember different sort settings for - * each type. In your controller, make sure you run setSortKey() in the - * onCreate() method. - */ - public static final int PREF_SORT_KEY_ALBUM = 1; - public static final int PREF_SORT_KEY_ARTIST = 2; - public static final int PREF_SORT_KEY_SONG = 3; - public static final int PREF_SORT_KEY_GENRE = 4; - public static final int PREF_SORT_KEY_FILEMODE = 5; - public static final int PREF_SORT_KEY_SHOW = 6; - public static final int PREF_SORT_KEY_MOVIE = 7; - public static final int PREF_SORT_KEY_EPISODE = 8; - - protected INotifiableController mController = null; - - protected Handler mHandler; - - protected SharedPreferences mPref; - protected int mCurrentSortKey; - - protected List failedRequests = new ArrayList(); - /** - * Sets the handler used in the looping thread - * @param handler - */ - public void setHandler(Handler handler) { - mHandler = handler; - } - - public void setController(INotifiableController controller) { - mController = controller; - } - - public void postActivity() { - AbstractThread.quitThreads(); - } - - /** - * Returns the InfoClient class - * @param response Response object - * @return - * @throws WifiStateException - */ - protected IInfoClient info(Context context) throws WifiStateException { - return ClientFactory.getInfoClient(this, context); - } - - /** - * Returns the ControlClient class - * @param response Response object - * @return - * @throws WifiStateException - */ - protected IControlClient control(Context context) throws WifiStateException { - return ClientFactory.getControlClient(this, context); - } - - /** - * Returns the VideoClient class - * @param response Response object - * @return - * @throws WifiStateException - */ - protected IVideoClient video(Context context) throws WifiStateException { - return ClientFactory.getVideoClient(this, context); - } - - /** - * Returns the MusicClient class - * @param response Response object - * @return - * @throws WifiStateException - */ - protected IMusicClient music(Context context) throws WifiStateException { - return ClientFactory.getMusicClient(this, context); - } - - protected ITvShowClient shows(Context context) throws WifiStateException { - return ClientFactory.getTvShowClient(this, context); - } - - /** - * Calls the UI thread's callback code. - * @param response Response object - */ - public void onFinish(DataResponse response) { - if (mController != null) { - //Log.i(TAG, "*** posting onFinish through controller"); - mController.runOnUI(response); - }else{ - Log.w(TAG, "*** ignoring onFinish, controller is null."); - //mHandler.post(response); - } - } - public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize){ - if(MemCacheThread.isInCache(cover, thumbSize)) - return MemCacheThread.getCover(cover, thumbSize); - else if(DiskCacheThread.isInCache(cover, thumbSize)) - return DiskCacheThread.getCover(cover, thumbSize); - else - return null; - } - - public boolean coverLoaded(final ICoverArt cover, final int thumbSize){ - return (MemCacheThread.isInCache(cover, thumbSize) || DiskCacheThread.isInCache(cover, thumbSize)); - } - - /** - * Returns bitmap of any cover. Note that the callback is done by the - * helper methods below. - * @param response Response object - */ - public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, final Bitmap defaultCover, final Context context, final boolean getFromCacheOnly) { - mHandler.post(new Runnable() { - public void run() { - if (cover.getCrc() != 0L) { - // first, try mem cache (only if size = small, other sizes aren't mem-cached. - if (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Trying memory (" + Crc32.formatAsHexLowerCase(cover.getCrc()) + ")"); - getCoverFromMem(response, cover, thumbSize, defaultCover, context, getFromCacheOnly); - } else { - if (getFromCacheOnly) { - Log.e(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] ERROR: NOT downloading big covers is a bad idea because they are not cached!"); - response.value = null; - onFinish(response); - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Downloading directly"); - getCoverFromNetwork(response, cover, thumbSize, context); - } - } - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] no crc, skipping."); - response.value = null; - onFinish(response); - } - } - }); - } - - /** - * Synchronously downloads a cover and stores on on disk cache. - * @param cover Cover to cache - * @param manager Reference to manager - * @param context Reference to context - * @return True if cover has been downloaded, false otherwise. - */ - public static boolean cacheCover(final ICoverArt cover, final INotifiableManager manager, final Context context) { - if (!DiskCacheThread.isInCache(cover, ThumbSize.MEDIUM)) { - return DownloadThread.download(null, cover, ThumbSize.MEDIUM, null, manager, context, false); - } - return false; - } - - /** - * Tries to get small cover from memory, then from disk, then download it from XBMC. - * @param response Response object - * @param cover Get cover for this object - */ - protected void getCoverFromMem(final DataResponse response, final ICoverArt cover, final int thumbSize, Bitmap defaultCover, final Context context, final boolean getFromCacheOnly) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking in mem cache.."); - MemCacheThread.get().getCover(new DataResponse() { - public void run() { - if (value == null) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] empty"); - // then, try sdcard cache - getCoverFromDisk(response, cover, thumbSize, context, getFromCacheOnly); - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] FOUND in memory!"); - response.value = value; - response.cacheType = CacheType.MEMORY; - onFinish(response); - } - } - }, cover, thumbSize, mController, defaultCover); - } - - /** - * Tries to get cover from disk, then download it from XBMC. - * @param response Response object - * @param cover Get cover for this object - * @param thumbSize Cover size - */ - protected void getCoverFromDisk(final DataResponse response, final ICoverArt cover, final int thumbSize, final Context context, final boolean getFromCacheOnly) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking in disk cache.."); - DiskCacheThread.get().getCover(new DataResponse() { - public void run() { - if (value == null) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Disk cache empty."); - if (response.postCache()) { - // well, let's download - if (getFromCacheOnly) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Skipping download."); - response.value = null; - onFinish(response); - } else { - getCoverFromNetwork(response, cover, thumbSize, context); - } - } - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] FOUND on disk!"); - response.value = value; - response.cacheType = CacheType.SDCARD; - onFinish(response); - } - } - }, cover, thumbSize, mController); - } - - /** - * Last stop: try to download from XBMC. - * @param response Response object - * @param cover Get cover for this object - * @param thumbSize Cover size - */ - protected void getCoverFromNetwork(final DataResponse response, final ICoverArt cover, final int thumbSize, final Context context) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Downloading.."); - DownloadThread.get().getCover(new DataResponse() { - public void run() { - if (value == null) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Download empty"); - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] DOWNLOADED (" + value.getWidth() + "x" + value.getHeight() + ")!"); - response.cacheType = CacheType.NETWORK; - response.value = value; - } - onFinish(response); // callback in any case, since we don't go further than that. - } - }, cover, thumbSize, mController, this, context); - } - - /** - * Commands failed because of wrong connection state are special. After the connection has the right state we - * could retry the command - */ - public void onWrongConnectionState(int state, Command cmd) { - failedRequests.add(cmd); - if (mController != null) - mController.onWrongConnectionState(state, this, cmd); - } - - public void onError(Exception e) { - if (mController != null) { - mController.onError(e); - } - } - - public void onMessage(String message) { - if (mController != null) { - mController.onMessage(message); - } - } - - public void onMessage(int code, String message) { - onMessage(message); - } - - public void retryAll() { - Log.d(TAG, "Posting retries to the queue"); - mHandler.post(new Runnable() { - public void run() { - Log.d(TAG, "runnable started, posting retries"); - while(failedRequests.size() > 0) { - if(mHandler.post(failedRequests.get(0))) - Log.d(TAG, "Runnable posted"); - else - Log.d(TAG, "Runnable coudln't be posted"); - failedRequests.remove(0); - } - } - }); - } - - /** - * Sets the static reference to the preferences object. Used to obtain - * current sort values. - * @param pref - */ - public void setPreferences(SharedPreferences pref) { - mPref = pref; - } - - /** - * Sets which kind of view is currently active. - * @param sortKey - */ - public void setSortKey(int sortKey) { - mCurrentSortKey = sortKey; - } - - public void post(Runnable runnable) - { - mHandler.post(runnable); - } - - /** - * Returns currently saved "sort by" value. If the preference was not set yet, or - * if the current sort key is not set, return default value. - * @param type Default value - * @return Sort by field - */ - protected int getSortBy(int type) { - if (mPref != null) { - return mPref.getInt(PREF_SORT_BY_PREFIX + mCurrentSortKey, type); - } - return type; - } - - /** - * Returns currently saved "sort by" value. If the preference was not set yet, or - * if the current sort key is not set, return "ASC". - * @return Sort order - */ - protected String getSortOrder() { - if (mPref != null) { - return mPref.getString(PREF_SORT_ORDER_PREFIX + mCurrentSortKey, SortType.ORDER_ASC); - } - return SortType.ORDER_ASC; - } - - protected boolean getHideWatched(Context context) { - return context.getSharedPreferences("global", Context.MODE_PRIVATE).getBoolean("HideWatched", false); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.os.Handler; +import android.util.Log; + +import org.xbmc.android.util.ClientFactory; +import org.xbmc.android.util.Crc32; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IControlClient; +import org.xbmc.api.data.IInfoClient; +import org.xbmc.api.data.IMusicClient; +import org.xbmc.api.data.ITvShowClient; +import org.xbmc.api.data.IVideoClient; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.CacheType; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.httpapi.WifiStateException; + +import java.util.ArrayList; +import java.util.List; + +/** + * Super class of the wrappers, keeps common code. + * + * @author Team XBMC + */ +public abstract class AbstractManager implements INotifiableManager { + + public static final Boolean DEBUG = false; + public static final String PREF_SORT_BY_PREFIX = "sort_by_"; + public static final String PREF_SORT_ORDER_PREFIX = "sort_order_"; + /* The idea of the sort keys is to remember different sort settings for + * each type. In your controller, make sure you run setSortKey() in the + * onCreate() method. + */ + public static final int PREF_SORT_KEY_ALBUM = 1; + public static final int PREF_SORT_KEY_ARTIST = 2; + public static final int PREF_SORT_KEY_SONG = 3; + public static final int PREF_SORT_KEY_GENRE = 4; + public static final int PREF_SORT_KEY_FILEMODE = 5; + public static final int PREF_SORT_KEY_SHOW = 6; + public static final int PREF_SORT_KEY_MOVIE = 7; + public static final int PREF_SORT_KEY_EPISODE = 8; + protected static final String TAG = "AbstractManager"; + protected INotifiableController mController = null; + + protected Handler mHandler; + + protected SharedPreferences mPref; + protected int mCurrentSortKey; + + protected List failedRequests = new ArrayList(); + + /** + * Synchronously downloads a cover and stores on on disk cache. + * + * @param cover Cover to cache + * @param manager Reference to manager + * @param context Reference to context + * @return True if cover has been downloaded, false otherwise. + */ + public static boolean cacheCover(final ICoverArt cover, final INotifiableManager manager, final Context context) { + if (!DiskCacheThread.isInCache(cover, ThumbSize.MEDIUM)) { + return DownloadThread.download(null, cover, ThumbSize.MEDIUM, null, manager, context, false); + } + return false; + } + + /** + * Sets the handler used in the looping thread + * + * @param handler + */ + public void setHandler(Handler handler) { + mHandler = handler; + } + + public void setController(INotifiableController controller) { + mController = controller; + } + + public void postActivity() { + AbstractThread.quitThreads(); + } + + /** + * Returns the InfoClient class + * + * @return + * @throws WifiStateException + */ + protected IInfoClient info(Context context) throws WifiStateException { + return ClientFactory.getInfoClient(this, context); + } + + /** + * Returns the ControlClient class + * + * @return + * @throws WifiStateException + */ + protected IControlClient control(Context context) throws WifiStateException { + return ClientFactory.getControlClient(this, context); + } + + /** + * Returns the VideoClient class + * + * @return + * @throws WifiStateException + */ + protected IVideoClient video(Context context) throws WifiStateException { + return ClientFactory.getVideoClient(this, context); + } + + /** + * Returns the MusicClient class + * + * @return + * @throws WifiStateException + */ + protected IMusicClient music(Context context) throws WifiStateException { + return ClientFactory.getMusicClient(this, context); + } + + protected ITvShowClient shows(Context context) throws WifiStateException { + return ClientFactory.getTvShowClient(this, context); + } + + /** + * Calls the UI thread's callback code. + * + * @param response Response object + */ + public void onFinish(DataResponse response) { + if (mController != null) { + //Log.i(TAG, "*** posting onFinish through controller"); + mController.runOnUI(response); + } else { + Log.w(TAG, "*** ignoring onFinish, controller is null."); + //mHandler.post(response); + } + } + + public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize) { + if (MemCacheThread.isInCache(cover, thumbSize)) + return MemCacheThread.getCover(cover, thumbSize); + else if (DiskCacheThread.isInCache(cover, thumbSize)) + return DiskCacheThread.getCover(cover, thumbSize); + else + return null; + } + + public boolean coverLoaded(final ICoverArt cover, final int thumbSize) { + return (MemCacheThread.isInCache(cover, thumbSize) || DiskCacheThread.isInCache(cover, thumbSize)); + } + + /** + * Returns bitmap of any cover. Note that the callback is done by the + * helper methods below. + * + * @param response Response object + */ + public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, + final Bitmap defaultCover, final Context context, final boolean getFromCacheOnly) { + mHandler.post(new Runnable() { + public void run() { + if (cover.getCrc() != 0L) { + // first, try mem cache (only if size = small, other sizes aren't mem-cached. + if (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) { + if (DEBUG) + Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Trying memory (" + Crc32 + .formatAsHexLowerCase(cover.getCrc()) + ")"); + getCoverFromMem(response, cover, thumbSize, defaultCover, context, getFromCacheOnly); + } else { + if (getFromCacheOnly) { + Log.e(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] ERROR: NOT downloading" + + " " + + "big covers is a bad idea because they are not cached!"); + response.value = null; + onFinish(response); + } else { + if (DEBUG) + Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Downloading " + + "directly"); + getCoverFromNetwork(response, cover, thumbSize, context); + } + } + } else { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] no crc, skipping."); + response.value = null; + onFinish(response); + } + } + }); + } + + /** + * Tries to get small cover from memory, then from disk, then download it from XBMC. + * + * @param response Response object + * @param cover Get cover for this object + */ + protected void getCoverFromMem(final DataResponse response, final ICoverArt cover, final int thumbSize, + Bitmap defaultCover, final Context context, final boolean getFromCacheOnly) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking in mem cache.."); + MemCacheThread.get().getCover(new DataResponse() { + public void run() { + if (value == null) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] empty"); + // then, try sdcard cache + getCoverFromDisk(response, cover, thumbSize, context, getFromCacheOnly); + } else { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] FOUND in memory!"); + response.value = value; + response.cacheType = CacheType.MEMORY; + onFinish(response); + } + } + }, cover, thumbSize, mController, defaultCover); + } + + /** + * Tries to get cover from disk, then download it from XBMC. + * + * @param response Response object + * @param cover Get cover for this object + * @param thumbSize Cover size + */ + protected void getCoverFromDisk(final DataResponse response, final ICoverArt cover, final int thumbSize, + final Context context, final boolean getFromCacheOnly) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking in disk cache.."); + DiskCacheThread.get().getCover(new DataResponse() { + public void run() { + if (value == null) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Disk cache empty."); + if (response.postCache()) { + // well, let's download + if (getFromCacheOnly) { + if (DEBUG) + Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] Skipping download."); + response.value = null; + onFinish(response); + } else { + getCoverFromNetwork(response, cover, thumbSize, context); + } + } + } else { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + ThumbSize.getDir(thumbSize) + "] FOUND on disk!"); + response.value = value; + response.cacheType = CacheType.SDCARD; + onFinish(response); + } + } + }, cover, thumbSize, mController); + } + + /** + * Last stop: try to download from XBMC. + * + * @param response Response object + * @param cover Get cover for this object + * @param thumbSize Cover size + */ + protected void getCoverFromNetwork(final DataResponse response, final ICoverArt cover, + final int thumbSize, final Context context) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Downloading.."); + DownloadThread.get().getCover(new DataResponse() { + public void run() { + if (value == null) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Download empty"); + } else { + if (DEBUG) + Log.i(TAG, "[" + cover.getId() + "] DOWNLOADED (" + value.getWidth() + "x" + value.getHeight() + + ")!"); + response.cacheType = CacheType.NETWORK; + response.value = value; + } + onFinish(response); // callback in any case, since we don't go further than that. + } + }, cover, thumbSize, mController, this, context); + } + + /** + * Commands failed because of wrong connection state are special. After the connection has the right state we + * could retry the command + */ + public void onWrongConnectionState(int state, Command cmd) { + failedRequests.add(cmd); + if (mController != null) + mController.onWrongConnectionState(state, this, cmd); + } + + public void onError(Exception e) { + if (mController != null) { + mController.onError(e); + } + } + + public void onMessage(String message) { + if (mController != null) { + mController.onMessage(message); + } + } + + public void onMessage(int code, String message) { + onMessage(message); + } + + public void retryAll() { + Log.d(TAG, "Posting retries to the queue"); + mHandler.post(new Runnable() { + public void run() { + Log.d(TAG, "runnable started, posting retries"); + while (failedRequests.size() > 0) { + if (mHandler.post(failedRequests.get(0))) + Log.d(TAG, "Runnable posted"); + else + Log.d(TAG, "Runnable coudln't be posted"); + failedRequests.remove(0); + } + } + }); + } + + /** + * Sets the static reference to the preferences object. Used to obtain + * current sort values. + * + * @param pref + */ + public void setPreferences(SharedPreferences pref) { + mPref = pref; + } + + /** + * Sets which kind of view is currently active. + * + * @param sortKey + */ + public void setSortKey(int sortKey) { + mCurrentSortKey = sortKey; + } + + public void post(Runnable runnable) { + mHandler.post(runnable); + } + + /** + * Returns currently saved "sort by" value. If the preference was not set yet, or + * if the current sort key is not set, return default value. + * + * @param type Default value + * @return Sort by field + */ + protected int getSortBy(int type) { + if (mPref != null) { + return mPref.getInt(PREF_SORT_BY_PREFIX + mCurrentSortKey, type); + } + return type; + } + + /** + * Returns currently saved "sort by" value. If the preference was not set yet, or + * if the current sort key is not set, return "ASC". + * + * @return Sort order + */ + protected String getSortOrder() { + if (mPref != null) { + return mPref.getString(PREF_SORT_ORDER_PREFIX + mCurrentSortKey, SortType.ORDER_ASC); + } + return SortType.ORDER_ASC; + } + + protected boolean getHideWatched(Context context) { + return context.getSharedPreferences("global", Context.MODE_PRIVATE).getBoolean("HideWatched", false); + } +} diff --git a/src/org/xbmc/android/remote/business/AbstractThread.java b/app/src/main/java/org/xbmc/android/remote/business/AbstractThread.java similarity index 89% rename from src/org/xbmc/android/remote/business/AbstractThread.java rename to app/src/main/java/org/xbmc/android/remote/business/AbstractThread.java index 6fcacfa1..a424e401 100644 --- a/src/org/xbmc/android/remote/business/AbstractThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/AbstractThread.java @@ -1,125 +1,132 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IMusicClient; -import org.xbmc.api.data.ITvShowClient; -import org.xbmc.api.data.IVideoClient; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.httpapi.WifiStateException; - -import android.content.Context; -import android.os.Handler; -import android.os.Looper; - -/** - * Super class for all the cache threads. Keeps common code - * in one place. - * - * @author Team XBMC - */ -abstract public class AbstractThread extends Thread { - - protected Handler mHandler; - - /** - * Class constructor is protected, use get() in the child class. - * @param name - */ - protected AbstractThread(String name) { - super(name); - } - - /** - * Creates the handler and then loops. - */ - public void run() { - Looper.prepare(); - mHandler = new Handler(); - Looper.loop(); - } - - /** - * Returns the MusicClient class - * @param manager Manager reference - * @return - * @throws WifiStateException - */ - protected static IMusicClient music(INotifiableManager manager, final Context context) throws WifiStateException { - return ClientFactory.getMusicClient(manager, context); - } - - /** - * Returns the VideoClient class - * @param manager Manager referencet - * @return - * @throws WifiStateException - */ - protected static IVideoClient video(INotifiableManager manager, final Context context) throws WifiStateException { - return ClientFactory.getVideoClient(manager, context); - } - - /** - * Returns the TvShowClient class - * @param manager Manager referencet - * @return - * @throws WifiStateException - */ - protected static ITvShowClient tvshow(INotifiableManager manager, final Context context) throws WifiStateException { - return ClientFactory.getTvShowClient(manager, context); - } - - /** - * Calls the UI thread's callback code. - * @param controller Controller reference - * @param response Response object - */ - protected static void done(INotifiableController controller, DataResponse response) { - if (controller != null && response != null) - controller.runOnUI(response); - } - - /** - * Waits until the thread has completely started and we can be sure - * the response has been initialized. - * @param thread - */ - protected static void waitForStartup(AbstractThread thread) { - while (thread.mHandler == null) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public static void quitThreads() { - MemCacheThread.quit(); - DiskCacheThread.quit(); - DownloadThread.quit(); - } - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IMusicClient; +import org.xbmc.api.data.ITvShowClient; +import org.xbmc.api.data.IVideoClient; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.httpapi.WifiStateException; + +/** + * Super class for all the cache threads. Keeps common code + * in one place. + * + * @author Team XBMC + */ +abstract public class AbstractThread extends Thread { + + protected Handler mHandler; + + /** + * Class constructor is protected, use get() in the child class. + * + * @param name + */ + protected AbstractThread(String name) { + super(name); + } + + /** + * Returns the MusicClient class + * + * @param manager Manager reference + * @return + * @throws WifiStateException + */ + protected static IMusicClient music(INotifiableManager manager, final Context context) throws WifiStateException { + return ClientFactory.getMusicClient(manager, context); + } + + /** + * Returns the VideoClient class + * + * @param manager Manager referencet + * @return + * @throws WifiStateException + */ + protected static IVideoClient video(INotifiableManager manager, final Context context) throws WifiStateException { + return ClientFactory.getVideoClient(manager, context); + } + + /** + * Returns the TvShowClient class + * + * @param manager Manager referencet + * @return + * @throws WifiStateException + */ + protected static ITvShowClient tvshow(INotifiableManager manager, final Context context) throws + WifiStateException { + return ClientFactory.getTvShowClient(manager, context); + } + + /** + * Calls the UI thread's callback code. + * + * @param controller Controller reference + * @param response Response object + */ + protected static void done(INotifiableController controller, DataResponse response) { + if (controller != null && response != null) + controller.runOnUI(response); + } + + /** + * Waits until the thread has completely started and we can be sure + * the response has been initialized. + * + * @param thread + */ + protected static void waitForStartup(AbstractThread thread) { + while (thread.mHandler == null) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public static void quitThreads() { + MemCacheThread.quit(); + DiskCacheThread.quit(); + DownloadThread.quit(); + } + + /** + * Creates the handler and then loops. + */ + public void run() { + Looper.prepare(); + mHandler = new Handler(); + Looper.loop(); + } + } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/CacheManager.java b/app/src/main/java/org/xbmc/android/remote/business/CacheManager.java similarity index 80% rename from src/org/xbmc/android/remote/business/CacheManager.java rename to app/src/main/java/org/xbmc/android/remote/business/CacheManager.java index e939b4fd..5601101d 100644 --- a/src/org/xbmc/android/remote/business/CacheManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/CacheManager.java @@ -1,23 +1,23 @@ -package org.xbmc.android.remote.business; - -import org.xbmc.android.util.ImportUtilities; - -public class CacheManager { - private static CacheManager instance; - - private CacheManager() { - } - - public static CacheManager get() { - if(instance == null) { - instance = new CacheManager(); - } - - return instance; - } - - public void purgeCache() { - ImportUtilities.purgeCache(); - MemCacheThread.purgeCache(); - } -} +package org.xbmc.android.remote.business; + +import org.xbmc.android.util.ImportUtilities; + +public class CacheManager { + private static CacheManager instance; + + private CacheManager() { + } + + public static CacheManager get() { + if (instance == null) { + instance = new CacheManager(); + } + + return instance; + } + + public void purgeCache() { + ImportUtilities.purgeCache(); + MemCacheThread.purgeCache(); + } +} diff --git a/src/org/xbmc/android/remote/business/Command.java b/app/src/main/java/org/xbmc/android/remote/business/Command.java similarity index 91% rename from src/org/xbmc/android/remote/business/Command.java rename to app/src/main/java/org/xbmc/android/remote/business/Command.java index 95360679..f5e44904 100644 --- a/src/org/xbmc/android/remote/business/Command.java +++ b/app/src/main/java/org/xbmc/android/remote/business/Command.java @@ -1,44 +1,43 @@ package org.xbmc.android.remote.business; +import android.util.Log; + import org.xbmc.api.business.DataResponse; import org.xbmc.api.business.INotifiableManager; import org.xbmc.httpapi.WifiStateException; -import android.util.Log; - /** * Class to asynchronous execute backend stuff and send the result back to the GUI. * Holds some extras to check how often this request failed and catch all to not have the backend crashing * and force closing the app. - * @author till * + * @author till */ public abstract class Command implements Runnable { - public int mRetryCount = 0; - public long mStarted = 0; + public static final int MAX_RETRY = 5; public final INotifiableManager mManager; public final DataResponse mResponse; - // TODO Disable this when not needed anymore public final StackTraceElement mCaller; - - public static final int MAX_RETRY = 5; - + public int mRetryCount = 0; + public long mStarted = 0; + public Command(DataResponse response, INotifiableManager manager) { mManager = manager; mResponse = response; mStarted = System.currentTimeMillis(); mCaller = new Throwable().fillInStackTrace().getStackTrace()[2]; } - + public void run() { try { - mRetryCount ++; + mRetryCount++; Log.d("Command", "Running command counter: " + mRetryCount); - if(mRetryCount > MAX_RETRY) return; + if (mRetryCount > MAX_RETRY) return; doRun(); - Log.i(mCaller.getClassName(), "*** " + mCaller.getMethodName() + ": " + (System.currentTimeMillis() - mStarted) + "ms"); + Log.i(mCaller.getClassName(), "*** " + mCaller.getMethodName() + ": " + (System.currentTimeMillis() - + mStarted) + "ms"); mManager.onFinish(mResponse); } catch (WifiStateException e) { @@ -47,7 +46,7 @@ public void run() { mManager.onError(e); } } - + public abstract void doRun() throws Exception; } diff --git a/src/org/xbmc/android/remote/business/ControlManager.java b/app/src/main/java/org/xbmc/android/remote/business/ControlManager.java similarity index 76% rename from src/org/xbmc/android/remote/business/ControlManager.java rename to app/src/main/java/org/xbmc/android/remote/business/ControlManager.java index 7f0f265f..076f6833 100644 --- a/src/org/xbmc/android/remote/business/ControlManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/ControlManager.java @@ -1,305 +1,325 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; -import org.xbmc.api.type.SeekType; - -import android.content.Context; - -/** - * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. - * - * @author Team XBMC - */ -public class ControlManager extends AbstractManager implements IControlManager, INotifiableManager { - - /** - * Starts playing the media file filename . - * @param response Response object - * @param filename File to play - */ - public void playFile(final DataResponse response, final String filename, final int playlistType, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).playFile(ControlManager.this, filename, playlistType); - } - }); - } - - /** - * Starts playing a whole folder - * @param response Response object - * @param foldername Path to the folder to play - * @param context Context reference - */ - public void playFolder(final DataResponse response, final String foldername, final int playlistType, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - IControlClient cc = control(context); - cc.stop(ControlManager.this); - cc.clearPlaylist(ControlManager.this, playlistType); - cc.addToPlaylist(ControlManager.this, foldername, playlistType); - cc.setCurrentPlaylist(ControlManager.this, playlistType); - response.value = cc.playNext(ControlManager.this); - } - }); - } - - /** - * Queues a whole folder - * @param response Response object - * @param foldername Path to the folder to play - * @param context Context reference - */ - public void queueFolder(final DataResponse response, final String foldername, final int playlistType, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - IControlClient cc = control(context); - final boolean ret = cc.addToPlaylist(ControlManager.this, foldername, playlistType); - if (!cc.getCurrentlyPlaying(ControlManager.this).isPlaying()) { - cc.setCurrentPlaylist(ControlManager.this, playlistType); - response.value = cc.playNext(ControlManager.this); - } else { - response.value = ret; - } - } - }); - } - - /** - * Start playing the media file at the given URL - * @param response Response object - * @param url An URL pointing to a supported media file - * @return true on success, false otherwise. - */ - public void playUrl(final DataResponse response, final String url, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).playUrl(ControlManager.this, url); - } - - }); - } - - /** - * Plays the next item in the playlist. - * @param response Response object - * @return true on success, false otherwise. - */ - public void playNext(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).playNext(ControlManager.this); - } - }); - } - - /** - * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. - * @param response Response object - * @param fileOrFolder File to play - */ - public void addToPlaylist(final DataResponse response, final String fileOrFolder, final int playlistType, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).addToPlaylist(ControlManager.this, fileOrFolder, playlistType); - } - }); - } - - /** - * Send the string text via keys on the virtual keyboard. - * @param response Response object - * @param text The text string to send. - * @return true on success, false otherwise. - */ - public void sendText(final DataResponse response, final String text, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).sendText(ControlManager.this, text); - } - }); - } - - /** - * Seeks to a position. If type is - *
    - *
  • absolute - Sets the playing position of the currently - * playing media as a percentage of the media's length.
  • - *
  • relative - Adds/Subtracts the current percentage on to - * the current position in the song
  • - *
- * - * @param response Response object - * @param type Seek type, relative or absolute - * @param progress Progress - * @return true on success, false otherwise. - */ - public void seek(final DataResponse response, final SeekType type, final int progress, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).seek(ControlManager.this, type, progress); - } - }); - } - - /** - * Takes either "video" or "music" as a parameter to begin updating the - * corresponding database. - * - * @param response Response object - * @param mediaType - */ - public void updateLibrary(final DataResponse response, final String mediaType, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).updateLibrary(ControlManager.this, mediaType); - } - }); - } - - /** - * Displays the image filename . - * @param response Response object - * @param filename File to show - */ - public void showPicture(final DataResponse response, final String filename, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).showPicture(ControlManager.this, filename); - } - }); - } - - - /** - * Returns what's currently playing. - * @param response - */ - public void getCurrentlyPlaying(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).getCurrentlyPlaying(ControlManager.this); - } - }); - } - - - /** - * Returns the current playlist identifier - * @param response Response object - */ - public void getPlaylistId(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).getPlaylistId(ControlManager.this); - } - }); - } - - - /** - * Sets the current playlist identifier - * @param response Response object - * @param id Playlist identifier - */ - public void setPlaylistId(final DataResponse response, final int id, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).setPlaylistId(ControlManager.this, id); - } - }); - } - - /** - * Sets the current playlist position - * @param response Response object - * @param position New playlist position - */ - public void setPlaylistPos(final DataResponse response, final int playlistId, final int position, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).setPlaylistPos(ControlManager.this, playlistId, position); - } - }); - } - - /** - * Clears playlist - * @param response Response object - * @param playlistId Playlist ID (0 = music, 1 = video) - * @param context Context reference - */ - public void clearPlaylist(final DataResponse response, final int playlistId, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = control(context).clearPlaylist(ControlManager.this, playlistId); - } - }); - } - - /** - * Sets the gui setting of XBMC to value - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings - * @param value the value to set - */ - public void setGuiSetting(final DataResponse response, final int setting, - final String value, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = control(context).setGuiSetting(ControlManager.this, setting, value); - } - }); - - } - - public void getVolume(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = control(context).getVolume(ControlManager.this); - } - }); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IControlClient; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.type.SeekType; + +/** + * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. + * + * @author Team XBMC + */ +public class ControlManager extends AbstractManager implements IControlManager, INotifiableManager { + + /** + * Starts playing the media file filename . + * + * @param response Response object + * @param filename File to play + */ + public void playFile(final DataResponse response, final String filename, final int playlistType, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).playFile(ControlManager.this, filename, playlistType); + } + }); + } + + /** + * Starts playing a whole folder + * + * @param response Response object + * @param foldername Path to the folder to play + * @param context Context reference + */ + public void playFolder(final DataResponse response, final String foldername, final int playlistType, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + IControlClient cc = control(context); + cc.stop(ControlManager.this); + cc.clearPlaylist(ControlManager.this, playlistType); + cc.addToPlaylist(ControlManager.this, foldername, playlistType); + cc.setCurrentPlaylist(ControlManager.this, playlistType); + response.value = cc.playNext(ControlManager.this); + } + }); + } + + /** + * Queues a whole folder + * + * @param response Response object + * @param foldername Path to the folder to play + * @param context Context reference + */ + public void queueFolder(final DataResponse response, final String foldername, final int playlistType, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + IControlClient cc = control(context); + final boolean ret = cc.addToPlaylist(ControlManager.this, foldername, playlistType); + if (!cc.getCurrentlyPlaying(ControlManager.this).isPlaying()) { + cc.setCurrentPlaylist(ControlManager.this, playlistType); + response.value = cc.playNext(ControlManager.this); + } else { + response.value = ret; + } + } + }); + } + + /** + * Start playing the media file at the given URL + * + * @param response Response object + * @param url An URL pointing to a supported media file + * @return true on success, false otherwise. + */ + public void playUrl(final DataResponse response, final String url, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).playUrl(ControlManager.this, url); + } + + }); + } + + /** + * Plays the next item in the playlist. + * + * @param response Response object + * @return true on success, false otherwise. + */ + public void playNext(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).playNext(ControlManager.this); + } + }); + } + + /** + * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. + * + * @param response Response object + * @param fileOrFolder File to play + */ + public void addToPlaylist(final DataResponse response, final String fileOrFolder, final int playlistType, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).addToPlaylist(ControlManager.this, fileOrFolder, playlistType); + } + }); + } + + /** + * Send the string text via keys on the virtual keyboard. + * + * @param response Response object + * @param text The text string to send. + * @return true on success, false otherwise. + */ + public void sendText(final DataResponse response, final String text, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).sendText(ControlManager.this, text); + } + }); + } + + /** + * Seeks to a position. If type is + *
    + *
  • absolute - Sets the playing position of the currently + * playing media as a percentage of the media's length.
  • + *
  • relative - Adds/Subtracts the current percentage on to + * the current position in the song
  • + *
+ * + * @param response Response object + * @param type Seek type, relative or absolute + * @param progress Progress + * @return true on success, false otherwise. + */ + public void seek(final DataResponse response, final SeekType type, final int progress, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).seek(ControlManager.this, type, progress); + } + }); + } + + /** + * Takes either "video" or "music" as a parameter to begin updating the + * corresponding database. + * + * @param response Response object + * @param mediaType + */ + public void updateLibrary(final DataResponse response, final String mediaType, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).updateLibrary(ControlManager.this, mediaType); + } + }); + } + + /** + * Displays the image filename . + * + * @param response Response object + * @param filename File to show + */ + public void showPicture(final DataResponse response, final String filename, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).showPicture(ControlManager.this, filename); + } + }); + } + + + /** + * Returns what's currently playing. + * + * @param response + */ + public void getCurrentlyPlaying(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).getCurrentlyPlaying(ControlManager.this); + } + }); + } + + + /** + * Returns the current playlist identifier + * + * @param response Response object + */ + public void getPlaylistId(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).getPlaylistId(ControlManager.this); + } + }); + } + + + /** + * Sets the current playlist identifier + * + * @param response Response object + * @param id Playlist identifier + */ + public void setPlaylistId(final DataResponse response, final int id, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).setPlaylistId(ControlManager.this, id); + } + }); + } + + /** + * Sets the current playlist position + * + * @param response Response object + * @param position New playlist position + */ + public void setPlaylistPos(final DataResponse response, final int playlistId, final int position, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).setPlaylistPos(ControlManager.this, playlistId, position); + } + }); + } + + /** + * Clears playlist + * + * @param response Response object + * @param playlistId Playlist ID (0 = music, 1 = video) + * @param context Context reference + */ + public void clearPlaylist(final DataResponse response, final int playlistId, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).clearPlaylist(ControlManager.this, playlistId); + } + }); + } + + /** + * Sets the gui setting of XBMC to value + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings + * @param value the value to set + */ + public void setGuiSetting(final DataResponse response, final int setting, + final String value, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).setGuiSetting(ControlManager.this, setting, value); + } + }); + + } + + public void getVolume(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = control(context).getVolume(ControlManager.this); + } + }); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/DiskCacheThread.java b/app/src/main/java/org/xbmc/android/remote/business/DiskCacheThread.java similarity index 72% rename from src/org/xbmc/android/remote/business/DiskCacheThread.java rename to app/src/main/java/org/xbmc/android/remote/business/DiskCacheThread.java index 0e12bfda..9df45ea7 100644 --- a/src/org/xbmc/android/remote/business/DiskCacheThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/DiskCacheThread.java @@ -1,145 +1,153 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.io.File; - -import org.xbmc.android.util.Crc32; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.MediaType; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -/** - * This thread asynchronously delivers sdcard-cached bitmaps. - * - * The sdcard cache keeps thumb bitmaps in three sizes (small, medium, - * original). This thread is directly accessed by the original HttpApi thread, - * through one of its wrappers. - * - * @author Team XBMC - */ -class DiskCacheThread extends AbstractThread { - - /** - * Singleton instance of this thread - */ - protected static DiskCacheThread sHttpApiThread; - - /** - * Constructor is protected, use get(). - */ - protected DiskCacheThread() { - super("HTTP API Disk Cache Thread"); - } - - /** - * Asynchronously returns a thumb from the disk cache, or null if - * not available. Accessed covers get automatically added to the - * memory cache. - * - * @param response Response object - * @param cover Which cover to return - * @param thumbSize Which size to return - */ - public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, final INotifiableController controller) { - mHandler.post(new Runnable() { - public void run() { - if (cover != null) { - final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), thumbSize, Crc32.formatAsHexLowerCase(cover.getCrc())); - if (file.exists()) { - final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); - if (bitmap == null) { // file is available but obviously corruped, so delete it. - file.delete(); - response.value = null; - } else { - MemCacheThread.addCoverToCache(cover, bitmap, thumbSize); - response.value = bitmap; - } - } - } - done(controller, response); - } - }); - } - - /** - * Synchronously returns a thumb from the disk cache, or null if not - * available. - * - * @param cover Which cover to return - * @return Bitmap or null if not available. - */ - public static Bitmap getCover(ICoverArt cover, int thumbSize) { - final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), thumbSize, Crc32.formatAsHexLowerCase(cover.getCrc())); - if (file.exists()) { - final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); - MemCacheThread.addCoverToCache(cover, bitmap, thumbSize); - return bitmap; - } else - return null; - } - - /** - * Checks if a thumb is in the disk cache. - * @param cover - * @return True if thumb is in disk cache, false otherwise. - */ - public static boolean isInCache(ICoverArt cover, int thumbSize) { - final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), thumbSize, Crc32.formatAsHexLowerCase(cover.getCrc()).toLowerCase()); - // TODO sometimes the filesize is zero - return file.exists() && file.length() > 0; - } - - /** - * Adds a cover to the disk cache - * @param cover Which cover to add - * @param bitmap Bitmap data, original size. - */ - public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int size) { - return ImportUtilities.addCoverToCache(cover, bitmap, size); - } - - /** - * Returns an instance of this thread. Spawns if necessary. - * @return - */ - public static DiskCacheThread get() { - if (sHttpApiThread == null) { - sHttpApiThread = new DiskCacheThread(); - sHttpApiThread.start(); - // thread must be entirely started - waitForStartup(sHttpApiThread); - } - return sHttpApiThread; - } - - public static synchronized void quit() { - if (sHttpApiThread != null) { - sHttpApiThread.mHandler.getLooper().quit(); - sHttpApiThread = null; - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import org.xbmc.android.util.Crc32; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.MediaType; + +import java.io.File; + +/** + * This thread asynchronously delivers sdcard-cached bitmaps. + *

+ * The sdcard cache keeps thumb bitmaps in three sizes (small, medium, + * original). This thread is directly accessed by the original HttpApi thread, + * through one of its wrappers. + * + * @author Team XBMC + */ +class DiskCacheThread extends AbstractThread { + + /** + * Singleton instance of this thread + */ + protected static DiskCacheThread sHttpApiThread; + + /** + * Constructor is protected, use get(). + */ + protected DiskCacheThread() { + super("HTTP API Disk Cache Thread"); + } + + /** + * Synchronously returns a thumb from the disk cache, or null if not + * available. + * + * @param cover Which cover to return + * @return Bitmap or null if not available. + */ + public static Bitmap getCover(ICoverArt cover, int thumbSize) { + final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), thumbSize, + Crc32.formatAsHexLowerCase(cover.getCrc())); + if (file.exists()) { + final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + MemCacheThread.addCoverToCache(cover, bitmap, thumbSize); + return bitmap; + } else + return null; + } + + /** + * Checks if a thumb is in the disk cache. + * + * @param cover + * @return True if thumb is in disk cache, false otherwise. + */ + public static boolean isInCache(ICoverArt cover, int thumbSize) { + final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), thumbSize, + Crc32.formatAsHexLowerCase(cover.getCrc()).toLowerCase()); + // TODO sometimes the filesize is zero + return file.exists() && file.length() > 0; + } + + /** + * Adds a cover to the disk cache + * + * @param cover Which cover to add + * @param bitmap Bitmap data, original size. + */ + public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int size) { + return ImportUtilities.addCoverToCache(cover, bitmap, size); + } + + /** + * Returns an instance of this thread. Spawns if necessary. + * + * @return + */ + public static DiskCacheThread get() { + if (sHttpApiThread == null) { + sHttpApiThread = new DiskCacheThread(); + sHttpApiThread.start(); + // thread must be entirely started + waitForStartup(sHttpApiThread); + } + return sHttpApiThread; + } + + public static synchronized void quit() { + if (sHttpApiThread != null) { + sHttpApiThread.mHandler.getLooper().quit(); + sHttpApiThread = null; + } + } + + /** + * Asynchronously returns a thumb from the disk cache, or null if + * not available. Accessed covers get automatically added to the + * memory cache. + * + * @param response Response object + * @param cover Which cover to return + * @param thumbSize Which size to return + */ + public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, + final INotifiableController controller) { + mHandler.post(new Runnable() { + public void run() { + if (cover != null) { + final File file = ImportUtilities.getCacheFile(MediaType.getArtFolder(cover.getMediaType()), + thumbSize, Crc32.formatAsHexLowerCase(cover.getCrc())); + if (file.exists()) { + final Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + if (bitmap == null) { // file is available but obviously corruped, so delete it. + file.delete(); + response.value = null; + } else { + MemCacheThread.addCoverToCache(cover, bitmap, thumbSize); + response.value = bitmap; + } + } + } + done(controller, response); + } + }); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/DownloadThread.java b/app/src/main/java/org/xbmc/android/remote/business/DownloadThread.java similarity index 81% rename from src/org/xbmc/android/remote/business/DownloadThread.java rename to app/src/main/java/org/xbmc/android/remote/business/DownloadThread.java index 9f0f0627..beec0268 100644 --- a/src/org/xbmc/android/remote/business/DownloadThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/DownloadThread.java @@ -1,192 +1,199 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.MediaType; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.httpapi.WifiStateException; - -import android.content.Context; -import android.graphics.Bitmap; -import android.util.Log; - -/** - * This thread asynchronously downloads thumbs from XBMC and returns them as - * Bitmap. - * - * When downloaded, the thumb is automatically saved to the memory- and disk- - * cache for further usage. - * - * @author Team XBMC - */ -class DownloadThread extends AbstractThread { - - /** - * Singleton instance of this thread - */ - protected static DownloadThread sHttpApiThread; - - private static final String TAG = "DownloadThread"; - private static final boolean DEBUG = AbstractManager.DEBUG; - - /** - * Constructor is protected, use get(). - */ - protected DownloadThread() { - super("HTTP API Network Thread"); - } - - /** - * Asynchronously downloads a thumb from XBMC and stores it locally. - * - * @param response Response object - * @param cover Which cover to download - * @param thumbSize Which size to return - */ - public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, final INotifiableController controller, final INotifiableManager manager, final Context context) { - mHandler.post(new Runnable() { - public void run() { - if (cover != null) { - if (DEBUG) Log.i(TAG, "Downloading cover " + cover); - /* it can happen that the same cover is queued consecutively several - * times. that's why we check both the disk cache and memory cache if - * the cover is not already available from a previously queued download. - */ - if (thumbSize < ThumbSize.BIG && MemCacheThread.isInCache(cover, thumbSize)) { // we're optimistic, let's check the memory first. - if (DEBUG) Log.i(TAG, "Cover is now already in mem cache, directly returning..."); - response.value = MemCacheThread.getCover(cover, thumbSize); - done(controller, response); - } else if (thumbSize < ThumbSize.BIG && DiskCacheThread.isInCache(cover, thumbSize)) { - if (DEBUG) Log.i(TAG, "Cover is not in mem cache anymore but still on disk, directly returning..."); - response.value = DiskCacheThread.getCover(cover, thumbSize); - done(controller, response); - } else { - download(response, cover, thumbSize, controller, manager, context, true); - } - } else { - done(controller, response); - } - } - }); - } - - /** - * Synchonously downloads a thumb from XBMC and stores it locally. - * - * @param response Response object, can be null. - * @param cover Cover to download - * @param thumbSize Size to return to response object - * @param controller Controller to be announced, can be null. - * @param manager Manager is needed to obtain different managers for cache access - * @param context Context is needed for obtaining other manager instances - * @return True if cover was downloaded successfully, false otherwise. - */ - public static boolean download(final DataResponse response, final ICoverArt cover, final int thumbSize, final INotifiableController controller, final INotifiableManager manager, final Context context, final boolean addToMemCache) { - if (DEBUG) Log.i(TAG, "Download START.."); - Bitmap bitmap = null; - final boolean success; - switch (cover.getMediaType()) { - case MediaType.MUSIC: - try { - bitmap = music(manager, context).getCover(manager, cover, thumbSize); - } catch (WifiStateException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - break; - case MediaType.VIDEO_MOVIE: - case MediaType.VIDEO: - try { - bitmap = video(manager, context).getCover(manager, cover, thumbSize); - } catch (WifiStateException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - break; - case MediaType.VIDEO_TVEPISODE: - case MediaType.VIDEO_TVSEASON: - case MediaType.VIDEO_TVSHOW: - try { - bitmap = tvshow(manager, context).getCover(manager, cover, thumbSize); - } catch (WifiStateException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - break; - case MediaType.PICTURES: - done(controller, response); - break; - default: - done(controller, response); - break; - } - if (DEBUG) Log.i(TAG, "Download END."); - if (bitmap != null) { - // add to disk cache - final Bitmap v = DiskCacheThread.addCoverToCache(cover, bitmap, thumbSize); - // add to mem cache - if (addToMemCache) { - MemCacheThread.addCoverToCache(cover, v, thumbSize); - } - if (response != null) { - response.value = v; - } - if (DEBUG) Log.i(TAG, "Done"); - success = true; - } else { - if (addToMemCache) { - // still add null value to mem cache so we don't try to fetch it again - if (DEBUG) Log.i(TAG, "Adding null-value (" + cover.getCrc() + ") to mem cache in order to block future downloads"); - MemCacheThread.addCoverToCache(cover, null, 0); - } - success = false; - } - done(controller, response); - return success; - } - - - /** - * Returns an instance of this thread. Spawns if necessary. - * @return - */ - public static DownloadThread get() { - if (sHttpApiThread == null) { - sHttpApiThread = new DownloadThread(); - sHttpApiThread.start(); - // thread must be entirely started - waitForStartup(sHttpApiThread); - } - return sHttpApiThread; - } - - public static synchronized void quit() { - if (sHttpApiThread != null) { - sHttpApiThread.mHandler.getLooper().quit(); - sHttpApiThread = null; - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; +import android.graphics.Bitmap; +import android.util.Log; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.MediaType; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.httpapi.WifiStateException; + +/** + * This thread asynchronously downloads thumbs from XBMC and returns them as + * Bitmap. + *

+ * When downloaded, the thumb is automatically saved to the memory- and disk- + * cache for further usage. + * + * @author Team XBMC + */ +class DownloadThread extends AbstractThread { + + private static final String TAG = "DownloadThread"; + private static final boolean DEBUG = AbstractManager.DEBUG; + /** + * Singleton instance of this thread + */ + protected static DownloadThread sHttpApiThread; + + /** + * Constructor is protected, use get(). + */ + protected DownloadThread() { + super("HTTP API Network Thread"); + } + + /** + * Synchonously downloads a thumb from XBMC and stores it locally. + * + * @param response Response object, can be null. + * @param cover Cover to download + * @param thumbSize Size to return to response object + * @param controller Controller to be announced, can be null. + * @param manager Manager is needed to obtain different managers for cache access + * @param context Context is needed for obtaining other manager instances + * @return True if cover was downloaded successfully, false otherwise. + */ + public static boolean download(final DataResponse response, final ICoverArt cover, final int thumbSize, + final INotifiableController controller, final INotifiableManager manager, + final Context context, final boolean addToMemCache) { + if (DEBUG) Log.i(TAG, "Download START.."); + Bitmap bitmap = null; + final boolean success; + switch (cover.getMediaType()) { + case MediaType.MUSIC: + try { + bitmap = music(manager, context).getCover(manager, cover, thumbSize); + } catch (WifiStateException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + break; + case MediaType.VIDEO_MOVIE: + case MediaType.VIDEO: + try { + bitmap = video(manager, context).getCover(manager, cover, thumbSize); + } catch (WifiStateException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + break; + case MediaType.VIDEO_TVEPISODE: + case MediaType.VIDEO_TVSEASON: + case MediaType.VIDEO_TVSHOW: + try { + bitmap = tvshow(manager, context).getCover(manager, cover, thumbSize); + } catch (WifiStateException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + break; + case MediaType.PICTURES: + done(controller, response); + break; + default: + done(controller, response); + break; + } + if (DEBUG) Log.i(TAG, "Download END."); + if (bitmap != null) { + // add to disk cache + final Bitmap v = DiskCacheThread.addCoverToCache(cover, bitmap, thumbSize); + // add to mem cache + if (addToMemCache) { + MemCacheThread.addCoverToCache(cover, v, thumbSize); + } + if (response != null) { + response.value = v; + } + if (DEBUG) Log.i(TAG, "Done"); + success = true; + } else { + if (addToMemCache) { + // still add null value to mem cache so we don't try to fetch it again + if (DEBUG) + Log.i(TAG, "Adding null-value (" + cover.getCrc() + ") to mem cache in order to block future " + + "downloads"); + MemCacheThread.addCoverToCache(cover, null, 0); + } + success = false; + } + done(controller, response); + return success; + } + + /** + * Returns an instance of this thread. Spawns if necessary. + * + * @return + */ + public static DownloadThread get() { + if (sHttpApiThread == null) { + sHttpApiThread = new DownloadThread(); + sHttpApiThread.start(); + // thread must be entirely started + waitForStartup(sHttpApiThread); + } + return sHttpApiThread; + } + + public static synchronized void quit() { + if (sHttpApiThread != null) { + sHttpApiThread.mHandler.getLooper().quit(); + sHttpApiThread = null; + } + } + + /** + * Asynchronously downloads a thumb from XBMC and stores it locally. + * + * @param response Response object + * @param cover Which cover to download + * @param thumbSize Which size to return + */ + public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, + final INotifiableController controller, final INotifiableManager manager, + final Context context) { + mHandler.post(new Runnable() { + public void run() { + if (cover != null) { + if (DEBUG) Log.i(TAG, "Downloading cover " + cover); + /* it can happen that the same cover is queued consecutively several + * times. that's why we check both the disk cache and memory cache if + * the cover is not already available from a previously queued download. + */ + if (thumbSize < ThumbSize.BIG && MemCacheThread.isInCache(cover, + thumbSize)) { // we're optimistic, let's check the memory first. + if (DEBUG) Log.i(TAG, "Cover is now already in mem cache, directly returning..."); + response.value = MemCacheThread.getCover(cover, thumbSize); + done(controller, response); + } else if (thumbSize < ThumbSize.BIG && DiskCacheThread.isInCache(cover, thumbSize)) { + if (DEBUG) + Log.i(TAG, "Cover is not in mem cache anymore but still on disk, directly returning..."); + response.value = DiskCacheThread.getCover(cover, thumbSize); + done(controller, response); + } else { + download(response, cover, thumbSize, controller, manager, context, true); + } + } else { + done(controller, response); + } + } + }); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/EventClientManager.java b/app/src/main/java/org/xbmc/android/remote/business/EventClientManager.java similarity index 91% rename from src/org/xbmc/android/remote/business/EventClientManager.java rename to app/src/main/java/org/xbmc/android/remote/business/EventClientManager.java index 0e1f43d6..59303710 100644 --- a/src/org/xbmc/android/remote/business/EventClientManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/EventClientManager.java @@ -1,132 +1,135 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.io.IOException; - -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; - -import android.content.Context; -import android.graphics.Bitmap; - -/** - * Super class of the wrappers, keeps common code. - * - * @author Team XBMC - */ -public class EventClientManager implements INotifiableManager, IEventClientManager { - - protected static final String TAG = "EventClientManager"; - protected static final Boolean DEBUG = false; - - private INotifiableController mController = null; - - public void setController(INotifiableController controller) { - mController = controller; - } - - public void onMessage(int code, String message) { - onMessage(message); - } - - public void sendAction(String actionmessage) throws IOException { - ClientFactory.getEventClient(this).sendAction(actionmessage); - } - - public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) throws IOException { - ClientFactory.getEventClient(this).sendButton(code, repeat, down, queue, amount, axis); - } - - public void sendButton(String mapName, String buttonName, boolean repeat, boolean down, boolean queue, short amount, byte axis) { - ClientFactory.getEventClient(this).sendButton(mapName, buttonName, repeat, down, queue, amount, axis); - } - - public void sendLog(byte loglevel, String logmessage) throws IOException { - ClientFactory.getEventClient(this).sendLog(loglevel, logmessage); - } - - public void sendMouse(int x, int y) throws IOException { - ClientFactory.getEventClient(this).sendMouse(x, y); - } - - public void sendNotification(String title, String message) throws IOException { - ClientFactory.getEventClient(this).sendNotification(title, message); - } - - public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException { - ClientFactory.getEventClient(this).sendNotification(title, message, icontype, icondata); - } - - public void onError(Exception e) { - if (mController != null) { - mController.onError(e); - } - } - - public void onMessage(String message) { - if (mController != null) { - mController.onMessage(message); - } - } - - public void getCover(DataResponse response, ICoverArt cover, int thumbSize, Bitmap defaultCover, final Context context, boolean b) { - // only a stub; - } - - public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize) { - return null; - } - - public boolean coverLoaded(final ICoverArt cover, final int thumbSize) { - return false; - } - - public void onWrongConnectionState(int state) { - if (mController != null) { - mController.onWrongConnectionState(state, null, null); - } - } - - public void onFinish(DataResponse response) { - // TODO Auto-generated method stub - - } - - public void onWrongConnectionState(int state, Command cmd) { - // TODO Auto-generated method stub - - } - - public void post(Runnable r) { - // TODO Auto-generated method stub - } - - public void retryAll() { - // TODO Auto-generated method stub - - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; +import android.graphics.Bitmap; + +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; + +import java.io.IOException; + +/** + * Super class of the wrappers, keeps common code. + * + * @author Team XBMC + */ +public class EventClientManager implements INotifiableManager, IEventClientManager { + + protected static final String TAG = "EventClientManager"; + protected static final Boolean DEBUG = false; + + private INotifiableController mController = null; + + public void setController(INotifiableController controller) { + mController = controller; + } + + public void onMessage(int code, String message) { + onMessage(message); + } + + public void sendAction(String actionmessage) throws IOException { + ClientFactory.getEventClient(this).sendAction(actionmessage); + } + + public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, + byte axis) throws IOException { + ClientFactory.getEventClient(this).sendButton(code, repeat, down, queue, amount, axis); + } + + public void sendButton(String mapName, String buttonName, boolean repeat, boolean down, boolean queue, + short amount, byte axis) { + ClientFactory.getEventClient(this).sendButton(mapName, buttonName, repeat, down, queue, amount, axis); + } + + public void sendLog(byte loglevel, String logmessage) throws IOException { + ClientFactory.getEventClient(this).sendLog(loglevel, logmessage); + } + + public void sendMouse(int x, int y) throws IOException { + ClientFactory.getEventClient(this).sendMouse(x, y); + } + + public void sendNotification(String title, String message) throws IOException { + ClientFactory.getEventClient(this).sendNotification(title, message); + } + + public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException { + ClientFactory.getEventClient(this).sendNotification(title, message, icontype, icondata); + } + + public void onError(Exception e) { + if (mController != null) { + mController.onError(e); + } + } + + public void onMessage(String message) { + if (mController != null) { + mController.onMessage(message); + } + } + + public void getCover(DataResponse response, ICoverArt cover, int thumbSize, Bitmap defaultCover, + final Context context, boolean b) { + // only a stub; + } + + public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize) { + return null; + } + + public boolean coverLoaded(final ICoverArt cover, final int thumbSize) { + return false; + } + + public void onWrongConnectionState(int state) { + if (mController != null) { + mController.onWrongConnectionState(state, null, null); + } + } + + public void onFinish(DataResponse response) { + // TODO Auto-generated method stub + + } + + public void onWrongConnectionState(int state, Command cmd) { + // TODO Auto-generated method stub + + } + + public void post(Runnable r) { + // TODO Auto-generated method stub + } + + public void retryAll() { + // TODO Auto-generated method stub + + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/InfoManager.java b/app/src/main/java/org/xbmc/android/remote/business/InfoManager.java similarity index 81% rename from src/org/xbmc/android/remote/business/InfoManager.java rename to app/src/main/java/org/xbmc/android/remote/business/InfoManager.java index c12fbabc..28e9cf7f 100644 --- a/src/org/xbmc/android/remote/business/InfoManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/InfoManager.java @@ -1,188 +1,202 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.util.ArrayList; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.FileLocation; -import org.xbmc.api.type.DirectoryMask; - -import android.content.Context; - - -/** - * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. - * - * @author Team XBMC - */ -public class InfoManager extends AbstractManager implements IInfoManager, INotifiableManager { - - /** - * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} - * @param response Response object - * @param field Field to return - */ - public void getSystemInfo(final DataResponse response, final int field, final Context context) { - mHandler.post(new Command(response, this){ - @Override - public void doRun() throws Exception { - response.value = info(context).getSystemInfo(InfoManager.this, field); - } - - }); - } - - /** - * Returns all defined shares of a media type - * @param response Response object - * @param mediaType Media type - */ - public void getShares(final DataResponse> response, final int mediaType, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = info(context).getShares(InfoManager.this, mediaType); - } - }); - } - - /** - * Returns the contents of a directory - * @param response Response object - * @param path Path to the directory - * @param mask Mask to filter - * @param offset Offset (0 for none) - * @param limit Limit (0 for none) - * @return - */ - public void getDirectory(final DataResponse> response, final String path, final DirectoryMask mask, final int offset, final int limit, final Context context, final int mediaType) { - mHandler.post(new Command>(response, this){ - @Override - public void doRun() throws Exception { - response.value = info(context).getDirectory(InfoManager.this, path, mask, offset, limit, mediaType); - } - - }); - } - - /** - * Returns the contents of a directory - * @param response Response object - * @param path Path to the directory - * @return - */ - public void getDirectory(final DataResponse> response, final String path, final Context context, final int mediaType) { - mHandler.post(new Command>(response, this){ - @Override - public void doRun() throws Exception { - response.value = info(context).getDirectory(InfoManager.this, path, mediaType); - } - - }); - } - - /** - * Returns the gui setting of XBMC - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. - * @param context - */ - public void getGuiSettingBool(final DataResponse response, final int setting, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = info(context).getGuiSettingBool(InfoManager.this, setting); - } - }); - } - - /** - * Returns the gui setting of XBMC - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. - * @param context - */ - public void getGuiSettingInt(final DataResponse response, final int setting, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = info(context).getGuiSettingInt(InfoManager.this, setting); - } - }); - } - - /** - * NOT YET IMPLEMENTED! Returns the gui setting of XBMC - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. - * @param context - */ - public void getGuiSettingString(final DataResponse response, final int setting) { - - } - - /** - * Sets an integer GUI setting - * @param response Response object - * @param field Field to return (see GuiSettings.java) - * @param val Integer value to set - */ - public void setGuiSettingInt(final DataResponse response, final int field, final int val, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = info(context).setGuiSettingInt(InfoManager.this, field, val); - } - }); - } - - /** - * Sets an integer GUI setting - * @param response Response object - * @param field Field to return (see GuiSettings.java) - * @param val Boolean value to set - */ - public void setGuiSettingBool(final DataResponse response, final int field, final boolean val, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = info(context).setGuiSettingBool(InfoManager.this, field, val); - } - }); - } - -// public void getGuiSetting(final Class t, final DataResponse response, final int setting) { -// mHandler.post(new Command(response, this) { -// @Override -// public void doRun() throws Exception { -// switch(GuiSettings.getTypeInt(setting)) { -// case 1: -// -// case 3: -// } -// } -// }); -// } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.FileLocation; +import org.xbmc.api.type.DirectoryMask; + +import java.util.ArrayList; + + +/** + * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. + * + * @author Team XBMC + */ +public class InfoManager extends AbstractManager implements IInfoManager, INotifiableManager { + + /** + * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} + * + * @param response Response object + * @param field Field to return + */ + public void getSystemInfo(final DataResponse response, final int field, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getSystemInfo(InfoManager.this, field); + } + + }); + } + + /** + * Returns all defined shares of a media type + * + * @param response Response object + * @param mediaType Media type + */ + public void getShares(final DataResponse> response, final int mediaType, + final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getShares(InfoManager.this, mediaType); + } + }); + } + + /** + * Returns the contents of a directory + * + * @param response Response object + * @param path Path to the directory + * @param mask Mask to filter + * @param offset Offset (0 for none) + * @param limit Limit (0 for none) + * @return + */ + public void getDirectory(final DataResponse> response, final String path, + final DirectoryMask mask, final int offset, final int limit, final Context context, + final int mediaType) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getDirectory(InfoManager.this, path, mask, offset, limit, mediaType); + } + + }); + } + + /** + * Returns the contents of a directory + * + * @param response Response object + * @param path Path to the directory + * @return + */ + public void getDirectory(final DataResponse> response, final String path, + final Context context, final int mediaType) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getDirectory(InfoManager.this, path, mediaType); + } + + }); + } + + /** + * Returns the gui setting of XBMC + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. + * @param context + */ + public void getGuiSettingBool(final DataResponse response, final int setting, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getGuiSettingBool(InfoManager.this, setting); + } + }); + } + + /** + * Returns the gui setting of XBMC + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. + * @param context + */ + public void getGuiSettingInt(final DataResponse response, final int setting, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).getGuiSettingInt(InfoManager.this, setting); + } + }); + } + + /** + * NOT YET IMPLEMENTED! Returns the gui setting of XBMC + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. + */ + public void getGuiSettingString(final DataResponse response, final int setting) { + + } + + /** + * Sets an integer GUI setting + * + * @param response Response object + * @param field Field to return (see GuiSettings.java) + * @param val Integer value to set + */ + public void setGuiSettingInt(final DataResponse response, final int field, final int val, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).setGuiSettingInt(InfoManager.this, field, val); + } + }); + } + + /** + * Sets an integer GUI setting + * + * @param response Response object + * @param field Field to return (see GuiSettings.java) + * @param val Boolean value to set + */ + public void setGuiSettingBool(final DataResponse response, final int field, final boolean val, + final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = info(context).setGuiSettingBool(InfoManager.this, field, val); + } + }); + } + +// public void getGuiSetting(final Class t, final DataResponse response, final int setting) { +// mHandler.post(new Command(response, this) { +// @Override +// public void doRun() throws Exception { +// switch(GuiSettings.getTypeInt(setting)) { +// case 1: +// +// case 3: +// } +// } +// }); +// } +} diff --git a/src/org/xbmc/android/remote/business/ManagerFactory.java b/app/src/main/java/org/xbmc/android/remote/business/ManagerFactory.java similarity index 97% rename from src/org/xbmc/android/remote/business/ManagerFactory.java rename to app/src/main/java/org/xbmc/android/remote/business/ManagerFactory.java index 49f7ae67..658f7c2b 100644 --- a/src/org/xbmc/android/remote/business/ManagerFactory.java +++ b/app/src/main/java/org/xbmc/android/remote/business/ManagerFactory.java @@ -1,58 +1,63 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.presentation.INotifiableController; - -public abstract class ManagerFactory { - - private static EventClientManager sEventClientManager = null; - - public static IInfoManager getInfoManager(INotifiableController controller) { - return ManagerThread.info(controller); - } - public static IControlManager getControlManager(INotifiableController controller) { - return ManagerThread.control(controller); - } - public static IVideoManager getVideoManager(INotifiableController controller) { - return ManagerThread.video(controller); - } - public static ITvShowManager getTvManager(INotifiableController controller) { - return ManagerThread.shows(controller); - } - public static IMusicManager getMusicManager(INotifiableController controller) { - return ManagerThread.music(controller); - } - public static IEventClientManager getEventClientManager(INotifiableController controller) { - if (sEventClientManager == null) { - sEventClientManager = new EventClientManager(); - } - sEventClientManager.setController(controller); - return sEventClientManager; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.presentation.INotifiableController; + +public abstract class ManagerFactory { + + private static EventClientManager sEventClientManager = null; + + public static IInfoManager getInfoManager(INotifiableController controller) { + return ManagerThread.info(controller); + } + + public static IControlManager getControlManager(INotifiableController controller) { + return ManagerThread.control(controller); + } + + public static IVideoManager getVideoManager(INotifiableController controller) { + return ManagerThread.video(controller); + } + + public static ITvShowManager getTvManager(INotifiableController controller) { + return ManagerThread.shows(controller); + } + + public static IMusicManager getMusicManager(INotifiableController controller) { + return ManagerThread.music(controller); + } + + public static IEventClientManager getEventClientManager(INotifiableController controller) { + if (sEventClientManager == null) { + sEventClientManager = new EventClientManager(); + } + sEventClientManager.setController(controller); + return sEventClientManager; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/ManagerThread.java b/app/src/main/java/org/xbmc/android/remote/business/ManagerThread.java similarity index 96% rename from src/org/xbmc/android/remote/business/ManagerThread.java rename to app/src/main/java/org/xbmc/android/remote/business/ManagerThread.java index 8cc96fa7..81c5be18 100644 --- a/src/org/xbmc/android/remote/business/ManagerThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/ManagerThread.java @@ -1,107 +1,110 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import org.xbmc.api.presentation.INotifiableController; - -import android.os.Handler; -import android.os.Looper; - -/** - * Spawned on first access, then looping. Takes all HTTP API commands and - * synchronously returns the result. - * - * @author Team XBMC - */ -public class ManagerThread extends Thread { - - private static ManagerThread sManagerThread; - private Handler mHandler; - - private final InfoManager mInfoManager; - private final ControlManager mControlManager; - private final MusicManager mMusicManager; - private final VideoManager mVideoManager; - private final TvShowManager mTvShowManager; - - private ManagerThread() { - super("ManagerThread"); - mInfoManager = new InfoManager(); - mControlManager = new ControlManager(); - mMusicManager = new MusicManager(); - mVideoManager = new VideoManager(); - mTvShowManager = new TvShowManager(); - } - public static ManagerThread get() { - if (sManagerThread == null) { - sManagerThread = new ManagerThread(); - sManagerThread.start(); - // thread must be entirely started - while (sManagerThread.mHandler == null) { - try { - Thread.sleep(50); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - return sManagerThread; - } - - public void run() { - Looper.prepare(); - mHandler = new Handler(); - mInfoManager.setHandler(mHandler); - mControlManager.setHandler(mHandler); - mMusicManager.setHandler(mHandler); - mVideoManager.setHandler(mHandler); - mTvShowManager.setHandler(mHandler); - Looper.loop(); - } - - public static InfoManager info(INotifiableController controller) { - final InfoManager im = get().mInfoManager; - im.setController(controller); - return im; - } - public static ControlManager control(INotifiableController controller) { - final ControlManager cm = get().mControlManager; - cm.setController(controller); - return cm; - } - public static MusicManager music(INotifiableController controller) { - final MusicManager mm = get().mMusicManager; - mm.setController(controller); - return mm; - } - public static VideoManager video(INotifiableController controller) { - final VideoManager vm = get().mVideoManager; - vm.setController(controller); - return vm; - } - - public static TvShowManager shows(INotifiableController controller) { - final TvShowManager shows = get().mTvShowManager; - shows.setController(controller); - return shows; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.os.Handler; +import android.os.Looper; + +import org.xbmc.api.presentation.INotifiableController; + +/** + * Spawned on first access, then looping. Takes all HTTP API commands and + * synchronously returns the result. + * + * @author Team XBMC + */ +public class ManagerThread extends Thread { + + private static ManagerThread sManagerThread; + private final InfoManager mInfoManager; + private final ControlManager mControlManager; + private final MusicManager mMusicManager; + private final VideoManager mVideoManager; + private final TvShowManager mTvShowManager; + private Handler mHandler; + + private ManagerThread() { + super("ManagerThread"); + mInfoManager = new InfoManager(); + mControlManager = new ControlManager(); + mMusicManager = new MusicManager(); + mVideoManager = new VideoManager(); + mTvShowManager = new TvShowManager(); + } + + public static ManagerThread get() { + if (sManagerThread == null) { + sManagerThread = new ManagerThread(); + sManagerThread.start(); + // thread must be entirely started + while (sManagerThread.mHandler == null) { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + return sManagerThread; + } + + public static InfoManager info(INotifiableController controller) { + final InfoManager im = get().mInfoManager; + im.setController(controller); + return im; + } + + public static ControlManager control(INotifiableController controller) { + final ControlManager cm = get().mControlManager; + cm.setController(controller); + return cm; + } + + public static MusicManager music(INotifiableController controller) { + final MusicManager mm = get().mMusicManager; + mm.setController(controller); + return mm; + } + + public static VideoManager video(INotifiableController controller) { + final VideoManager vm = get().mVideoManager; + vm.setController(controller); + return vm; + } + + public static TvShowManager shows(INotifiableController controller) { + final TvShowManager shows = get().mTvShowManager; + shows.setController(controller); + return shows; + } + + public void run() { + Looper.prepare(); + mHandler = new Handler(); + mInfoManager.setHandler(mHandler); + mControlManager.setHandler(mHandler); + mMusicManager.setHandler(mHandler); + mVideoManager.setHandler(mHandler); + mTvShowManager.setHandler(mHandler); + Looper.loop(); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/MemCacheThread.java b/app/src/main/java/org/xbmc/android/remote/business/MemCacheThread.java similarity index 76% rename from src/org/xbmc/android/remote/business/MemCacheThread.java rename to app/src/main/java/org/xbmc/android/remote/business/MemCacheThread.java index 5f7164f4..5c1eb20c 100644 --- a/src/org/xbmc/android/remote/business/MemCacheThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/MemCacheThread.java @@ -1,169 +1,173 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.lang.ref.SoftReference; -import java.util.HashMap; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.ThumbSize; - -import android.graphics.Bitmap; -import android.util.Log; - -/** - * This thread asynchronously delivers memory-cached bitmaps. - * - * The memory cache keeps small-size thumb bitmaps in a soft-referenced list. - * This thread is directly accessed by the original HttpApi thread, through one - * of its wrappers. - * - * @author Team XBMC - */ -class MemCacheThread extends AbstractThread { - - private final static String TAG = "MemCacheThread"; - private final static boolean DEBUG = AbstractManager.DEBUG; - - /** - * Singleton instance of this thread - */ - protected static MemCacheThread sHttpApiThread; - - /** - * The actual cache variable. Here are the thumbs stored. - */ - private static final HashMap> sCacheSmall = new HashMap>(); - private static final HashMap> sCacheMedium = new HashMap>(); - private static final HashMap sNotAvailable = new HashMap(); - - /** - * Constructor is protected, use get(). - */ - protected MemCacheThread() { - super("HTTP API Mem Cache Thread"); - } - - /** - * Asynchronously returns a thumb from the mem cache, or null if - * not available. - * - * @param response Response object - * @param cover Which cover to return - */ - public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, final INotifiableController controller, final Bitmap defaultCover) { - if (controller == null) { - Log.w(TAG, "[" + cover.getId() + "] Controller is null."); - } - mHandler.post(new Runnable() { - public void run() { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking if cover in cache.."); - if (cover != null) { - final long crc = cover.getCrc(); - final SoftReference ref = getCache(thumbSize).get(crc); - if (ref != null) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> In cache."); - response.value = ref.get(); - if (DEBUG && response.value == null) Log.w(TAG, "[" + cover.getId() + "] -> GC'd from cache."); - } else if (sNotAvailable.containsKey(crc)) { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Marked as not-in-cache (" + crc + ")."); - response.value = defaultCover; - } else { - if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Not in cache."); - } - } - done(controller, response); - } - }); - } - - private static HashMap> getCache(int thumbSize) { - return (thumbSize == ThumbSize.MEDIUM) ? sCacheMedium : sCacheSmall; - } - - /** - * Synchronously returns a thumb from the mem cache, or null - * if not available. - * - * @param cover Which cover to return - * @return Bitmap or null if not available. - */ - public static Bitmap getCover(ICoverArt cover, int thumbSize) { - Bitmap cache = getCache(thumbSize).get(cover.getCrc()).get(); - return cache; - } - - /** - * Checks if a thumb is in the mem cache. - * @param cover - * @return True if thumb is in mem cache, false otherwise. - */ - public static boolean isInCache(ICoverArt cover, int thumbSize) { - return (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) && - getCache(thumbSize).containsKey(cover.getCrc()) && - getCache(thumbSize).get(cover.getCrc()) != null && - getCache(thumbSize).get(cover.getCrc()).get() != null; - } - - /** - * Adds a cover to the mem cache - * @param cover Which cover to add - * @param bitmap Bitmap data - */ - public static void addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) { - // if bitmap is null, add an entry to the sNotAvailable table so we can return the default bitmap later directly. - if (bitmap == null) { - sNotAvailable.put(cover.getCrc(), true); - } else if (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) { - getCache(thumbSize).put(cover.getCrc(), new SoftReference(bitmap)); - } - } - - /** - * Returns an instance of this thread. Spawns if necessary. - * @return - */ - public static MemCacheThread get() { - if (sHttpApiThread == null) { - sHttpApiThread = new MemCacheThread(); - sHttpApiThread.start(); - // thread must be entirely started - waitForStartup(sHttpApiThread); - } - return sHttpApiThread; - } - - public synchronized static void quit() { - if (sHttpApiThread != null) { - sHttpApiThread.mHandler.getLooper().quit(); - sHttpApiThread = null; - } - } - - public static void purgeCache() { - sCacheMedium.clear(); - sCacheSmall.clear(); - sNotAvailable.clear(); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.graphics.Bitmap; +import android.util.Log; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.ThumbSize; + +import java.lang.ref.SoftReference; +import java.util.HashMap; + +/** + * This thread asynchronously delivers memory-cached bitmaps. + *

+ * The memory cache keeps small-size thumb bitmaps in a soft-referenced list. + * This thread is directly accessed by the original HttpApi thread, through one + * of its wrappers. + * + * @author Team XBMC + */ +class MemCacheThread extends AbstractThread { + + private final static String TAG = "MemCacheThread"; + private final static boolean DEBUG = AbstractManager.DEBUG; + /** + * The actual cache variable. Here are the thumbs stored. + */ + private static final HashMap> sCacheSmall = new HashMap>(); + private static final HashMap> sCacheMedium = new HashMap>(); + private static final HashMap sNotAvailable = new HashMap(); + /** + * Singleton instance of this thread + */ + protected static MemCacheThread sHttpApiThread; + + /** + * Constructor is protected, use get(). + */ + protected MemCacheThread() { + super("HTTP API Mem Cache Thread"); + } + + private static HashMap> getCache(int thumbSize) { + return (thumbSize == ThumbSize.MEDIUM) ? sCacheMedium : sCacheSmall; + } + + /** + * Synchronously returns a thumb from the mem cache, or null + * if not available. + * + * @param cover Which cover to return + * @return Bitmap or null if not available. + */ + public static Bitmap getCover(ICoverArt cover, int thumbSize) { + Bitmap cache = getCache(thumbSize).get(cover.getCrc()).get(); + return cache; + } + + /** + * Checks if a thumb is in the mem cache. + * + * @param cover + * @return True if thumb is in mem cache, false otherwise. + */ + public static boolean isInCache(ICoverArt cover, int thumbSize) { + return (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) && + getCache(thumbSize).containsKey(cover.getCrc()) && + getCache(thumbSize).get(cover.getCrc()) != null && + getCache(thumbSize).get(cover.getCrc()).get() != null; + } + + /** + * Adds a cover to the mem cache + * + * @param cover Which cover to add + * @param bitmap Bitmap data + */ + public static void addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) { + // if bitmap is null, add an entry to the sNotAvailable table so we can return the default bitmap later + // directly. + if (bitmap == null) { + sNotAvailable.put(cover.getCrc(), true); + } else if (thumbSize == ThumbSize.SMALL || thumbSize == ThumbSize.MEDIUM) { + getCache(thumbSize).put(cover.getCrc(), new SoftReference(bitmap)); + } + } + + /** + * Returns an instance of this thread. Spawns if necessary. + * + * @return + */ + public static MemCacheThread get() { + if (sHttpApiThread == null) { + sHttpApiThread = new MemCacheThread(); + sHttpApiThread.start(); + // thread must be entirely started + waitForStartup(sHttpApiThread); + } + return sHttpApiThread; + } + + public synchronized static void quit() { + if (sHttpApiThread != null) { + sHttpApiThread.mHandler.getLooper().quit(); + sHttpApiThread = null; + } + } + + public static void purgeCache() { + sCacheMedium.clear(); + sCacheSmall.clear(); + sNotAvailable.clear(); + } + + /** + * Asynchronously returns a thumb from the mem cache, or null if + * not available. + * + * @param response Response object + * @param cover Which cover to return + */ + public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, + final INotifiableController controller, final Bitmap defaultCover) { + if (controller == null) { + Log.w(TAG, "[" + cover.getId() + "] Controller is null."); + } + mHandler.post(new Runnable() { + public void run() { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] Checking if cover in cache.."); + if (cover != null) { + final long crc = cover.getCrc(); + final SoftReference ref = getCache(thumbSize).get(crc); + if (ref != null) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> In cache."); + response.value = ref.get(); + if (DEBUG && response.value == null) Log.w(TAG, "[" + cover.getId() + "] -> GC'd from cache."); + } else if (sNotAvailable.containsKey(crc)) { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Marked as not-in-cache (" + crc + ")."); + response.value = defaultCover; + } else { + if (DEBUG) Log.i(TAG, "[" + cover.getId() + "] -> Not in cache."); + } + } + done(controller, response); + } + }); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/MusicManager.java b/app/src/main/java/org/xbmc/android/remote/business/MusicManager.java similarity index 81% rename from src/org/xbmc/android/remote/business/MusicManager.java rename to app/src/main/java/org/xbmc/android/remote/business/MusicManager.java index 0d9e28fa..6436fd0f 100644 --- a/src/org/xbmc/android/remote/business/MusicManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/MusicManager.java @@ -1,643 +1,698 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.util.ArrayList; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IMusicClient; -import org.xbmc.api.info.GuiSettings; -import org.xbmc.api.info.PlayStatus; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Song; -import org.xbmc.api.type.SortType; -import org.xbmc.httpapi.WifiStateException; -import org.xbmc.jsonrpc.client.MusicClient; - -import android.content.Context; - -/** - * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. - * - * @author Team XBMC - */ -public class MusicManager extends AbstractManager implements IMusicManager, ISortableManager, INotifiableManager { - - /** - * Gets all albums from database - * @param response Response object - */ - public void getCompilations(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this){ - @Override - public void doRun() throws Exception { - final IMusicClient mc = music(context); - ArrayList compilationArtistIDs = mc.getCompilationArtistIDs(MusicManager.this); - response.value = mc.getAlbums(MusicManager.this, compilationArtistIDs); - } - }); - } - - /** - * Gets all albums from database - * @param response Response object - */ - public void getAlbums(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = music(context).getAlbums(MusicManager.this, getSortBy(SortType.ALBUM), getSortOrder()); - } - }); - } - - /** - * SYNCHRONOUSLY gets all albums from database - * @return All albums in database - */ - public ArrayList getAlbums(final Context context) { - try { //TODO fix this to throw - return music(context).getAlbums(MusicManager.this, getSortBy(SortType.ALBUM), getSortOrder()); - } catch (WifiStateException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Gets all albums of an artist from database - * @param response Response object - * @param artist Artist of the albums - */ - public void getAlbums(final DataResponse> response, final Artist artist, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getAlbums(MusicManager.this, artist, getSortBy(SortType.ALBUM), getSortOrder()); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this){ - @Override - public void doRun() throws Exception { - response.value = music(context).getAlbums(MusicManager.this, artist, getSortBy(SortType.ALBUM), getSortOrder()); - } - }); - } - - /** - * Gets all albums of a genre from database - * @param response Response object - * @param artist Genre of the albums - */ - public void getAlbums(final DataResponse> response, final Genre genre, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getAlbums(MusicManager.this, genre, getSortBy(SortType.ALBUM), getSortOrder()); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getAlbums(MusicManager.this, genre, getSortBy(SortType.ALBUM), getSortOrder()); - } - }); - } - - /** - * Gets all songs of an album from database - * @param response Response object - * @param album Album - */ - public void getSongs(final DataResponse> response, final Album album, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getSongs(MusicManager.this, album, getSortBy(SortType.ARTIST), getSortOrder()); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getSongs(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); - } - }); - } - - /** - * Gets all songs from an artist from database - * @param response Response object - * @param album Artist - */ - public void getSongs(final DataResponse> response, final Artist artist, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getSongs(MusicManager.this, artist, getSortBy(SortType.ARTIST), getSortOrder()); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getSongs(MusicManager.this, artist, getSortBy(SortType.ARTIST), getSortOrder()); - } - }); - } - - /** - * Gets all songs of a genre from database - * @param response Response object - * @param album Genre - */ - public void getSongs(final DataResponse> response, final Genre genre, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getSongs(MusicManager.this, genre, getSortBy(SortType.ARTIST), getSortOrder()); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getSongs(MusicManager.this, genre, getSortBy(SortType.ARTIST), getSortOrder()); - } - }); - } - - /** - * Gets all artists from database - * @param response Response object - */ - public void getArtists(final DataResponse> response, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// boolean albumArtistsOnly; -// try { -// albumArtistsOnly = info(context).getGuiSettingBool(MusicManager.this, GuiSettings.MusicLibrary.ALBUM_ARTISTS_ONLY); -// response.value = music(context).getArtists(MusicManager.this, albumArtistsOnly); -// onFinish(response); -// } catch (WifiStateException e) { -// onWrongConnectionState(e.getState()); -// } -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - final boolean albumArtistsOnly = !info(context).getGuiSettingBool(MusicManager.this, GuiSettings.MusicLibrary.SHOW_COMPLATION_ARTISTS); - response.value = music(context).getArtists(MusicManager.this, albumArtistsOnly); - } - }); - } - - /** - * Gets all artists with at least one song of a genre. - * @param response Response object - * @param genre Genre - */ - public void getArtists(final DataResponse> response, final Genre genre, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// boolean albumArtistsOnly; -// try { -// albumArtistsOnly = info(context).getGuiSettingBool(MusicManager.this, GuiSettings.MusicLibrary.ALBUM_ARTISTS_ONLY); -// response.value = music(context).getArtists(MusicManager.this, genre, albumArtistsOnly); -// onFinish(response); -// } catch (WifiStateException e) { -// onWrongConnectionState(e.getState()); -// } -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - final boolean albumArtistsOnly = !info(context).getGuiSettingBool(MusicManager.this, GuiSettings.MusicLibrary.SHOW_COMPLATION_ARTISTS); - response.value = music(context).getArtists(MusicManager.this, genre, albumArtistsOnly); - } - }); - } - - /** - * Gets all artists from database - * @param response Response object - */ - public void getGenres(final DataResponse> response, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// response.value = music(context).getGenres(MusicManager.this); -// onFinish(response); -// } -// }); - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getGenres(MusicManager.this); - } - }); - } - - /** - * Adds an album to the current playlist. If current playlist is stopped, - * the album is added to playlist and the first song is selected to play. - * If something is playing already, the album is only queued. - * - * @param response Response object - * @param album Album to add - */ - public void addToPlaylist(final DataResponse response, final Album album, final Context context) { -// mHandler.post(new Runnable() { -// public void run() { -// final IMusicClient mc = music(context); -// final IControlClient cc = control(context); -// final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); -// response.value = mc.addToPlaylist(MusicManager.this, album); -// checkForPlayAfterQueue(mc, cc, numAlreadyQueued); -// onFinish(response); -// } -// }); - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); - response.value = mc.addToPlaylist(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); - checkForPlayAfterQueue(mc, cc, numAlreadyQueued); - } - }); - } - - /** - * Adds all songs of a genre to the current playlist. If current playlist is stopped, - * play is executed. Value is the first song of the added album. - * @param response Response object - * @param genre Genre of songs to add - */ - public void addToPlaylist(final DataResponse response, final Genre genre, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); - response.value = mc.addToPlaylist(MusicManager.this, genre, getSortBy(SortType.ARTIST), getSortOrder()); - checkForPlayAfterQueue(mc, cc, numAlreadyQueued); - } - }); - } - - /** - * Adds a song to the current playlist. Even if the playlist is empty, only this song will be added. - * @param response Response object - * @param album Song to add - */ - public void addToPlaylist(final DataResponse response, final Song song, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).addToPlaylist(MusicManager.this, song); - } - }); - } - - /** - * Adds a song to the current playlist. If the playlist is empty, the whole - * album will be added with this song playing, otherwise only this song is - * added. - * - * Attention, the response.value result is different as usual: True - * means the whole album was added, false means ony the song. - * - * @param response Response object - * @param album Album to add - * @param song Song to play - */ - public void addToPlaylist(final DataResponse response, final Album album, final Song song, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - final int playStatus = cc.getPlayState(MusicManager.this); - //cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); - final int playlistSize = mc.getPlaylistSize(MusicManager.this); - int playPos = -1; - if (playlistSize == 0) { // if playlist is empty, add the whole album - int n = 0; - for (Song albumSong : mc.getSongs(MusicManager.this, album, getSortBy(PREF_SORT_KEY_ALBUM), getSortOrder())) { - if (albumSong.id == song.id) { - playPos = n; - break; - } - n++; - } - mc.addToPlaylist(MusicManager.this, album, getSortBy(PREF_SORT_KEY_ALBUM), getSortOrder()); - response.value = true; - } else { // otherwise, only add the song - mc.addToPlaylist(MusicManager.this, song); - response.value = false; - } - if (playStatus == PlayStatus.STOPPED) { // if nothing is playing, play the song - if (playPos == 0) { - mc.playlistSetSong(MusicManager.this, playPos + 1); - mc.playPrev(MusicManager.this); - } else if (playPos > 0) { - mc.playlistSetSong(MusicManager.this, playPos - 1); - mc.playNext(MusicManager.this); - } else { - mc.playlistSetSong(MusicManager.this, playlistSize - 1); - mc.playNext(MusicManager.this); - } - } - } - }); - } - - /** - * Adds all songs from an artist to the playlist. If current playlist is - * stopped, the all songs of the artist are added to playlist and the first - * song is selected to play. If something is playing already, the songs are - * only queued. - * @param response Response object - * @param artist Artist - */ - public void addToPlaylist(final DataResponse response, final Artist artist, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); - response.value = mc.addToPlaylist(MusicManager.this, artist, getSortBy(SortType.ALBUM), getSortOrder()); - checkForPlayAfterQueue(mc, cc, numAlreadyQueued); - } - }); - } - - /** - * Adds all songs of a genre from an artist to the playlist. If nothing is playing, - * the first song will be played, otherwise songs are just added to the playlist. - * @param response Response object - * @param artist Artist - * @param genre Genre - */ - public void addToPlaylist(final DataResponse response, final Artist artist, final Genre genre, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); - response.value = mc.addToPlaylist(MusicManager.this, artist, genre, getSortBy(SortType.ARTIST), getSortOrder()); - checkForPlayAfterQueue(mc, cc, numAlreadyQueued); - } - }); - } - - /** - * Sets the media at playlist position position to be the next item to be played. - * @param response Response object - * @param position Position, starting with 0. - */ - public void setPlaylistSong(final DataResponse response, final int position, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).setPlaylistPosition(MusicManager.this, position); - } - }); - } - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Position to remove, starting with 0. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final int position, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).removeFromPlaylist(MusicManager.this, position); - } - }); - } - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final String path, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).removeFromPlaylist(MusicManager.this, path); - } - }); - } - - /** - * Plays an album - * @param response Response object - * @param album Album to play - */ - public void play(final DataResponse response, final Album album, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - control(context).stop(MusicManager.this); - response.value = music(context).play(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); - } - }); - } - - /** - * Plays all songs of a genre - * @param response Response object - * @param genre Genre of songs to play - */ - public void play(final DataResponse response, final Genre genre, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - control(context).stop(MusicManager.this); - response.value = music(context).play(MusicManager.this, genre, getSortBy(SortType.ARTIST), getSortOrder()); - } - }); - } - - /** - * Plays a song - * @param response Response object - * @param song Song to play - */ - public void play(final DataResponse response, final Song song, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - control(context).stop(MusicManager.this); - response.value = music(context).play(MusicManager.this, song); - } - }); - } - - /** - * Plays a song, but the whole album is added to the playlist. - * @param response Response object - * @param album Album to queue - * @param song Song to play - */ - public void play(final DataResponse response, final Album album, final Song song, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - final IMusicClient mc = music(context); - final IControlClient cc = control(context); - int n = 0; - int playPos = 0; - mc.clearPlaylist(MusicManager.this); - for (Song albumSong : mc.getSongs(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder())) { - if (albumSong.id == song.id) { - playPos = n; - break; - } - n++; - } - cc.stop(MusicManager.this); - mc.addToPlaylist(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); - if (playPos > 0) { - response.value = mc.playlistSetSong(MusicManager.this, playPos); - } - else{ - response.value = cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); - } - } - }); - } - - /** - * Plays all songs from an artist - * @param response Response object - * @param artist Artist whose songs to play - */ - public void play(final DataResponse response, final Artist artist, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - control(context).stop(MusicManager.this); - response.value = music(context).play(MusicManager.this, artist, getSortBy(SortType.ALBUM), getSortOrder()); - } - }); - } - - /** - * Plays songs of a genre from an artist - * @param response Response object - * @param artist Artist whose songs to play - * @param genre Genre filter - */ - public void play(final DataResponse response, final Artist artist, final Genre genre, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - control(context).stop(MusicManager.this); - response.value = music(context).play(MusicManager.this, artist, genre); - } - }); - } - - - /** - * Starts playing the next media in the current playlist. - * @param response Response object - */ - public void playlistNext(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).playNext(MusicManager.this); - } - }); - } - - /** - * Returns an array of songs on the playlist. Empty array if nothing is playing. - * @param response Response object - */ - public void getPlaylist(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getPlaylist(MusicManager.this); - final String firstEntry = response.value.get(0); - if (firstEntry != null && firstEntry.equals("[Empty]")) { - response.value = new ArrayList(); - } - } - }); - } - - /** - * Returns the position of the currently playing song in the playlist. First position is 0. - * @param response Response object - */ - public void getPlaylistPosition(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).getPlaylistPosition(MusicManager.this); - } - }); - } - - /** - * Updates the album object with additional data from the albuminfo table - * @param response Response object - * @param album Album to update - */ - public void updateAlbumInfo(final DataResponse response, final Album album, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).updateAlbumInfo(MusicManager.this, album); - } - }); - } - - /** - * Updates the artist object with additional data from the artistinfo table - * @param response Response object - * @param artist Artist to update - */ - public void updateArtistInfo(final DataResponse response, final Artist artist, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = music(context).updateArtistInfo(MusicManager.this, artist); - } - }); - } - - /** - * Checks if something's playing. If that's not the case, set the - * playlist's play position either to the start if there were no items - * before, or to the first position of the newly added files. - * @param mc Music client - * @param cc Control client - * @param numAlreadyQueued Number of previously queued items - */ - private void checkForPlayAfterQueue(final IMusicClient mc, final IControlClient cc, int numAlreadyQueued) { - final int ps = cc.getPlayState(MusicManager.this); - if (ps == PlayStatus.STOPPED) { // if nothing is playing, play the song - cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); - if (numAlreadyQueued == 0) { - mc.playNext(MusicManager.this); - } else { - mc.playlistSetSong(MusicManager.this, numAlreadyQueued); - } - } - } - - public void onWrongConnectionState(int state) { - // TODO Auto-generated method stub - - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.data.IControlClient; +import org.xbmc.api.data.IMusicClient; +import org.xbmc.api.info.GuiSettings; +import org.xbmc.api.info.PlayStatus; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Song; +import org.xbmc.api.type.SortType; +import org.xbmc.httpapi.WifiStateException; +import org.xbmc.jsonrpc.client.MusicClient; + +import java.util.ArrayList; + +/** + * Asynchronously wraps the {@link org.xbmc.httpapi.client.InfoClient} class. + * + * @author Team XBMC + */ +public class MusicManager extends AbstractManager implements IMusicManager, ISortableManager, INotifiableManager { + + /** + * Gets all albums from database + * + * @param response Response object + */ + public void getCompilations(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + final IMusicClient mc = music(context); + ArrayList compilationArtistIDs = mc.getCompilationArtistIDs(MusicManager.this); + response.value = mc.getAlbums(MusicManager.this, compilationArtistIDs); + } + }); + } + + /** + * Gets all albums from database + * + * @param response Response object + */ + public void getAlbums(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = music(context).getAlbums(MusicManager.this, getSortBy(SortType.ALBUM), + getSortOrder()); + } + }); + } + + /** + * SYNCHRONOUSLY gets all albums from database + * + * @return All albums in database + */ + public ArrayList getAlbums(final Context context) { + try { //TODO fix this to throw + return music(context).getAlbums(MusicManager.this, getSortBy(SortType.ALBUM), getSortOrder()); + } catch (WifiStateException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Gets all albums of an artist from database + * + * @param response Response object + * @param artist Artist of the albums + */ + public void getAlbums(final DataResponse> response, final Artist artist, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getAlbums(MusicManager.this, artist, getSortBy(SortType.ALBUM), +// getSortOrder()); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = music(context).getAlbums(MusicManager.this, artist, getSortBy(SortType.ALBUM), + getSortOrder()); + } + }); + } + + /** + * Gets all albums of a genre from database + * + * @param response Response object + * @param genre Genre of the albums + */ + public void getAlbums(final DataResponse> response, final Genre genre, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getAlbums(MusicManager.this, genre, getSortBy(SortType.ALBUM), +// getSortOrder()); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getAlbums(MusicManager.this, genre, getSortBy(SortType.ALBUM), + getSortOrder()); + } + }); + } + + /** + * Gets all songs of an album from database + * + * @param response Response object + * @param album Album + */ + public void getSongs(final DataResponse> response, final Album album, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getSongs(MusicManager.this, album, getSortBy(SortType.ARTIST), +// getSortOrder()); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getSongs(MusicManager.this, album, getSortBy(SortType.TRACK), + getSortOrder()); + } + }); + } + + /** + * Gets all songs from an artist from database + * + * @param response Response object + * @param artist Artist + */ + public void getSongs(final DataResponse> response, final Artist artist, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getSongs(MusicManager.this, artist, getSortBy(SortType.ARTIST), +// getSortOrder()); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getSongs(MusicManager.this, artist, getSortBy(SortType.ARTIST), + getSortOrder()); + } + }); + } + + /** + * Gets all songs of a genre from database + * + * @param response Response object + * @param genre Genre + */ + public void getSongs(final DataResponse> response, final Genre genre, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getSongs(MusicManager.this, genre, getSortBy(SortType.ARTIST), +// getSortOrder()); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getSongs(MusicManager.this, genre, getSortBy(SortType.ARTIST), + getSortOrder()); + } + }); + } + + /** + * Gets all artists from database + * + * @param response Response object + */ + public void getArtists(final DataResponse> response, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// boolean albumArtistsOnly; +// try { +// albumArtistsOnly = info(context).getGuiSettingBool(MusicManager.this, +// GuiSettings.MusicLibrary.ALBUM_ARTISTS_ONLY); +// response.value = music(context).getArtists(MusicManager.this, albumArtistsOnly); +// onFinish(response); +// } catch (WifiStateException e) { +// onWrongConnectionState(e.getState()); +// } +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + final boolean albumArtistsOnly = !info(context).getGuiSettingBool(MusicManager.this, + GuiSettings.MusicLibrary.SHOW_COMPLATION_ARTISTS); + response.value = music(context).getArtists(MusicManager.this, albumArtistsOnly); + } + }); + } + + /** + * Gets all artists with at least one song of a genre. + * + * @param response Response object + * @param genre Genre + */ + public void getArtists(final DataResponse> response, final Genre genre, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// boolean albumArtistsOnly; +// try { +// albumArtistsOnly = info(context).getGuiSettingBool(MusicManager.this, +// GuiSettings.MusicLibrary.ALBUM_ARTISTS_ONLY); +// response.value = music(context).getArtists(MusicManager.this, genre, albumArtistsOnly); +// onFinish(response); +// } catch (WifiStateException e) { +// onWrongConnectionState(e.getState()); +// } +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + final boolean albumArtistsOnly = !info(context).getGuiSettingBool(MusicManager.this, + GuiSettings.MusicLibrary.SHOW_COMPLATION_ARTISTS); + response.value = music(context).getArtists(MusicManager.this, genre, albumArtistsOnly); + } + }); + } + + /** + * Gets all artists from database + * + * @param response Response object + */ + public void getGenres(final DataResponse> response, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// response.value = music(context).getGenres(MusicManager.this); +// onFinish(response); +// } +// }); + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getGenres(MusicManager.this); + } + }); + } + + /** + * Adds an album to the current playlist. If current playlist is stopped, + * the album is added to playlist and the first song is selected to play. + * If something is playing already, the album is only queued. + * + * @param response Response object + * @param album Album to add + */ + public void addToPlaylist(final DataResponse response, final Album album, final Context context) { +// mHandler.post(new Runnable() { +// public void run() { +// final IMusicClient mc = music(context); +// final IControlClient cc = control(context); +// final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); +// response.value = mc.addToPlaylist(MusicManager.this, album); +// checkForPlayAfterQueue(mc, cc, numAlreadyQueued); +// onFinish(response); +// } +// }); + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); + response.value = mc.addToPlaylist(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); + checkForPlayAfterQueue(mc, cc, numAlreadyQueued); + } + }); + } + + /** + * Adds all songs of a genre to the current playlist. If current playlist is stopped, + * play is executed. Value is the first song of the added album. + * + * @param response Response object + * @param genre Genre of songs to add + */ + public void addToPlaylist(final DataResponse response, final Genre genre, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); + response.value = mc.addToPlaylist(MusicManager.this, genre, getSortBy(SortType.ARTIST), + getSortOrder()); + checkForPlayAfterQueue(mc, cc, numAlreadyQueued); + } + }); + } + + /** + * Adds a song to the current playlist. Even if the playlist is empty, only this song will be added. + * + * @param response Response object + * @param song Song to add + */ + public void addToPlaylist(final DataResponse response, final Song song, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).addToPlaylist(MusicManager.this, song); + } + }); + } + + /** + * Adds a song to the current playlist. If the playlist is empty, the whole + * album will be added with this song playing, otherwise only this song is + * added. + *

+ * Attention, the response.value result is different as usual: True + * means the whole album was added, false means ony the song. + * + * @param response Response object + * @param album Album to add + * @param song Song to play + */ + public void addToPlaylist(final DataResponse response, final Album album, final Song song, + final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + final int playStatus = cc.getPlayState(MusicManager.this); + //cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); + final int playlistSize = mc.getPlaylistSize(MusicManager.this); + int playPos = -1; + if (playlistSize == 0) { // if playlist is empty, add the whole album + int n = 0; + for (Song albumSong : mc.getSongs(MusicManager.this, album, getSortBy(PREF_SORT_KEY_ALBUM), + getSortOrder())) { + if (albumSong.id == song.id) { + playPos = n; + break; + } + n++; + } + mc.addToPlaylist(MusicManager.this, album, getSortBy(PREF_SORT_KEY_ALBUM), getSortOrder()); + response.value = true; + } else { // otherwise, only add the song + mc.addToPlaylist(MusicManager.this, song); + response.value = false; + } + if (playStatus == PlayStatus.STOPPED) { // if nothing is playing, play the song + if (playPos == 0) { + mc.playlistSetSong(MusicManager.this, playPos + 1); + mc.playPrev(MusicManager.this); + } else if (playPos > 0) { + mc.playlistSetSong(MusicManager.this, playPos - 1); + mc.playNext(MusicManager.this); + } else { + mc.playlistSetSong(MusicManager.this, playlistSize - 1); + mc.playNext(MusicManager.this); + } + } + } + }); + } + + /** + * Adds all songs from an artist to the playlist. If current playlist is + * stopped, the all songs of the artist are added to playlist and the first + * song is selected to play. If something is playing already, the songs are + * only queued. + * + * @param response Response object + * @param artist Artist + */ + public void addToPlaylist(final DataResponse response, final Artist artist, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); + response.value = mc.addToPlaylist(MusicManager.this, artist, getSortBy(SortType.ALBUM), + getSortOrder()); + checkForPlayAfterQueue(mc, cc, numAlreadyQueued); + } + }); + } + + /** + * Adds all songs of a genre from an artist to the playlist. If nothing is playing, + * the first song will be played, otherwise songs are just added to the playlist. + * + * @param response Response object + * @param artist Artist + * @param genre Genre + */ + public void addToPlaylist(final DataResponse response, final Artist artist, final Genre genre, + final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + final int numAlreadyQueued = mc.getPlaylistSize(MusicManager.this); + response.value = mc.addToPlaylist(MusicManager.this, artist, genre, getSortBy(SortType.ARTIST), + getSortOrder()); + checkForPlayAfterQueue(mc, cc, numAlreadyQueued); + } + }); + } + + /** + * Sets the media at playlist position position to be the next item to be played. + * + * @param response Response object + * @param position Position, starting with 0. + */ + public void setPlaylistSong(final DataResponse response, final int position, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).setPlaylistPosition(MusicManager.this, position); + } + }); + } + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param position Position to remove, starting with 0. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final int position, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).removeFromPlaylist(MusicManager.this, position); + } + }); + } + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final String path, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).removeFromPlaylist(MusicManager.this, path); + } + }); + } + + /** + * Plays an album + * + * @param response Response object + * @param album Album to play + */ + public void play(final DataResponse response, final Album album, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + control(context).stop(MusicManager.this); + response.value = music(context).play(MusicManager.this, album, getSortBy(SortType.TRACK), + getSortOrder()); + } + }); + } + + /** + * Plays all songs of a genre + * + * @param response Response object + * @param genre Genre of songs to play + */ + public void play(final DataResponse response, final Genre genre, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + control(context).stop(MusicManager.this); + response.value = music(context).play(MusicManager.this, genre, getSortBy(SortType.ARTIST), + getSortOrder()); + } + }); + } + + /** + * Plays a song + * + * @param response Response object + * @param song Song to play + */ + public void play(final DataResponse response, final Song song, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + control(context).stop(MusicManager.this); + response.value = music(context).play(MusicManager.this, song); + } + }); + } + + /** + * Plays a song, but the whole album is added to the playlist. + * + * @param response Response object + * @param album Album to queue + * @param song Song to play + */ + public void play(final DataResponse response, final Album album, final Song song, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + final IMusicClient mc = music(context); + final IControlClient cc = control(context); + int n = 0; + int playPos = 0; + mc.clearPlaylist(MusicManager.this); + for (Song albumSong : mc.getSongs(MusicManager.this, album, getSortBy(SortType.TRACK), + getSortOrder())) { + if (albumSong.id == song.id) { + playPos = n; + break; + } + n++; + } + cc.stop(MusicManager.this); + mc.addToPlaylist(MusicManager.this, album, getSortBy(SortType.TRACK), getSortOrder()); + if (playPos > 0) { + response.value = mc.playlistSetSong(MusicManager.this, playPos); + } else { + response.value = cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); + } + } + }); + } + + /** + * Plays all songs from an artist + * + * @param response Response object + * @param artist Artist whose songs to play + */ + public void play(final DataResponse response, final Artist artist, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + control(context).stop(MusicManager.this); + response.value = music(context).play(MusicManager.this, artist, getSortBy(SortType.ALBUM), + getSortOrder()); + } + }); + } + + /** + * Plays songs of a genre from an artist + * + * @param response Response object + * @param artist Artist whose songs to play + * @param genre Genre filter + */ + public void play(final DataResponse response, final Artist artist, final Genre genre, + final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + control(context).stop(MusicManager.this); + response.value = music(context).play(MusicManager.this, artist, genre); + } + }); + } + + + /** + * Starts playing the next media in the current playlist. + * + * @param response Response object + */ + public void playlistNext(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).playNext(MusicManager.this); + } + }); + } + + /** + * Returns an array of songs on the playlist. Empty array if nothing is playing. + * + * @param response Response object + */ + public void getPlaylist(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = music(context).getPlaylist(MusicManager.this); + final String firstEntry = response.value.get(0); + if (firstEntry != null && firstEntry.equals("[Empty]")) { + response.value = new ArrayList(); + } + } + }); + } + + /** + * Returns the position of the currently playing song in the playlist. First position is 0. + * + * @param response Response object + */ + public void getPlaylistPosition(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).getPlaylistPosition(MusicManager.this); + } + }); + } + + /** + * Updates the album object with additional data from the albuminfo table + * + * @param response Response object + * @param album Album to update + */ + public void updateAlbumInfo(final DataResponse response, final Album album, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).updateAlbumInfo(MusicManager.this, album); + } + }); + } + + /** + * Updates the artist object with additional data from the artistinfo table + * + * @param response Response object + * @param artist Artist to update + */ + public void updateArtistInfo(final DataResponse response, final Artist artist, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = music(context).updateArtistInfo(MusicManager.this, artist); + } + }); + } + + /** + * Checks if something's playing. If that's not the case, set the + * playlist's play position either to the start if there were no items + * before, or to the first position of the newly added files. + * + * @param mc Music client + * @param cc Control client + * @param numAlreadyQueued Number of previously queued items + */ + private void checkForPlayAfterQueue(final IMusicClient mc, final IControlClient cc, int numAlreadyQueued) { + final int ps = cc.getPlayState(MusicManager.this); + if (ps == PlayStatus.STOPPED) { // if nothing is playing, play the song + cc.setCurrentPlaylist(MusicManager.this, MusicClient.PLAYLIST_ID); + if (numAlreadyQueued == 0) { + mc.playNext(MusicManager.this); + } else { + mc.playlistSetSong(MusicManager.this, numAlreadyQueued); + } + } + } + + public void onWrongConnectionState(int state) { + // TODO Auto-generated method stub + + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/NowPlayingPollerThread.java b/app/src/main/java/org/xbmc/android/remote/business/NowPlayingPollerThread.java similarity index 92% rename from src/org/xbmc/android/remote/business/NowPlayingPollerThread.java rename to app/src/main/java/org/xbmc/android/remote/business/NowPlayingPollerThread.java index 61791308..6bad501e 100644 --- a/src/org/xbmc/android/remote/business/NowPlayingPollerThread.java +++ b/app/src/main/java/org/xbmc/android/remote/business/NowPlayingPollerThread.java @@ -21,10 +21,13 @@ package org.xbmc.android.remote.business; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.HashSet; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.util.Log; import org.xbmc.android.util.ClientFactory; import org.xbmc.android.util.HostFactory; @@ -37,19 +40,16 @@ import org.xbmc.api.object.Host; import org.xbmc.jsonrpc.Connection; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.util.Log; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.HashSet; /** * Activities (and other stuff) can subscribe to this thread in order to obtain * real-time "Now playing" information. The thread will send relevant messages * to all subscribers. If there are no subscriptions, nothing is polled. - * + *

* Please remember to unsubscribe (e.g. onPause()) in order to avoid unnecessary * polling. * @@ -57,41 +57,41 @@ */ public class NowPlayingPollerThread extends Thread { - private static final String TAG = "NowPlayingPollerThread"; - public static final String BUNDLE_CURRENTLY_PLAYING = "CurrentlyPlaying"; public static final String BUNDLE_LAST_PLAYLIST = "LastPlaylist"; public static final String BUNDLE_LAST_PLAYPOSITION = "LastPlayPosition"; - public static final int MESSAGE_CONNECTION_ERROR = 1; public static final int MESSAGE_RECONFIGURE = 2; public static final int MESSAGE_PROGRESS_CHANGED = 666; public static final int MESSAGE_PLAYLIST_ITEM_CHANGED = 667; public static final int MESSAGE_COVER_CHANGED = 668; public static final int MESSAGE_PLAYSTATE_CHANGED = 669; - - private IInfoClient mInfo; - private IControlClient mControl; + private static final String TAG = "NowPlayingPollerThread"; private final HashSet mSubscribers; - - private String mCoverPath; - private Bitmap mCover; - - private int mPlayList = -1; - private int mPosition = -1; - /** * Since this one is kinda of its own, we use a stub as manager. + * * @TODO create some toats or at least logs instead of empty on* methods. */ private final INotifiableManager mManagerStub; + private IInfoClient mInfo; + private IControlClient mControl; + private String mCoverPath; + private Bitmap mCover; + private int mPlayList = -1; + private int mPosition = -1; - public NowPlayingPollerThread(final Context context){ + public NowPlayingPollerThread(final Context context) { mManagerStub = new INotifiableManager() { - public void onMessage(int code, String message) { } - public void onMessage(String message) { } + public void onMessage(int code, String message) { + } + + public void onMessage(String message) { + } + public void onError(Exception e) { - // XXX link to context will eventually change if activity which created the thread changes (java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()) + // XXX link to context will eventually change if activity which created the thread changes (java.lang + // .RuntimeException: Can't create handler inside thread that has not called Looper.prepare()) //Toast toast = Toast.makeText(context, "Poller Error: " + e.getMessage(), Toast.LENGTH_LONG); //toast.show(); if (e.getMessage() != null) { @@ -99,10 +99,13 @@ public void onError(Exception e) { } e.printStackTrace(); } + public void onFinish(DataResponse response) { } + public void onWrongConnectionState(int state, Command cmd) { } + public void retryAll() { } }; @@ -131,13 +134,13 @@ public void subscribe(Handler handler) { } } - public void unSubscribe(Handler handler){ + public void unSubscribe(Handler handler) { synchronized (mSubscribers) { mSubscribers.remove(handler); } } - public Bitmap getNowPlayingCover(){ + public Bitmap getNowPlayingCover() { return mCover; } @@ -208,18 +211,18 @@ public void run() { int currentMediaType = 0; IControlClient control = mControl; // use local reference for faster access HashSet subscribers; - while (!isInterrupted() ) { + while (!isInterrupted()) { synchronized (mSubscribers) { subscribers = new HashSet(mSubscribers); } - if (subscribers.size() > 0){ + if (subscribers.size() > 0) { /* if (!control.isConnected()) { sendEmptyMessage(MESSAGE_CONNECTION_ERROR); } else {*/ ICurrentlyPlaying currPlaying; - try{ + try { currPlaying = control.getCurrentlyPlaying(mManagerStub); - } catch(Exception e) { + } catch (Exception e) { e.printStackTrace(); sendEmptyMessage(MESSAGE_CONNECTION_ERROR); return; @@ -267,8 +270,7 @@ public void run() { sendMessage(MESSAGE_COVER_CHANGED, currPlaying); } } - } - else{ + } else { this.interrupt(); } try { @@ -284,13 +286,13 @@ public void run() { private byte[] download(String pathToDownload) throws IOException, URISyntaxException { Connection connection; final Host host = HostFactory.host; - if (host != null) { - connection = Connection.getInstance(host.addr, host.port); - connection.setAuth(host.user, host.pass); - } else { - connection = Connection.getInstance(null, 0); - } + if (host != null) { + connection = Connection.getInstance(host.addr, host.port); + connection.setAuth(host.user, host.pass); + } else { + connection = Connection.getInstance(null, 0); + } - return connection.download(pathToDownload); + return connection.download(pathToDownload); } } diff --git a/src/org/xbmc/android/remote/business/TvShowManager.java b/app/src/main/java/org/xbmc/android/remote/business/TvShowManager.java similarity index 81% rename from src/org/xbmc/android/remote/business/TvShowManager.java rename to app/src/main/java/org/xbmc/android/remote/business/TvShowManager.java index fe6411b6..a2764e92 100644 --- a/src/org/xbmc/android/remote/business/TvShowManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/TvShowManager.java @@ -1,6 +1,6 @@ package org.xbmc.android.remote.business; -import java.util.ArrayList; +import android.content.Context; import org.xbmc.api.business.DataResponse; import org.xbmc.api.business.INotifiableManager; @@ -14,13 +14,14 @@ import org.xbmc.api.type.SortType; import org.xbmc.httpapi.WifiStateException; -import android.content.Context; +import java.util.ArrayList; public class TvShowManager extends AbstractManager implements ITvShowManager, ISortableManager, INotifiableManager { /** * Gets all tv shows actors from database + * * @param response Response object */ public void getTvShowActors(final DataResponse> response, final Context context) { @@ -34,6 +35,7 @@ public void doRun() throws Exception { /** * Gets all tv show genres from database + * * @param response Response object */ public void getTvShowGenres(final DataResponse> response, final Context context) { @@ -47,50 +49,58 @@ public void doRun() throws Exception { /** * Gets all tv shows from database + * * @param response Response object */ public void getTvShows(final DataResponse> response, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - response.value = shows(context).getTvShows(TvShowManager.this, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); + response.value = shows(context).getTvShows(TvShowManager.this, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); } }); } - + /** * SYNCHRONOUSLY gets all tv shows from database + * * @return All tv shows in database */ public ArrayList getTvShows(Context context) { try { - return shows(context).getTvShows(TvShowManager.this, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); + return shows(context).getTvShows(TvShowManager.this, getSortBy(SortType.TITLE), getSortOrder(), + getHideWatched(context)); } catch (WifiStateException e) { TvShowManager.this.onError(e); } return new ArrayList(); } - + /** * SYNCHRONOUSLY gets all tv show seasons from database + * * @return All tv show seasons in database */ public ArrayList getAllSeasons(Context context) { try { - return shows(context).getSeasons(TvShowManager.this, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); + return shows(context).getSeasons(TvShowManager.this, getSortBy(SortType.TITLE), getSortOrder(), + getHideWatched(context)); } catch (WifiStateException e) { TvShowManager.this.onError(e); } return new ArrayList(); } - + /** * SYNCHRONOUSLY gets all tv show episodes from database + * * @return All tv show episodes in database */ public ArrayList getAllEpisodes(Context context) { try { - return shows(context).getEpisodes(TvShowManager.this, getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); + return shows(context).getEpisodes(TvShowManager.this, getSortBy(SortType.EPISODE_NUM), getSortOrder(), + getHideWatched(context)); } catch (WifiStateException e) { TvShowManager.this.onError(e); } @@ -99,54 +109,61 @@ public ArrayList getAllEpisodes(Context context) { /** * Gets all tv shows of a genre from database + * * @param response Response object - * @param genre Genre of the tv shows + * @param genre Genre of the tv shows */ public void getTvShows(final DataResponse> response, final Genre genre, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - response.value = shows(context).getTvShows(TvShowManager.this, genre, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); + response.value = shows(context).getTvShows(TvShowManager.this, genre, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); } }); } /** * Gets all tv shows of an actor from database + * * @param response Response object - * @param actor Actor of the tv shows + * @param actor Actor of the tv shows */ public void getTvShows(DataResponse> response, final Actor actor, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - mResponse.value = shows(context).getTvShows(TvShowManager.this, actor, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); + mResponse.value = shows(context).getTvShows(TvShowManager.this, actor, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); } }); } /** * Gets all episodes of a tv show from database + * * @param response Response object - * @param show TvShow the returning episodes belong to + * @param show TvShow the returning episodes belong to */ public void getEpisodes(DataResponse> response, - final TvShow show, final Context context) { + final TvShow show, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - mResponse.value = shows(context).getEpisodes(TvShowManager.this, show, getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); + mResponse.value = shows(context).getEpisodes(TvShowManager.this, show, getSortBy(SortType.EPISODE_NUM) + , getSortOrder(), getHideWatched(context)); } }); } /** * Gets all seasons of a tv show from database + * * @param response Response object - * @param show TvShow the returning seasons belong to + * @param show TvShow the returning seasons belong to */ public void getSeasons(DataResponse> response, - final TvShow show, final Context context) { + final TvShow show, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { @@ -157,40 +174,45 @@ public void doRun() throws Exception { /** * Gets all episodes of a season of a tv show from database + * * @param response Response object - * @param show TvShow the returning episodes belong to - * @param season Season the returning episodes belong to + * @param show TvShow the returning episodes belong to + * @param season Season the returning episodes belong to */ public void getEpisodes(DataResponse> response, - final TvShow show, final Season season, final Context context) { + final TvShow show, final Season season, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - mResponse.value = shows(context).getEpisodes(TvShowManager.this, show, season, getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); + mResponse.value = shows(context).getEpisodes(TvShowManager.this, show, season, + getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); } }); - + } /** * Gets all episodes of a season from database + * * @param response Response object - * @param season Season the returning episodes belong to + * @param season Season the returning episodes belong to */ public void getEpisodes(DataResponse> response, - final Season season, final Context context) { + final Season season, final Context context) { mHandler.post(new Command>(response, this) { @Override public void doRun() throws Exception { - mResponse.value = shows(context).getEpisodes(TvShowManager.this, season, getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); + mResponse.value = shows(context).getEpisodes(TvShowManager.this, season, + getSortBy(SortType.EPISODE_NUM), getSortOrder(), getHideWatched(context)); } }); } /** * Updates the episode object with additional data from the episodeview table + * * @param response Response object - * @param episode Episode to update + * @param episode Episode to update */ public void updateEpisodeDetails(DataResponse response, final Episode episode, final Context context) { mHandler.post(new Command(response, this) { @@ -203,8 +225,9 @@ public void doRun() throws Exception { /** * Updates the show object with additional data from the tvshow table + * * @param response Response object - * @param show TvShow to update + * @param show TvShow to update */ public void updateTvShowDetails(DataResponse response, final TvShow show, final Context context) { mHandler.post(new Command(response, this) { @@ -223,6 +246,6 @@ public void doRun() throws Exception { mResponse.value = shows(context).getRecentlyAddedEpisodes(TvShowManager.this, getHideWatched(context)); } }); - + } } diff --git a/src/org/xbmc/android/remote/business/VideoManager.java b/app/src/main/java/org/xbmc/android/remote/business/VideoManager.java similarity index 82% rename from src/org/xbmc/android/remote/business/VideoManager.java rename to app/src/main/java/org/xbmc/android/remote/business/VideoManager.java index 29c5c6ef..6cbbc452 100644 --- a/src/org/xbmc/android/remote/business/VideoManager.java +++ b/app/src/main/java/org/xbmc/android/remote/business/VideoManager.java @@ -1,263 +1,283 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business; - -import java.util.ArrayList; - -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Movie; -import org.xbmc.api.type.SortType; -import org.xbmc.httpapi.WifiStateException; - -import android.content.Context; - -/** - * Asynchronously wraps the {@link org.xbmc.httpapi.client.VideoClient} class. - * - * @author Team XBMC - */ -public class VideoManager extends AbstractManager implements IVideoManager, ISortableManager, INotifiableManager { - - /** - * Updates the movie object with additional data (plot, cast, etc) - * @param response Response object - * @param movie Movie - */ - public void updateMovieDetails(final DataResponse response, final Movie movie, final Context context) { - mHandler.post(new Command(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).updateMovieDetails(VideoManager.this, movie); - } - }); - } - - /** - * Gets all movies from database - * @param response Response object - */ - public void getMovies(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); - } - }); - } - - /** - * SYNCHRONOUSLY gets all movies from database - * @return All movies in database - */ - public ArrayList getMovies(final Context context) { - try { - return video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); - } catch (WifiStateException e) { - e.printStackTrace(); - } - return null; - } - - /** - * SYNCHRONOUSLY gets movies from database with offset - * @return Movies in database with offset - */ - public ArrayList getMovies(final Context context, int offset) { - try { - return video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), getSortOrder(), offset, getHideWatched(context)); - } catch (WifiStateException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Gets all movies with an actor from database - * @param response Response object - * @param actor Actor - */ - public void getMovies(final DataResponse> response, final Actor actor, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getMovies(VideoManager.this, actor, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); - } - }); - } - - /** - * Gets all movies of a genre from database - * @param response Response object - * @param genre Genre - */ - public void getMovies(final DataResponse> response, final Genre genre, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getMovies(VideoManager.this, genre, getSortBy(SortType.TITLE), getSortOrder(), getHideWatched(context)); - } - }); - } - - /** - * Gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. - * @param response Response object - */ - public void getActors(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getActors(VideoManager.this); - } - }); - } - - /** - * SYNCHRONOUSLY gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. - * @return All actors - */ - public ArrayList getActors(final Context context) { - try { - return video(context).getActors(VideoManager.this); - } catch (WifiStateException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Gets all movie actors from database - * @param response Response object - */ - public void getMovieActors(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getMovieActors(VideoManager.this); - } - }); - } - - /** - * Gets all TV show actors from database - * @param response Response object - */ - public void getTvShowActors(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getTvShowActors(VideoManager.this); - } - }); - } - - /** - * Gets all movie genres from database - * @param response Response object - */ - public void getMovieGenres(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - response.value = video(context).getMovieGenres(VideoManager.this); - } - }); - } - - public void onWrongConnectionState(int state) { - // TODO Auto-generated method stub - - } - - public void getTvShowGenres(DataResponse> response, - final Context context) { - mHandler.post(new Command>(response, this) { - @Override - public void doRun() throws Exception { - mResponse.value = video(context).getTvShowGenres(VideoManager.this); - } - }); - } - - /** - * Sets the media at playlist position to be the next item to be played. - * @param response Response object - * @param position Position, starting with 0. - */ - public void setPlaylistVideo(final DataResponse response, final int position, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = video(context).setPlaylistPosition(VideoManager.this, position); - } - }); - } - - /** - * Returns an array of videos on the playlist. Empty array if nothing is playing. - * @param response Response object - */ - public void getPlaylist(final DataResponse> response, final Context context) { - mHandler.post(new Command>(response, this) { - public void doRun() throws Exception{ - response.value = video(context).getPlaylist(VideoManager.this); - if (response.value.size() > 0) { - final String firstEntry = response.value.get(0); - if (firstEntry != null && firstEntry.equals("[Empty]")) { - response.value = new ArrayList(); - } - } - } - }); - } - - /** - * Returns the position of the currently playing video in the playlist. First position is 0. - * @param response Response object - */ - public void getPlaylistPosition(final DataResponse response, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = video(context).getPlaylistPosition(VideoManager.this); - } - }); - } - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final String path, final Context context) { - mHandler.post(new Command(response, this) { - public void doRun() throws Exception{ - response.value = video(context).removeFromPlaylist(VideoManager.this, path); - } - }); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business; + +import android.content.Context; + +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Movie; +import org.xbmc.api.type.SortType; +import org.xbmc.httpapi.WifiStateException; + +import java.util.ArrayList; + +/** + * Asynchronously wraps the {@link org.xbmc.httpapi.client.VideoClient} class. + * + * @author Team XBMC + */ +public class VideoManager extends AbstractManager implements IVideoManager, ISortableManager, INotifiableManager { + + /** + * Updates the movie object with additional data (plot, cast, etc) + * + * @param response Response object + * @param movie Movie + */ + public void updateMovieDetails(final DataResponse response, final Movie movie, final Context context) { + mHandler.post(new Command(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).updateMovieDetails(VideoManager.this, movie); + } + }); + } + + /** + * Gets all movies from database + * + * @param response Response object + */ + public void getMovies(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); + } + }); + } + + /** + * SYNCHRONOUSLY gets all movies from database + * + * @return All movies in database + */ + public ArrayList getMovies(final Context context) { + try { + return video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), getSortOrder(), + getHideWatched(context)); + } catch (WifiStateException e) { + e.printStackTrace(); + } + return null; + } + + /** + * SYNCHRONOUSLY gets movies from database with offset + * + * @return Movies in database with offset + */ + public ArrayList getMovies(final Context context, int offset) { + try { + return video(context).getMovies(VideoManager.this, getSortBy(SortType.TITLE), getSortOrder(), offset, + getHideWatched(context)); + } catch (WifiStateException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Gets all movies with an actor from database + * + * @param response Response object + * @param actor Actor + */ + public void getMovies(final DataResponse> response, final Actor actor, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getMovies(VideoManager.this, actor, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); + } + }); + } + + /** + * Gets all movies of a genre from database + * + * @param response Response object + * @param genre Genre + */ + public void getMovies(final DataResponse> response, final Genre genre, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getMovies(VideoManager.this, genre, getSortBy(SortType.TITLE), + getSortOrder(), getHideWatched(context)); + } + }); + } + + /** + * Gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * + * @param response Response object + */ + public void getActors(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getActors(VideoManager.this); + } + }); + } + + /** + * SYNCHRONOUSLY gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * + * @return All actors + */ + public ArrayList getActors(final Context context) { + try { + return video(context).getActors(VideoManager.this); + } catch (WifiStateException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Gets all movie actors from database + * + * @param response Response object + */ + public void getMovieActors(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getMovieActors(VideoManager.this); + } + }); + } + + /** + * Gets all TV show actors from database + * + * @param response Response object + */ + public void getTvShowActors(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getTvShowActors(VideoManager.this); + } + }); + } + + /** + * Gets all movie genres from database + * + * @param response Response object + */ + public void getMovieGenres(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + response.value = video(context).getMovieGenres(VideoManager.this); + } + }); + } + + public void onWrongConnectionState(int state) { + // TODO Auto-generated method stub + + } + + public void getTvShowGenres(DataResponse> response, + final Context context) { + mHandler.post(new Command>(response, this) { + @Override + public void doRun() throws Exception { + mResponse.value = video(context).getTvShowGenres(VideoManager.this); + } + }); + } + + /** + * Sets the media at playlist position to be the next item to be played. + * + * @param response Response object + * @param position Position, starting with 0. + */ + public void setPlaylistVideo(final DataResponse response, final int position, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = video(context).setPlaylistPosition(VideoManager.this, position); + } + }); + } + + /** + * Returns an array of videos on the playlist. Empty array if nothing is playing. + * + * @param response Response object + */ + public void getPlaylist(final DataResponse> response, final Context context) { + mHandler.post(new Command>(response, this) { + public void doRun() throws Exception { + response.value = video(context).getPlaylist(VideoManager.this); + if (response.value.size() > 0) { + final String firstEntry = response.value.get(0); + if (firstEntry != null && firstEntry.equals("[Empty]")) { + response.value = new ArrayList(); + } + } + } + }); + } + + /** + * Returns the position of the currently playing video in the playlist. First position is 0. + * + * @param response Response object + */ + public void getPlaylistPosition(final DataResponse response, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = video(context).getPlaylistPosition(VideoManager.this); + } + }); + } + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final String path, final Context context) { + mHandler.post(new Command(response, this) { + public void doRun() throws Exception { + response.value = video(context).removeFromPlaylist(VideoManager.this, path); + } + }); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/provider/HostProvider.java b/app/src/main/java/org/xbmc/android/remote/business/provider/HostProvider.java similarity index 73% rename from src/org/xbmc/android/remote/business/provider/HostProvider.java rename to app/src/main/java/org/xbmc/android/remote/business/provider/HostProvider.java index 9029a0b3..0abc0918 100644 --- a/src/org/xbmc/android/remote/business/provider/HostProvider.java +++ b/app/src/main/java/org/xbmc/android/remote/business/provider/HostProvider.java @@ -1,443 +1,429 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business.provider; - -import java.util.HashMap; - -import android.content.ContentProvider; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.UriMatcher; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.database.sqlite.SQLiteQueryBuilder; -import android.net.Uri; -import android.provider.BaseColumns; -import android.text.TextUtils; -import android.util.Log; - -public class HostProvider extends ContentProvider { - - private static final String TAG = "HostProvider"; - - public static final String AUTHORITY = "org.xbmc.android.provider.remote"; - - private static final int DATABASE_VERSION = 4; - private static final String DATABASE_NAME = "xbmc_hosts.db"; - private static final String HOSTS_TABLE_NAME = "hosts"; - - private static HashMap sHostsProjectionMap; - - private static final int HOSTS = 1; - private static final int HOST_ID = 2; - - private static final UriMatcher sUriMatcher; - - /** - * This class helps open, create, and upgrade the database file. - */ - private static class DatabaseHelper extends SQLiteOpenHelper { - - DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + HOSTS_TABLE_NAME + " (" - + Hosts._ID + " INTEGER PRIMARY KEY," - + Hosts.NAME + " TEXT," - + Hosts.ADDR + " TEXT," - + Hosts.PORT + " INTEGER," - + Hosts.USER + " TEXT," - + Hosts.PASS + " TEXT," - + Hosts.ESPORT + " INTEGER," - + Hosts.TIMEOUT + " INTEGER," - + Hosts.WIFI_ONLY + " INTEGER," - + Hosts.ACCESS_POINT + " TEXT," - + Hosts.MAC_ADDR + " TEXT," - + Hosts.WOL_PORT + " INTEGER," - + Hosts.WOL_WAIT + " INTEGER" - + ");"); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - String altertable; - switch (oldVersion) { - case 2: - Log.d(TAG, "Upgrading database from version 2 to 3"); - altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WIFI_ONLY - + " INTEGER DEFAULT 0;"; - db.execSQL(altertable); - Log.d(TAG, "executed: " + altertable); - altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.ACCESS_POINT - + " TEXT;"; - db.execSQL(altertable); - Log.d(TAG, "executed: " + altertable); - altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.MAC_ADDR - + " TEXT;"; - db.execSQL(altertable); - Log.d(TAG, "executed: " + altertable); - case 3: - Log.d(TAG, "Upgrading database from version 3 to 4"); - altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WOL_PORT - + " INTEGER;"; - db.execSQL(altertable); - Log.d(TAG, "executed: " + altertable); - altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WOL_WAIT - + " INTEGER;"; - db.execSQL(altertable); - Log.d(TAG, "executed: " + altertable); - - //WARNING!!! ADD A break; BEFORE THE DEFAULT BLOCK OF THE DATABASE WILL BE DROPPED!!! - break; - default: - Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", which will destroy all old data"); - db.execSQL("DROP TABLE IF EXISTS " + HOSTS_TABLE_NAME); - onCreate(db); - - } - } - } - - private DatabaseHelper mOpenHelper; - - @Override - public boolean onCreate() { - mOpenHelper = new DatabaseHelper(getContext()); - return true; - } - - @Override - public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); - - switch (sUriMatcher.match(uri)) { - case HOSTS: - qb.setTables(HOSTS_TABLE_NAME); - qb.setProjectionMap(sHostsProjectionMap); - break; - - case HOST_ID: - qb.setTables(HOSTS_TABLE_NAME); - qb.setProjectionMap(sHostsProjectionMap); - qb.appendWhere(Hosts._ID + "=" + uri.getPathSegments().get(1)); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - - // If no sort order is specified use the default - String orderBy; - if (TextUtils.isEmpty(sortOrder)) { - orderBy = Hosts.DEFAULT_SORT_ORDER; - } else { - orderBy = sortOrder; - } - - // Get the database and run the query - SQLiteDatabase db = mOpenHelper.getReadableDatabase(); - Log.d(TAG, "SQLite database version: " + db.getVersion()); - Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); - - // Tell the cursor what uri to watch, so it knows when its source data - // changes - c.setNotificationUri(getContext().getContentResolver(), uri); - return c; - } - - @Override - public String getType(Uri uri) { - switch (sUriMatcher.match(uri)) { - case HOSTS: - return Hosts.CONTENT_TYPE; - - case HOST_ID: - return Hosts.CONTENT_ITEM_TYPE; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - } - - @Override - public Uri insert(Uri uri, ContentValues initialValues) { - // Validate the requested uri - if (sUriMatcher.match(uri) != HOSTS) { - throw new IllegalArgumentException("Unknown URI " + uri); - } - - ContentValues values; - if (initialValues != null) { - values = new ContentValues(initialValues); - } else { - values = new ContentValues(); - } - - if (values.containsKey(Hosts.NAME) == false) { - Resources r = Resources.getSystem(); - values.put(Hosts.NAME, r.getString(android.R.string.untitled)); - } - - if (values.containsKey(Hosts.ADDR) == false) { - values.put(Hosts.ADDR, ""); - } - if (values.containsKey(Hosts.PORT) == false) { - values.put(Hosts.PORT, 0); - } - if (values.containsKey(Hosts.USER) == false) { - values.put(Hosts.USER, ""); - } - if (values.containsKey(Hosts.PASS) == false) { - values.put(Hosts.PASS, ""); - } - if (values.containsKey(Hosts.ESPORT) == false) { - values.put(Hosts.ESPORT, 0); - } - if (values.containsKey(Hosts.TIMEOUT) == false) { - values.put(Hosts.TIMEOUT, -1); - } - if (values.containsKey(Hosts.WIFI_ONLY) == false) { - values.put(Hosts.WIFI_ONLY, 0); - } - if (values.containsKey(Hosts.ACCESS_POINT) == false) { - values.put(Hosts.ACCESS_POINT, ""); - } - if (values.containsKey(Hosts.MAC_ADDR) == false) { - values.put(Hosts.MAC_ADDR, ""); - } - if (values.containsKey(Hosts.WOL_PORT) == false) { - values.put(Hosts.WOL_PORT, 0); - } - if (values.containsKey(Hosts.WOL_WAIT) == false) { - values.put(Hosts.WOL_WAIT, 0); - } - - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - long rowId = db.insert(HOSTS_TABLE_NAME, Hosts.ADDR, values); - if (rowId > 0) { - Uri noteUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, rowId); - getContext().getContentResolver().notifyChange(noteUri, null); - return noteUri; - } - throw new SQLException("Failed to insert row into " + uri); - } - - @Override - public int delete(Uri uri, String where, String[] whereArgs) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count; - switch (sUriMatcher.match(uri)) { - case HOSTS: - count = db.delete(HOSTS_TABLE_NAME, where, whereArgs); - break; - - case HOST_ID: - String hostId = uri.getPathSegments().get(1); - count = db.delete(HOSTS_TABLE_NAME, Hosts._ID + "=" + hostId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - - getContext().getContentResolver().notifyChange(uri, null); - return count; - } - - @Override - public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { - SQLiteDatabase db = mOpenHelper.getWritableDatabase(); - int count; - switch (sUriMatcher.match(uri)) { - case HOSTS: - count = db.update(HOSTS_TABLE_NAME, values, where, whereArgs); - break; - - case HOST_ID: - String hostId = uri.getPathSegments().get(1); - count = db.update(HOSTS_TABLE_NAME, values, Hosts._ID + "=" + hostId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); - break; - - default: - throw new IllegalArgumentException("Unknown URI " + uri); - } - - getContext().getContentResolver().notifyChange(uri, null); - return count; - } - - static { - sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); - sUriMatcher.addURI(AUTHORITY, "hosts", HOSTS); - sUriMatcher.addURI(AUTHORITY, "hosts/#", HOST_ID); - - sHostsProjectionMap = new HashMap(); - sHostsProjectionMap.put(Hosts._ID, Hosts._ID); - sHostsProjectionMap.put(Hosts.NAME, Hosts.NAME); - sHostsProjectionMap.put(Hosts.ADDR, Hosts.ADDR); - sHostsProjectionMap.put(Hosts.PORT, Hosts.PORT); - sHostsProjectionMap.put(Hosts.USER, Hosts.USER); - sHostsProjectionMap.put(Hosts.PASS, Hosts.PASS); - sHostsProjectionMap.put(Hosts.ESPORT, Hosts.ESPORT); - sHostsProjectionMap.put(Hosts.TIMEOUT, Hosts.TIMEOUT); - sHostsProjectionMap.put(Hosts.WIFI_ONLY, Hosts.WIFI_ONLY); - sHostsProjectionMap.put(Hosts.ACCESS_POINT, Hosts.ACCESS_POINT); - sHostsProjectionMap.put(Hosts.MAC_ADDR, Hosts.MAC_ADDR); - sHostsProjectionMap.put(Hosts.WOL_PORT, Hosts.WOL_PORT); - sHostsProjectionMap.put(Hosts.WOL_WAIT, Hosts.WOL_WAIT); - } - - /** - * Notes table - */ - public static final class Hosts implements BaseColumns { - - // This class cannot be instantiated - private Hosts() { - } - - /** - * The name of the host (as in label/title) - *

- * Type: TEXT - *

- */ - public static final String NAME = "name"; - - /** - * The address or IP of the host - *

- * Type: TEXT - *

- */ - public static final String ADDR = "address"; - - /** - * The note itself - *

- * Type: INTEGER - *

- */ - public static final String PORT = "http_port"; - - /** - * The user name if HTTP Auth is used - *

- * Type: TEXT - *

- */ - public static final String USER = "user"; - - /** - * The password if HTTP Auth is used - *

- * Type: TEXT - *

- */ - public static final String PASS = "pass"; - - /** - * The event server port - *

- * Type: INTEGER - *

- */ - public static final String ESPORT = "esport"; - - /** - * The socket read timeout in milliseconds - *

- * Type: INTEGER - *

- */ - public static final String TIMEOUT = "timeout"; - - /** - * If this connection is for wireless lan only - *

- * Type: BOOLEAN - *

- */ - public static final String WIFI_ONLY = "wifi_only"; - - /** - * If WIFI_ONLY is set this may or may not include an access point name - *

- * Type: TEXT - *

- */ - public static final String ACCESS_POINT = "access_point"; - - /** - * The MAC address of this host - *

- * Type: TEXT - *

- */ - public static final String MAC_ADDR = "mac_addr"; - - /** - * The time in seconds to wait after sending WOL paket - *

- * Type: INTEGER - *

- */ - public static final String WOL_WAIT = "wol_wait"; - - /** - * The port the WOL packet should be send to - *

- * Type: INTEGER - *

- */ - public static final String WOL_PORT = "wol_port"; - - /** - * The content:// style URL for this table - */ - public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + HOSTS_TABLE_NAME); - - /** - * The MIME type of {@link #CONTENT_URI} providing a directory of notes. - */ - public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.xbmc.host"; - - /** - * The MIME type of a {@link #CONTENT_URI} sub-directory of a single - * note. - */ - public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.xbmc.host"; - - /** - * The default sort order for this table - */ - public static final String DEFAULT_SORT_ORDER = NAME + " ASC"; - - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business.provider; + +import android.content.ContentProvider; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.UriMatcher; +import android.content.res.Resources; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteQueryBuilder; +import android.net.Uri; +import android.provider.BaseColumns; +import android.text.TextUtils; +import android.util.Log; + +import java.util.HashMap; + +public class HostProvider extends ContentProvider { + + public static final String AUTHORITY = "org.xbmc.android.provider.remote"; + private static final String TAG = "HostProvider"; + private static final int DATABASE_VERSION = 4; + private static final String DATABASE_NAME = "xbmc_hosts.db"; + private static final String HOSTS_TABLE_NAME = "hosts"; + private static final int HOSTS = 1; + private static final int HOST_ID = 2; + private static final UriMatcher sUriMatcher; + private static HashMap sHostsProjectionMap; + private DatabaseHelper mOpenHelper; + + @Override + public boolean onCreate() { + mOpenHelper = new DatabaseHelper(getContext()); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); + + switch (sUriMatcher.match(uri)) { + case HOSTS: + qb.setTables(HOSTS_TABLE_NAME); + qb.setProjectionMap(sHostsProjectionMap); + break; + + case HOST_ID: + qb.setTables(HOSTS_TABLE_NAME); + qb.setProjectionMap(sHostsProjectionMap); + qb.appendWhere(Hosts._ID + "=" + uri.getPathSegments().get(1)); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + + // If no sort order is specified use the default + String orderBy; + if (TextUtils.isEmpty(sortOrder)) { + orderBy = Hosts.DEFAULT_SORT_ORDER; + } else { + orderBy = sortOrder; + } + + // Get the database and run the query + SQLiteDatabase db = mOpenHelper.getReadableDatabase(); + Log.d(TAG, "SQLite database version: " + db.getVersion()); + Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); + + // Tell the cursor what uri to watch, so it knows when its source data + // changes + c.setNotificationUri(getContext().getContentResolver(), uri); + return c; + } + + @Override + public String getType(Uri uri) { + switch (sUriMatcher.match(uri)) { + case HOSTS: + return Hosts.CONTENT_TYPE; + + case HOST_ID: + return Hosts.CONTENT_ITEM_TYPE; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + } + + @Override + public Uri insert(Uri uri, ContentValues initialValues) { + // Validate the requested uri + if (sUriMatcher.match(uri) != HOSTS) { + throw new IllegalArgumentException("Unknown URI " + uri); + } + + ContentValues values; + if (initialValues != null) { + values = new ContentValues(initialValues); + } else { + values = new ContentValues(); + } + + if (values.containsKey(Hosts.NAME) == false) { + Resources r = Resources.getSystem(); + values.put(Hosts.NAME, r.getString(android.R.string.untitled)); + } + + if (values.containsKey(Hosts.ADDR) == false) { + values.put(Hosts.ADDR, ""); + } + if (values.containsKey(Hosts.PORT) == false) { + values.put(Hosts.PORT, 0); + } + if (values.containsKey(Hosts.USER) == false) { + values.put(Hosts.USER, ""); + } + if (values.containsKey(Hosts.PASS) == false) { + values.put(Hosts.PASS, ""); + } + if (values.containsKey(Hosts.ESPORT) == false) { + values.put(Hosts.ESPORT, 0); + } + if (values.containsKey(Hosts.TIMEOUT) == false) { + values.put(Hosts.TIMEOUT, -1); + } + if (values.containsKey(Hosts.WIFI_ONLY) == false) { + values.put(Hosts.WIFI_ONLY, 0); + } + if (values.containsKey(Hosts.ACCESS_POINT) == false) { + values.put(Hosts.ACCESS_POINT, ""); + } + if (values.containsKey(Hosts.MAC_ADDR) == false) { + values.put(Hosts.MAC_ADDR, ""); + } + if (values.containsKey(Hosts.WOL_PORT) == false) { + values.put(Hosts.WOL_PORT, 0); + } + if (values.containsKey(Hosts.WOL_WAIT) == false) { + values.put(Hosts.WOL_WAIT, 0); + } + + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + long rowId = db.insert(HOSTS_TABLE_NAME, Hosts.ADDR, values); + if (rowId > 0) { + Uri noteUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, rowId); + getContext().getContentResolver().notifyChange(noteUri, null); + return noteUri; + } + throw new SQLException("Failed to insert row into " + uri); + } + + @Override + public int delete(Uri uri, String where, String[] whereArgs) { + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count; + switch (sUriMatcher.match(uri)) { + case HOSTS: + count = db.delete(HOSTS_TABLE_NAME, where, whereArgs); + break; + + case HOST_ID: + String hostId = uri.getPathSegments().get(1); + count = db.delete(HOSTS_TABLE_NAME, Hosts._ID + "=" + hostId + (!TextUtils.isEmpty(where) ? " AND (" + + where + ')' : ""), whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + @Override + public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { + SQLiteDatabase db = mOpenHelper.getWritableDatabase(); + int count; + switch (sUriMatcher.match(uri)) { + case HOSTS: + count = db.update(HOSTS_TABLE_NAME, values, where, whereArgs); + break; + + case HOST_ID: + String hostId = uri.getPathSegments().get(1); + count = db.update(HOSTS_TABLE_NAME, values, Hosts._ID + "=" + hostId + (!TextUtils.isEmpty(where) ? + "" + + " " + + "AND (" + where + ')' : ""), whereArgs); + break; + + default: + throw new IllegalArgumentException("Unknown URI " + uri); + } + + getContext().getContentResolver().notifyChange(uri, null); + return count; + } + + static { + sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + sUriMatcher.addURI(AUTHORITY, "hosts", HOSTS); + sUriMatcher.addURI(AUTHORITY, "hosts/#", HOST_ID); + + sHostsProjectionMap = new HashMap(); + sHostsProjectionMap.put(Hosts._ID, Hosts._ID); + sHostsProjectionMap.put(Hosts.NAME, Hosts.NAME); + sHostsProjectionMap.put(Hosts.ADDR, Hosts.ADDR); + sHostsProjectionMap.put(Hosts.PORT, Hosts.PORT); + sHostsProjectionMap.put(Hosts.USER, Hosts.USER); + sHostsProjectionMap.put(Hosts.PASS, Hosts.PASS); + sHostsProjectionMap.put(Hosts.ESPORT, Hosts.ESPORT); + sHostsProjectionMap.put(Hosts.TIMEOUT, Hosts.TIMEOUT); + sHostsProjectionMap.put(Hosts.WIFI_ONLY, Hosts.WIFI_ONLY); + sHostsProjectionMap.put(Hosts.ACCESS_POINT, Hosts.ACCESS_POINT); + sHostsProjectionMap.put(Hosts.MAC_ADDR, Hosts.MAC_ADDR); + sHostsProjectionMap.put(Hosts.WOL_PORT, Hosts.WOL_PORT); + sHostsProjectionMap.put(Hosts.WOL_WAIT, Hosts.WOL_WAIT); + } + + /** + * This class helps open, create, and upgrade the database file. + */ + private static class DatabaseHelper extends SQLiteOpenHelper { + + DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + db.execSQL("CREATE TABLE " + HOSTS_TABLE_NAME + " (" + + Hosts._ID + " INTEGER PRIMARY KEY," + + Hosts.NAME + " TEXT," + + Hosts.ADDR + " TEXT," + + Hosts.PORT + " INTEGER," + + Hosts.USER + " TEXT," + + Hosts.PASS + " TEXT," + + Hosts.ESPORT + " INTEGER," + + Hosts.TIMEOUT + " INTEGER," + + Hosts.WIFI_ONLY + " INTEGER," + + Hosts.ACCESS_POINT + " TEXT," + + Hosts.MAC_ADDR + " TEXT," + + Hosts.WOL_PORT + " INTEGER," + + Hosts.WOL_WAIT + " INTEGER" + + ");"); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + String altertable; + switch (oldVersion) { + case 2: + Log.d(TAG, "Upgrading database from version 2 to 3"); + altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WIFI_ONLY + + " INTEGER DEFAULT 0;"; + db.execSQL(altertable); + Log.d(TAG, "executed: " + altertable); + altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.ACCESS_POINT + + " TEXT;"; + db.execSQL(altertable); + Log.d(TAG, "executed: " + altertable); + altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.MAC_ADDR + + " TEXT;"; + db.execSQL(altertable); + Log.d(TAG, "executed: " + altertable); + case 3: + Log.d(TAG, "Upgrading database from version 3 to 4"); + altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WOL_PORT + + " INTEGER;"; + db.execSQL(altertable); + Log.d(TAG, "executed: " + altertable); + altertable = "ALTER TABLE " + HOSTS_TABLE_NAME + " ADD COLUMN " + Hosts.WOL_WAIT + + " INTEGER;"; + db.execSQL(altertable); + Log.d(TAG, "executed: " + altertable); + + //WARNING!!! ADD A break; BEFORE THE DEFAULT BLOCK OF THE DATABASE WILL BE DROPPED!!! + break; + default: + Log.w(TAG, "Upgrading database from version " + oldVersion + " to " + newVersion + ", " + + "which will destroy all old data"); + db.execSQL("DROP TABLE IF EXISTS " + HOSTS_TABLE_NAME); + onCreate(db); + + } + } + } + + /** + * Notes table + */ + public static final class Hosts implements BaseColumns { + + /** + * The name of the host (as in label/title) + *

+ * Type: TEXT + *

+ */ + public static final String NAME = "name"; + /** + * The address or IP of the host + *

+ * Type: TEXT + *

+ */ + public static final String ADDR = "address"; + /** + * The note itself + *

+ * Type: INTEGER + *

+ */ + public static final String PORT = "http_port"; + /** + * The user name if HTTP Auth is used + *

+ * Type: TEXT + *

+ */ + public static final String USER = "user"; + /** + * The password if HTTP Auth is used + *

+ * Type: TEXT + *

+ */ + public static final String PASS = "pass"; + /** + * The event server port + *

+ * Type: INTEGER + *

+ */ + public static final String ESPORT = "esport"; + /** + * The socket read timeout in milliseconds + *

+ * Type: INTEGER + *

+ */ + public static final String TIMEOUT = "timeout"; + /** + * If this connection is for wireless lan only + *

+ * Type: BOOLEAN + *

+ */ + public static final String WIFI_ONLY = "wifi_only"; + /** + * If WIFI_ONLY is set this may or may not include an access point name + *

+ * Type: TEXT + *

+ */ + public static final String ACCESS_POINT = "access_point"; + /** + * The MAC address of this host + *

+ * Type: TEXT + *

+ */ + public static final String MAC_ADDR = "mac_addr"; + /** + * The time in seconds to wait after sending WOL paket + *

+ * Type: INTEGER + *

+ */ + public static final String WOL_WAIT = "wol_wait"; + /** + * The port the WOL packet should be send to + *

+ * Type: INTEGER + *

+ */ + public static final String WOL_PORT = "wol_port"; + /** + * The MIME type of {@link #CONTENT_URI} providing a directory of notes. + */ + public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.xbmc.host"; + /** + * The MIME type of a {@link #CONTENT_URI} sub-directory of a single + * note. + */ + public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.xbmc.host"; + /** + * The default sort order for this table + */ + public static final String DEFAULT_SORT_ORDER = NAME + " ASC"; + + // This class cannot be instantiated + private Hosts() { + } + + /** + * The content:// style URL for this table + */ + public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/" + HOSTS_TABLE_NAME); + + + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java b/app/src/main/java/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java similarity index 87% rename from src/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java rename to app/src/main/java/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java index 844d6f58..7ab65a38 100644 --- a/src/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java +++ b/app/src/main/java/org/xbmc/android/remote/business/receiver/AndroidBroadcastReceiver.java @@ -21,8 +21,19 @@ package org.xbmc.android.remote.business.receiver; -import java.io.ByteArrayOutputStream; -import java.io.IOException; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Resources.NotFoundException; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.Contacts; import org.xbmc.android.remote.R; import org.xbmc.android.remote.business.Command; @@ -39,19 +50,8 @@ import org.xbmc.eventclient.ButtonCodes; import org.xbmc.eventclient.Packet; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.res.Resources.NotFoundException; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.provider.Contacts; +import java.io.ByteArrayOutputStream; +import java.io.IOException; @SuppressWarnings("deprecation") public class AndroidBroadcastReceiver extends BroadcastReceiver { @@ -62,9 +62,8 @@ public class AndroidBroadcastReceiver extends BroadcastReceiver { private static final String SMS_RECVEICED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; private static final int PLAY_STATE_NONE = -1; - private static final int PLAY_STATE_PAUSED = 0; - private static int sPlayState = PLAY_STATE_NONE; + private static final int PLAY_STATE_PAUSED = 0; @Override public void onReceive(Context context, Intent intent) { @@ -72,15 +71,16 @@ public void onReceive(Context context, Intent intent) { //(Don't know why this method should be called but we're safe this way ;)) PackageManager pm = context.getPackageManager(); boolean hasTelephony = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); - if(!hasTelephony) return; - + if (!hasTelephony) return; + String action = intent.getAction(); final IEventClientManager eventClient = ManagerFactory.getEventClientManager(null); final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); // currently no new connection to the event server is opened if (eventClient != null) { try { - if (action.equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED) && prefs.getBoolean("setting_show_call", false)) { + if (action.equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED) && prefs.getBoolean + ("setting_show_call", false)) { String extra = intent.getStringExtra(android.telephony.TelephonyManager.EXTRA_STATE); if (extra.equals(android.telephony.TelephonyManager.EXTRA_STATE_RINGING)) { @@ -99,7 +99,8 @@ public void onReceive(Context context, Intent intent) { // have to compress it Bitmap pic; if (id != null) - pic = Contacts.People.loadContactPhoto(context, Uri.withAppendedPath(Contacts.People.CONTENT_URI, id), R.drawable.icon, null); + pic = Contacts.People.loadContactPhoto(context, Uri.withAppendedPath(Contacts.People + .CONTENT_URI, id), R.drawable.icon, null); else pic = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon); ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -114,20 +115,24 @@ public void onReceive(Context context, Intent intent) { cm.getCurrentlyPlaying(new DataResponse() { public void run() { if (value != null && value.isPlaying()) { - eventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short) 0, (byte) 0); + eventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, + (short) 0, (byte) 0); sPlayState = PLAY_STATE_PAUSED; } } }, null); - eventClient.sendNotification(callername, "calling", Packet.ICON_PNG, pic == null ? null : os.toByteArray()); - + eventClient.sendNotification(callername, "calling", Packet.ICON_PNG, + pic == null ? null : os.toByteArray()); + } else if (extra.equals(android.telephony.TelephonyManager.EXTRA_STATE_IDLE)) { - + // phone state changed to idle, so if we paused the // playback before, we resume it now if (sPlayState == PLAY_STATE_PAUSED) { - eventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, true, true, true, (short) 0, (byte) 0); - eventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, false, true, (short) 0, (byte) 0); + eventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, true, true, true, (short) 0, + (byte) 0); + eventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, false, true, (short) 0, + (byte) 0); } sPlayState = PLAY_STATE_NONE; } @@ -142,16 +147,20 @@ public void run() { if (pic != null) { ByteArrayOutputStream os = new ByteArrayOutputStream(); pic.compress(Bitmap.CompressFormat.PNG, 0, os); - eventClient.sendNotification("SMS Received from " + msg.getContactName(), msg.getMessageBody(), Packet.ICON_PNG, os.toByteArray()); + eventClient.sendNotification("SMS Received from " + msg.getContactName(), + msg.getMessageBody(), Packet.ICON_PNG, os.toByteArray()); } else - eventClient.sendNotification("SMS Received from " + msg.getContactName(), msg.getMessageBody()); + eventClient.sendNotification("SMS Received from " + msg.getContactName(), + msg.getMessageBody()); } } - } else if (action.equals(Intent.ACTION_SCREEN_OFF) && prefs.getBoolean("setting_show_notification", false)) { - NowPlayingNotificationManager.getInstance(context).stopNotificating(); - } else if (action.equals(Intent.ACTION_SCREEN_ON) && prefs.getBoolean("setting_show_notification", false)) { - NowPlayingNotificationManager.getInstance(context).startNotificating(); - } + } else if (action.equals(Intent.ACTION_SCREEN_OFF) && prefs.getBoolean("setting_show_notification", + false)) { + NowPlayingNotificationManager.getInstance(context).stopNotificating(); + } else if (action.equals(Intent.ACTION_SCREEN_ON) && prefs.getBoolean("setting_show_notification", + false)) { + NowPlayingNotificationManager.getInstance(context).startNotificating(); + } } catch (NotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -161,15 +170,16 @@ public void run() { } } } - + public class NullNotifiableController implements INotifiableController { - + private Handler mHandler = null; + public NullNotifiableController(Handler handler) { mHandler = handler; } - + public void onError(Exception e) { // shoudln't come up } @@ -184,9 +194,9 @@ public void runOnUI(Runnable action) { public void onWrongConnectionState(int state, INotifiableManager manager, Command source) { // TODO Auto-generated method stub - + } - + } } diff --git a/src/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java b/app/src/main/java/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java similarity index 96% rename from src/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java rename to app/src/main/java/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java index f2035952..a23d8450 100644 --- a/src/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java +++ b/app/src/main/java/org/xbmc/android/remote/business/receiver/AutoStartReceiver.java @@ -1,57 +1,57 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.business.receiver; - -import org.xbmc.android.remote.presentation.activity.HomeActivity; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import android.util.Log; - -/** - * Received when XBMC starts - * - * @author Team-XBMC (thanks larry) - */ -public class AutoStartReceiver extends BroadcastReceiver { - - private static final String TAG = "AutoStartReceiver"; - - @Override - public void onReceive(Context context, Intent intent) { - - // Received intent only when the system boot is completed - Log.d(TAG, "onReceiveIntent"); - - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - boolean startupOnBoot = sharedPreferences.getBoolean("setting_startup_onboot", false); - if (startupOnBoot) { - Intent activityIntent = new Intent(context, HomeActivity.class); - activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(activityIntent); - } - } - -} +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.business.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Log; + +import org.xbmc.android.remote.presentation.activity.HomeActivity; + +/** + * Received when XBMC starts + * + * @author Team-XBMC (thanks larry) + */ +public class AutoStartReceiver extends BroadcastReceiver { + + private static final String TAG = "AutoStartReceiver"; + + @Override + public void onReceive(Context context, Intent intent) { + + // Received intent only when the system boot is completed + Log.d(TAG, "onReceiveIntent"); + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + boolean startupOnBoot = sharedPreferences.getBoolean("setting_startup_onboot", false); + if (startupOnBoot) { + Intent activityIntent = new Intent(context, HomeActivity.class); + activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(activityIntent); + } + } + +} diff --git a/src/org/xbmc/android/remote/presentation/activity/AboutActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/AboutActivity.java similarity index 80% rename from src/org/xbmc/android/remote/presentation/activity/AboutActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/AboutActivity.java index d8eebc8a..8f5eec16 100644 --- a/src/org/xbmc/android/remote/presentation/activity/AboutActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/AboutActivity.java @@ -1,92 +1,95 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.view.Display; -import android.view.KeyEvent; -import android.widget.TextView; - -public class AboutActivity extends Activity { - - private ConfigurationManager mConfigurationManager; - private IEventClientManager mEventClientManager; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.about); - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - try { - mEventClientManager = ManagerFactory.getEventClientManager(null); - final String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; - final int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; - ((TextView)findViewById(R.id.about_version)).setText("v" + versionName); - ((TextView)findViewById(R.id.about_revision)).setText("Revision " + versionCode); - TextView message = (TextView)findViewById(R.id.about_url_message); - - message.setText(Html.fromHtml("Visit our project page at Google Code.")); - message.setMovementMethod(LinkMovementMethod.getInstance()); - } catch (NameNotFoundException e) { - ((TextView)findViewById(R.id.about_version)).setText("Error reading version"); - } - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - @Override - protected void onResume() { - super.onResume(); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - return super.onKeyDown(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.text.Html; +import android.text.method.LinkMovementMethod; +import android.view.Display; +import android.view.KeyEvent; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +public class AboutActivity extends Activity { + + private ConfigurationManager mConfigurationManager; + private IEventClientManager mEventClientManager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.about); + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + try { + mEventClientManager = ManagerFactory.getEventClientManager(null); + final String versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; + final int versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; + ((TextView) findViewById(R.id.about_version)).setText("v" + versionName); + ((TextView) findViewById(R.id.about_revision)).setText("Revision " + versionCode); + TextView message = (TextView) findViewById(R.id.about_url_message); + + message.setText(Html.fromHtml("Visit our project page at Google Code.")); + message.setMovementMethod(LinkMovementMethod.getInstance()); + } catch (NameNotFoundException e) { + ((TextView) findViewById(R.id.about_version)).setText("Error reading version"); + } + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + protected void onResume() { + super.onResume(); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, + (byte) 0); + return true; + } + return super.onKeyDown(keyCode, event); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/AbsListActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/AbsListActivity.java similarity index 87% rename from src/org/xbmc/android/remote/presentation/activity/AbsListActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/AbsListActivity.java index e79defda..ae938ac0 100644 --- a/src/org/xbmc/android/remote/presentation/activity/AbsListActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/AbsListActivity.java @@ -1,196 +1,197 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.ListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.os.Handler; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Display; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AbsListView; -import android.widget.FrameLayout; - -public abstract class AbsListActivity extends Activity { - - private static final int MENU_NOW_PLAYING = 501; - private static final int MENU_REMOTE = 502; - - protected ConfigurationManager mConfigurationManager; - - ListController mListController; - private KeyTracker mKeyTracker; - - public AbsListActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { - mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - - @Override - public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - onKeyLongPress(keyCode, event); - } - - @Override - public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - callSuperOnKeyDown(keyCode, event); - } - - }); - } - } - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - } - - protected void setupLists(int layoutResId) { - setContentView(layoutResId); - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - mListController = (ListController)getLastNonConfigurationInstance(); - if (mListController == null) { - mListController = (ListController) getIntent().getSerializableExtra(ListController.EXTRA_LIST_CONTROLLER); - mListController.findTitleView(findViewById(R.id.blanklist_outer_layout)); - mListController.findMessageView(findViewById(R.id.blanklist_outer_layout)); - mListController.onCreate(this, new Handler(), (AbsListView)findViewById(R.id.blanklist_list)); - } - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - @Override - public Object onRetainNonConfigurationInstance() { -// // TODO Auto-generated method stub -// return super.onRetainNonConfigurationInstance(); - return mListController; - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - mListController.onCreateContextMenu(menu, v, menuInfo); - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - mListController.onContextItemSelected(item); - return super.onContextItemSelected(item); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - mListController.onCreateOptionsMenu(menu); - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - mListController.onOptionsItemSelected(item); - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mListController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); - return true; - } - client.setController(null); - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; - return handled || super.onKeyDown(keyCode, event); - } - - @Override - protected void onResume() { - super.onResume(); - mListController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mConfigurationManager.onActivityPause(); - mListController.onActivityPause(); - } - - protected void callSuperOnKeyDown(int keyCode, KeyEvent event) { - super.onKeyDown(keyCode, event); - } - - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - Intent intent = new Intent(AbsListActivity.this, HomeActivity.class); - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; - return handled || super.onKeyUp(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.os.Handler; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AbsListView; +import android.widget.FrameLayout; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.ListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +public abstract class AbsListActivity extends Activity { + + private static final int MENU_NOW_PLAYING = 501; + private static final int MENU_REMOTE = 502; + + protected ConfigurationManager mConfigurationManager; + + ListController mListController; + private KeyTracker mKeyTracker; + + public AbsListActivity() { + if (Integer.parseInt(VERSION.SDK) < 5) { + mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { + + @Override + public void onLongPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + onKeyLongPress(keyCode, event); + } + + @Override + public void onShortPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + callSuperOnKeyDown(keyCode, event); + } + + }); + } + } + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + } + + protected void setupLists(int layoutResId) { + setContentView(layoutResId); + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + mListController = (ListController) getLastNonConfigurationInstance(); + if (mListController == null) { + mListController = (ListController) getIntent().getSerializableExtra(ListController.EXTRA_LIST_CONTROLLER); + mListController.findTitleView(findViewById(R.id.blanklist_outer_layout)); + mListController.findMessageView(findViewById(R.id.blanklist_outer_layout)); + mListController.onCreate(this, new Handler(), (AbsListView) findViewById(R.id.blanklist_list)); + } + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + public Object onRetainNonConfigurationInstance() { +// // TODO Auto-generated method stub +// return super.onRetainNonConfigurationInstance(); + return mListController; + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + mListController.onCreateContextMenu(menu, v, menuInfo); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + mListController.onContextItemSelected(item); + return super.onContextItemSelected(item); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + mListController.onCreateOptionsMenu(menu); + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + mListController.onOptionsItemSelected(item); + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mListController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; + return handled || super.onKeyDown(keyCode, event); + } + + @Override + protected void onResume() { + super.onResume(); + mListController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mConfigurationManager.onActivityPause(); + mListController.onActivityPause(); + } + + protected void callSuperOnKeyDown(int keyCode, KeyEvent event) { + super.onKeyDown(keyCode, event); + } + + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + Intent intent = new Intent(AbsListActivity.this, HomeActivity.class); + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; + return handled || super.onKeyUp(keyCode, event); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java similarity index 94% rename from src/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java index de17723a..1df93634 100644 --- a/src/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/ConfigurationManager.java @@ -1,135 +1,135 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import android.app.Activity; -import android.app.KeyguardManager; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.media.AudioManager; -import android.preference.PreferenceManager; - -class ConfigurationManager implements OnSharedPreferenceChangeListener { - - public final static String PREF_KEYGUARD_DISABLED = "setting_disable_keyguard"; - - public final static String KEYGUARD_STATUS_ENABLED = "0"; - public final static String KEYGUARD_STATUS_REMOTE_ONLY = "1"; - public final static String KEYGUARD_STATUS_ALL = "2"; - - public final static int INT_KEYGUARD_STATUS_ENABLED = 0; - public final static int INT_KEYGUARD_STATUS_REMOTE_ONLY = 1; - public final static int INT_KEYGUARD_STATUS_ALL = 2; - - public final static String KEYGUARD_TAG = "xbmc_remote_keyguard_lock"; - - private static ConfigurationManager sInstance; - - private Activity mActivity; - - private int mKeyguardState = 0; - - private KeyguardManager.KeyguardLock mKeyguardLock = null; - - private ConfigurationManager(Activity activity) { - mActivity = activity; - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity); - prefs.registerOnSharedPreferenceChangeListener(this); - mKeyguardState = Integer.parseInt(prefs.getString(PREF_KEYGUARD_DISABLED, KEYGUARD_STATUS_ENABLED)); - } - - public static ConfigurationManager getInstance(Activity activity) { - if (sInstance == null) { - sInstance = new ConfigurationManager(activity); - } else { - sInstance.mActivity = activity; - } - return sInstance; - } - - //Use with extreme care! this could return null, so you need to null-check - //in the calling code! - public static ConfigurationManager getInstance() { - return sInstance; - } - - public Context getActiveContext() { - return sInstance.mActivity; - } - - public void disableKeyguard(Activity activity) { - if (mKeyguardLock != null) { - mKeyguardLock.disableKeyguard(); - } else { - KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Activity.KEYGUARD_SERVICE); - mKeyguardLock = keyguardManager.newKeyguardLock(KEYGUARD_TAG); - mKeyguardLock.disableKeyguard(); - } - } - - public void enableKeyguard() { - if (mKeyguardLock != null) { - mKeyguardLock.reenableKeyguard(); - } - mKeyguardLock = null; - } - - - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - if (key.equals(PREF_KEYGUARD_DISABLED)) { - mKeyguardState = Integer.parseInt(prefs.getString(PREF_KEYGUARD_DISABLED, KEYGUARD_STATUS_ENABLED)); - if (mKeyguardState == INT_KEYGUARD_STATUS_ALL) - disableKeyguard(mActivity); - else - enableKeyguard(); - } - } - - public void onActivityResume(Activity activity) { - switch (mKeyguardState) { - case INT_KEYGUARD_STATUS_REMOTE_ONLY: - if(activity.getClass().equals(RemoteActivity.class)) - disableKeyguard(activity); - else - enableKeyguard(); - break; - case INT_KEYGUARD_STATUS_ALL: - disableKeyguard(activity); - break; - default: - enableKeyguard(); - break; - } - - activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); - mActivity = activity; - } - - public void onActivityPause() { - if (mKeyguardLock != null){ - mKeyguardLock.reenableKeyguard(); - mKeyguardLock = null; - } - } - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.app.KeyguardManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.media.AudioManager; +import android.preference.PreferenceManager; + +class ConfigurationManager implements OnSharedPreferenceChangeListener { + + public final static String PREF_KEYGUARD_DISABLED = "setting_disable_keyguard"; + + public final static String KEYGUARD_STATUS_ENABLED = "0"; + public final static String KEYGUARD_STATUS_REMOTE_ONLY = "1"; + public final static String KEYGUARD_STATUS_ALL = "2"; + + public final static int INT_KEYGUARD_STATUS_ENABLED = 0; + public final static int INT_KEYGUARD_STATUS_REMOTE_ONLY = 1; + public final static int INT_KEYGUARD_STATUS_ALL = 2; + + public final static String KEYGUARD_TAG = "xbmc_remote_keyguard_lock"; + + private static ConfigurationManager sInstance; + + private Activity mActivity; + + private int mKeyguardState = 0; + + private KeyguardManager.KeyguardLock mKeyguardLock = null; + + private ConfigurationManager(Activity activity) { + mActivity = activity; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity); + prefs.registerOnSharedPreferenceChangeListener(this); + mKeyguardState = Integer.parseInt(prefs.getString(PREF_KEYGUARD_DISABLED, KEYGUARD_STATUS_ENABLED)); + } + + public static ConfigurationManager getInstance(Activity activity) { + if (sInstance == null) { + sInstance = new ConfigurationManager(activity); + } else { + sInstance.mActivity = activity; + } + return sInstance; + } + + //Use with extreme care! this could return null, so you need to null-check + //in the calling code! + public static ConfigurationManager getInstance() { + return sInstance; + } + + public Context getActiveContext() { + return sInstance.mActivity; + } + + public void disableKeyguard(Activity activity) { + if (mKeyguardLock != null) { + mKeyguardLock.disableKeyguard(); + } else { + KeyguardManager keyguardManager = (KeyguardManager) activity.getSystemService(Activity.KEYGUARD_SERVICE); + mKeyguardLock = keyguardManager.newKeyguardLock(KEYGUARD_TAG); + mKeyguardLock.disableKeyguard(); + } + } + + public void enableKeyguard() { + if (mKeyguardLock != null) { + mKeyguardLock.reenableKeyguard(); + } + mKeyguardLock = null; + } + + + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if (key.equals(PREF_KEYGUARD_DISABLED)) { + mKeyguardState = Integer.parseInt(prefs.getString(PREF_KEYGUARD_DISABLED, KEYGUARD_STATUS_ENABLED)); + if (mKeyguardState == INT_KEYGUARD_STATUS_ALL) + disableKeyguard(mActivity); + else + enableKeyguard(); + } + } + + public void onActivityResume(Activity activity) { + switch (mKeyguardState) { + case INT_KEYGUARD_STATUS_REMOTE_ONLY: + if (activity.getClass().equals(RemoteActivity.class)) + disableKeyguard(activity); + else + enableKeyguard(); + break; + case INT_KEYGUARD_STATUS_ALL: + disableKeyguard(activity); + break; + default: + enableKeyguard(); + break; + } + + activity.setVolumeControlStream(AudioManager.STREAM_MUSIC); + mActivity = activity; + } + + public void onActivityPause() { + if (mKeyguardLock != null) { + mKeyguardLock.reenableKeyguard(); + mKeyguardLock = null; + } + } + } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/DialogFactory.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/DialogFactory.java similarity index 78% rename from src/org/xbmc/android/remote/presentation/activity/DialogFactory.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/DialogFactory.java index 53d58480..68216b39 100644 --- a/src/org/xbmc/android/remote/presentation/activity/DialogFactory.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/DialogFactory.java @@ -21,20 +21,6 @@ package org.xbmc.android.remote.presentation.activity; -import java.io.File; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.util.Crc32; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Song; -import org.xbmc.api.type.MediaType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -51,25 +37,41 @@ import android.widget.TableRow; import android.widget.TextView; +import org.xbmc.android.remote.R; +import org.xbmc.android.util.Crc32; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Song; +import org.xbmc.api.type.MediaType; +import org.xbmc.api.type.ThumbSize; + +import java.io.File; +import java.util.ArrayList; + /** * Keeps all the more sophisticated dialogs in one place. Feel free to change * if it gets inconvenient. - * + * * @author Team XBMC */ public abstract class DialogFactory { - + /** * Returns the album details dialog, the one with big cover and queue/play button. + * * @param activity Parent activity * @param album Album to display * @return Album details dialog */ - public static Dialog getAlbumDetail(final IMusicManager musicManager, final Activity activity, final Album album, final Context context) { - + public static Dialog getAlbumDetail(final IMusicManager musicManager, final Activity activity, final Album album, + final Context context) { + final Dialog dialog = new Dialog(activity); dialog.setContentView(R.layout.albuminfo); - + // get controls final TextView artistText = (TextView) dialog.findViewById(R.id.album_artistname); final ImageView cover = (ImageView) dialog.findViewById(R.id.album_cover); @@ -77,7 +79,7 @@ public static Dialog getAlbumDetail(final IMusicManager musicManager, final Acti final TextView yearText = (TextView) dialog.findViewById(R.id.album_year); final Button queueButton = (Button) dialog.findViewById(R.id.album_queuebutton); final Button playButton = (Button) dialog.findViewById(R.id.album_playbutton); - + musicManager.updateAlbumInfo(new DataResponse() { public void run() { final Album album = value; @@ -107,18 +109,18 @@ public void onClick(View v) { musicManager.addToPlaylist(new DataResponse(), album, context); } }); - + // asynchronously load the cover musicManager.getCover(new DataResponse() { - public void run() { - if (value == null) { - cover.setImageResource(R.drawable.nocover); - } else { - cover.setImageBitmap(value); - } - } - }, album, ThumbSize.BIG, null, context, false); - + public void run() { + if (value == null) { + cover.setImageResource(R.drawable.nocover); + } else { + cover.setImageBitmap(value); + } + } + }, album, ThumbSize.BIG, null, context, false); + cover.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { getTrackDetail(musicManager, activity, album, context).show(); @@ -126,22 +128,24 @@ public void onClick(View v) { }); return dialog; } - + /** * Returns the track listing of an album. + * * @param activity * @param album * @return Track listing dialog */ - public static Dialog getTrackDetail(final IMusicManager musicManager, final Activity activity, final Album album, final Context context) { - + public static Dialog getTrackDetail(final IMusicManager musicManager, final Activity activity, final Album album, + final Context context) { + Dialog dialog = new Dialog(activity); dialog.setContentView(R.layout.albumtracks); dialog.setTitle(album.name); // get controls final TextView artistText = (TextView) dialog.findViewById(R.id.album_artistname); - final ImageView cover = (ImageView)dialog.findViewById(R.id.album_cover); + final ImageView cover = (ImageView) dialog.findViewById(R.id.album_cover); final TextView numTrackText = (TextView) dialog.findViewById(R.id.album_numtracks); final TextView yearText = (TextView) dialog.findViewById(R.id.album_year); final TableLayout trackTable = (TableLayout) dialog.findViewById(R.id.album_tracktable); @@ -153,28 +157,29 @@ public static Dialog getTrackDetail(final IMusicManager musicManager, final Acti } else { yearText.setVisibility(View.GONE); } - - final File file = new File(ImportUtilities.getCacheDirectory(MediaType.getArtFolder(album.getMediaType()), ThumbSize.SMALL), Crc32.formatAsHexLowerCase(album.getCrc())); - if (file.exists()) { - cover.setImageBitmap(BitmapFactory.decodeFile(file.getAbsolutePath())); - } - + + final File file = new File(ImportUtilities.getCacheDirectory(MediaType.getArtFolder(album.getMediaType()), + ThumbSize.SMALL), Crc32.formatAsHexLowerCase(album.getCrc())); + if (file.exists()) { + cover.setImageBitmap(BitmapFactory.decodeFile(file.getAbsolutePath())); + } + trackTable.setScrollContainer(true); - + musicManager.getSongs(new DataResponse>() { public void run() { final ArrayList songs = value; numTrackText.setText(songs.size() + " Tracks"); - for (Song song: songs) { + for (Song song : songs) { TableRow tr = new TableRow(activity); - + TextView txtTrack = new TextView(activity); txtTrack.setText(String.valueOf(song.track)); txtTrack.setGravity(Gravity.RIGHT); txtTrack.setWidth(20); txtTrack.setPadding(0, 0, 5, 0); txtTrack.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10); - + TextView txtTitle = new TextView(activity); if (album.isVA()) { txtTitle.setText(song.artist + " - " + song.title); @@ -182,30 +187,32 @@ public void run() { txtTitle.setText(song.title); } txtTitle.setWidth(200); - + TextView txtDuration = new TextView(activity); txtDuration.setText(song.getDuration()); txtDuration.setGravity(Gravity.RIGHT); - + tr.addView(txtTrack); tr.addView(txtTitle); tr.addView(txtDuration); - + trackTable.addView(tr); - } + } } }, album, context); return dialog; } - + /** * Returns the artist details dialog. - * @param activity Parent activity - * @param album Artist to display - * @return Artist details dialog + * + * @param activity Parent activity + * @param artist Artist to display + * @return Artist details dialog */ - public static Dialog getArtistDetail(final IMusicManager musicManager, final Activity activity, final Artist artist, final Context context) { - + public static Dialog getArtistDetail(final IMusicManager musicManager, final Activity activity, + final Artist artist, final Context context) { + Dialog dialog = new Dialog(activity); dialog.setContentView(R.layout.artistinfo); dialog.setTitle(artist.name); @@ -216,26 +223,27 @@ public static Dialog getArtistDetail(final IMusicManager musicManager, final Act final TextView formedText = (TextView) dialog.findViewById(R.id.artist_formed); final TextView genresText = (TextView) dialog.findViewById(R.id.artist_genres); final TextView biographyText = (TextView) dialog.findViewById(R.id.artist_biography); - - final File file = new File(ImportUtilities.getCacheDirectory(MediaType.getArtFolder(artist.getMediaType()), ThumbSize.MEDIUM), Crc32.formatAsHexLowerCase(artist.getCrc())); - if (file.exists()) { - final Bitmap coverBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); - if (coverBitmap != null) { - cover.setImageBitmap(coverBitmap); - - // correct alignment if texts do not fit - final Display display = activity.getWindowManager().getDefaultDisplay(); - final LinearLayout header = (LinearLayout) dialog.findViewById(R.id.LinearLayoutHeader); - if (coverBitmap.getWidth() > display.getWidth() / 2) { - header.setOrientation(LinearLayout.VERTICAL); - } else { - header.setOrientation(LinearLayout.HORIZONTAL); - } - } - } - + + final File file = new File(ImportUtilities.getCacheDirectory(MediaType.getArtFolder(artist.getMediaType()), + ThumbSize.MEDIUM), Crc32.formatAsHexLowerCase(artist.getCrc())); + if (file.exists()) { + final Bitmap coverBitmap = BitmapFactory.decodeFile(file.getAbsolutePath()); + if (coverBitmap != null) { + cover.setImageBitmap(coverBitmap); + + // correct alignment if texts do not fit + final Display display = activity.getWindowManager().getDefaultDisplay(); + final LinearLayout header = (LinearLayout) dialog.findViewById(R.id.LinearLayoutHeader); + if (coverBitmap.getWidth() > display.getWidth() / 2) { + header.setOrientation(LinearLayout.VERTICAL); + } else { + header.setOrientation(LinearLayout.HORIZONTAL); + } + } + } + biographyText.setScrollContainer(true); - + musicManager.updateArtistInfo(new DataResponse() { public void run() { final Artist artist = value; @@ -260,7 +268,7 @@ public void run() { biographyText.setText(artist.biography); } else { biographyText.setVisibility(View.GONE); - } + } } }, artist, context); return dialog; diff --git a/src/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java similarity index 67% rename from src/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java index a94503ee..a3269d41 100644 --- a/src/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/EpisodeDetailsActivity.java @@ -1,329 +1,337 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AbstractController; -import org.xbmc.android.remote.presentation.controller.IController; -import org.xbmc.android.remote.presentation.controller.ListController; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Episode; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Display; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View.OnClickListener; -import android.view.View.OnCreateContextMenuListener; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -public class EpisodeDetailsActivity extends Activity { - - private static final String NO_DATA = "-"; - - public static final int CAST_CONTEXT_IMDB = 1; - private static View selectedView; - private static Actor selectedAcotr; - - private ConfigurationManager mConfigurationManager; - private EpisodeDetailsController mEpisodeDetailsController; - - private KeyTracker mKeyTracker; - - private static final int[] sStarImages = { R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10 }; - - public EpisodeDetailsActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { - mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - - @Override - public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - onKeyLongPress(keyCode, event); - } - - @Override - public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - EpisodeDetailsActivity.super.onKeyDown(keyCode, event); - } - - }); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.tvepisodedetails); - - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - final Episode episode = (Episode)getIntent().getSerializableExtra(ListController.EXTRA_EPISODE); - mEpisodeDetailsController = new EpisodeDetailsController(this, episode); - - ((TextView)findViewById(R.id.titlebar_text)).setText(episode.getName()); - - Log.i("EpisodeDetailsActivity", "rating = " + episode.rating + ", index = " + ((int)Math.round(episode.rating % 10)) + "."); - if (episode.rating > -1) { - ((ImageView)findViewById(R.id.tvepisodedetails_rating_stars)).setImageResource(sStarImages[(int)Math.round(episode.rating % 10)]); - } - ((TextView)findViewById(R.id.tvepisodedetails_show)).setText(episode.showTitle); - ((TextView)findViewById(R.id.tvepisodedetails_first_aired)).setText(episode.firstAired); - ((TextView)findViewById(R.id.tvepisodedetails_director)).setText(episode.director); - ((TextView)findViewById(R.id.tvepisodedetails_writer)).setText(episode.writer); - ((TextView)findViewById(R.id.tvepisodedetails_rating)).setText(String.valueOf(episode.rating)); - - mEpisodeDetailsController.setupPlayButton((Button)findViewById(R.id.tvepisodedetails_playbutton)); - mEpisodeDetailsController.setupQueueButton((Button)findViewById(R.id.tvepisodedetails_queuebutton)); - mEpisodeDetailsController.loadCover(new Handler(), (ImageView)findViewById(R.id.tvepisodedetails_thumb)); - mEpisodeDetailsController.updateEpisodeDetails( - (TextView)findViewById(R.id.tvepisodedetails_plot), - (LinearLayout)findViewById(R.id.tvepisodedetails_datalayout)); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - private static class EpisodeDetailsController extends AbstractController implements INotifiableController, IController { - - private ITvShowManager mShowManager; - private IControlManager mControlManager; - private final Episode mEpisode; - - EpisodeDetailsController(Activity activity, Episode episode) { - super.onCreate(activity, new Handler()); - mActivity = activity; - mEpisode = episode; - mShowManager = ManagerFactory.getTvManager(this); - mControlManager = ManagerFactory.getControlManager(this); - } - - public void setupPlayButton(Button button) { - button.setText("Play Episode"); - button.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - Toast.makeText(mActivity, "Playing Episode", Toast.LENGTH_LONG).show(); - mControlManager.playFile(new DataResponse(){ - public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); - } - } - }, mEpisode.fileName, 1, mActivity.getApplicationContext()); - } - }); - } - - public void setupQueueButton(Button button) { - button.setText("Queue Episode"); - button.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mControlManager.addToPlaylist(new DataResponse(){ - public void run() { - if (value) { - Toast.makeText(mActivity, "Episode Queued", Toast.LENGTH_LONG).show(); - } - } - }, mEpisode.getPath(), 1, mActivity); - } - }); - } - - public void loadCover(final Handler handler, final ImageView imageView) { - mShowManager.getCover(new DataResponse() { - public void run() { - handler.post(new Runnable() { - public void run() { - if (value == null) { - imageView.setImageResource(R.drawable.nocover); - } else { - imageView.setImageBitmap(value); - } - } - }); - } - }, mEpisode, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); - } - - public void updateEpisodeDetails(final TextView plotView, final LinearLayout dataLayout) { - mShowManager.updateEpisodeDetails(new DataResponse() { - public void run() { - final Episode episode = value; - plotView.setText(episode.plot.equals("") ? NO_DATA : episode.plot); - - if (episode.actors != null) { - final LayoutInflater inflater = mActivity.getLayoutInflater(); - //int n = 0; - for (Actor actor : episode.actors) { - final View view = inflater.inflate(R.layout.actor_item, null); - - ((TextView)view.findViewById(R.id.actor_name)).setText(actor.name); - if (actor.role != null && !actor.role.equals("")) { - ((TextView)view.findViewById(R.id.actor_role)).setText("as " + actor.role); - } else { - ((TextView)view.findViewById(R.id.actor_role)).setVisibility(View.GONE); - } - ImageButton img = ((ImageButton)view.findViewById(R.id.actor_image)); - mShowManager.getCover(new DataResponse() { - public void run() { - if (value != null) { - ((ImageButton)view.findViewById(R.id.actor_image)).setImageBitmap(value); - } - } - }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); - - img.setTag(actor); - - // this isn't working -// img.setOnClickListener(new OnClickListener() { -// public void onClick(View v) { -// Intent nextActivity; -// Actor actor = (Actor)v.getTag(); -// nextActivity = new Intent(view.getContext(), ListActivity.class); -// nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new TvShowListController()); -// nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); -// mActivity.startActivity(nextActivity); -// } -// }); - img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - - selectedAcotr = (Actor) v.getTag(); - selectedView = v; - - // final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; - menu.setHeaderTitle(selectedAcotr.getShortName()); - menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new OnMenuItemClickListener( ) { - - public boolean onMenuItemClick(MenuItem item) { - Intent intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); - if (selectedView.getContext().getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/find?s=nm&q=" + selectedAcotr.getName())); - } - selectedView.getContext().startActivity(intentIMDb); - - return false; - } - }); - }; - }); - dataLayout.addView(view); - //n++; - } - } - } - }, mEpisode, mActivity.getApplicationContext()); - } - - public void onActivityPause() { - mShowManager.setController(null); -// mShowManager.postActivity(); - mControlManager.setController(null); - } - - public void onActivityResume(Activity activity) { - mShowManager.setController(this); - mControlManager.setController(this); - } - } - - @Override - protected void onResume() { - super.onResume(); - mEpisodeDetailsController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mEpisodeDetailsController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)? mKeyTracker.doKeyUp(keyCode, event): false; - return handled || super.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mEpisodeDetailsController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; - return handled || super.onKeyDown(keyCode, event); - } - - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - Intent intent = new Intent(EpisodeDetailsActivity.this, HomeActivity.class); - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AbstractController; +import org.xbmc.android.remote.presentation.controller.IController; +import org.xbmc.android.remote.presentation.controller.ListController; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Episode; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +public class EpisodeDetailsActivity extends Activity { + + public static final int CAST_CONTEXT_IMDB = 1; + private static final String NO_DATA = "-"; + private static final int[] sStarImages = {R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, + R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, + R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10}; + private static View selectedView; + private static Actor selectedAcotr; + private ConfigurationManager mConfigurationManager; + private EpisodeDetailsController mEpisodeDetailsController; + private KeyTracker mKeyTracker; + + public EpisodeDetailsActivity() { + if (Integer.parseInt(VERSION.SDK) < 5) { + mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { + + @Override + public void onLongPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + onKeyLongPress(keyCode, event); + } + + @Override + public void onShortPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + EpisodeDetailsActivity.super.onKeyDown(keyCode, event); + } + + }); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tvepisodedetails); + + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + final Episode episode = (Episode) getIntent().getSerializableExtra(ListController.EXTRA_EPISODE); + mEpisodeDetailsController = new EpisodeDetailsController(this, episode); + + ((TextView) findViewById(R.id.titlebar_text)).setText(episode.getName()); + + Log.i("EpisodeDetailsActivity", "rating = " + episode.rating + ", index = " + ((int) Math.round(episode.rating + % 10)) + "."); + if (episode.rating > -1) { + ((ImageView) findViewById(R.id.tvepisodedetails_rating_stars)).setImageResource(sStarImages[(int) Math + .round(episode.rating % 10)]); + } + ((TextView) findViewById(R.id.tvepisodedetails_show)).setText(episode.showTitle); + ((TextView) findViewById(R.id.tvepisodedetails_first_aired)).setText(episode.firstAired); + ((TextView) findViewById(R.id.tvepisodedetails_director)).setText(episode.director); + ((TextView) findViewById(R.id.tvepisodedetails_writer)).setText(episode.writer); + ((TextView) findViewById(R.id.tvepisodedetails_rating)).setText(String.valueOf(episode.rating)); + + mEpisodeDetailsController.setupPlayButton((Button) findViewById(R.id.tvepisodedetails_playbutton)); + mEpisodeDetailsController.setupQueueButton((Button) findViewById(R.id.tvepisodedetails_queuebutton)); + mEpisodeDetailsController.loadCover(new Handler(), (ImageView) findViewById(R.id.tvepisodedetails_thumb)); + mEpisodeDetailsController.updateEpisodeDetails( + (TextView) findViewById(R.id.tvepisodedetails_plot), + (LinearLayout) findViewById(R.id.tvepisodedetails_datalayout)); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + protected void onResume() { + super.onResume(); + mEpisodeDetailsController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mEpisodeDetailsController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; + return handled || super.onKeyUp(keyCode, event); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mEpisodeDetailsController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; + return handled || super.onKeyDown(keyCode, event); + } + + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + Intent intent = new Intent(EpisodeDetailsActivity.this, HomeActivity.class); + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + } + + private static class EpisodeDetailsController extends AbstractController implements INotifiableController, + IController { + + private final Episode mEpisode; + private ITvShowManager mShowManager; + private IControlManager mControlManager; + + EpisodeDetailsController(Activity activity, Episode episode) { + super.onCreate(activity, new Handler()); + mActivity = activity; + mEpisode = episode; + mShowManager = ManagerFactory.getTvManager(this); + mControlManager = ManagerFactory.getControlManager(this); + } + + public void setupPlayButton(Button button) { + button.setText("Play Episode"); + button.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + Toast.makeText(mActivity, "Playing Episode", Toast.LENGTH_LONG).show(); + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + } + } + }, mEpisode.fileName, 1, mActivity.getApplicationContext()); + } + }); + } + + public void setupQueueButton(Button button) { + button.setText("Queue Episode"); + button.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mControlManager.addToPlaylist(new DataResponse() { + public void run() { + if (value) { + Toast.makeText(mActivity, "Episode Queued", Toast.LENGTH_LONG).show(); + } + } + }, mEpisode.getPath(), 1, mActivity); + } + }); + } + + public void loadCover(final Handler handler, final ImageView imageView) { + mShowManager.getCover(new DataResponse() { + public void run() { + handler.post(new Runnable() { + public void run() { + if (value == null) { + imageView.setImageResource(R.drawable.nocover); + } else { + imageView.setImageBitmap(value); + } + } + }); + } + }, mEpisode, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); + } + + public void updateEpisodeDetails(final TextView plotView, final LinearLayout dataLayout) { + mShowManager.updateEpisodeDetails(new DataResponse() { + public void run() { + final Episode episode = value; + plotView.setText(episode.plot.equals("") ? NO_DATA : episode.plot); + + if (episode.actors != null) { + final LayoutInflater inflater = mActivity.getLayoutInflater(); + //int n = 0; + for (Actor actor : episode.actors) { + final View view = inflater.inflate(R.layout.actor_item, null); + + ((TextView) view.findViewById(R.id.actor_name)).setText(actor.name); + if (actor.role != null && !actor.role.equals("")) { + ((TextView) view.findViewById(R.id.actor_role)).setText("as " + actor.role); + } else { + ((TextView) view.findViewById(R.id.actor_role)).setVisibility(View.GONE); + } + ImageButton img = ((ImageButton) view.findViewById(R.id.actor_image)); + mShowManager.getCover(new DataResponse() { + public void run() { + if (value != null) { + ((ImageButton) view.findViewById(R.id.actor_image)).setImageBitmap(value); + } + } + }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); + + img.setTag(actor); + + // this isn't working +// img.setOnClickListener(new OnClickListener() { +// public void onClick(View v) { +// Intent nextActivity; +// Actor actor = (Actor)v.getTag(); +// nextActivity = new Intent(view.getContext(), ListActivity.class); +// nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, +// new TvShowListController()); +// nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); +// mActivity.startActivity(nextActivity); +// } +// }); + img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + selectedAcotr = (Actor) v.getTag(); + selectedView = v; + + // final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo) + // menuInfo).targetView; + menu.setHeaderTitle(selectedAcotr.getShortName()); + menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new + OnMenuItemClickListener() { + + public boolean onMenuItemClick(MenuItem item) { + Intent intentIMDb = new Intent(Intent.ACTION_VIEW, + Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); + if (selectedView.getContext().getPackageManager().resolveActivity + (intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb" + + ".com/find?s=nm&q=" + selectedAcotr.getName())); + } + selectedView.getContext().startActivity(intentIMDb); + + return false; + } + }); + } + + ; + }); + dataLayout.addView(view); + //n++; + } + } + } + }, mEpisode, mActivity.getApplicationContext()); + } + + public void onActivityPause() { + mShowManager.setController(null); +// mShowManager.postActivity(); + mControlManager.setController(null); + } + + public void onActivityResume(Activity activity) { + mShowManager.setController(this); + mControlManager.setController(this); + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java similarity index 94% rename from src/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java index e99ff950..d0714a97 100644 --- a/src/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/GestureRemoteActivity.java @@ -21,12 +21,6 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.widget.gestureremote.GestureRemoteView; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -40,31 +34,35 @@ import android.view.MotionEvent; import android.widget.FrameLayout; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.widget.gestureremote.GestureRemoteView; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + /** * Gesture mode. Let's see how this works out... - * + * * @author Team XBMC */ public class GestureRemoteActivity extends Activity { - + private final static String TAG = "GestureRemoteActivity"; - - private ConfigurationManager mConfigurationManager; - private RemoteController mRemoteController; - private static final int MENU_NOW_PLAYING = 401; private static final int MENU_SWITCH_BUTTONS = 402; -// private static final int MENU_SWITCH_MOUSE = 403; + // private static final int MENU_SWITCH_MOUSE = 403; private static final int MENU_ENTER_TEXT = 406; + private ConfigurationManager mConfigurationManager; + private RemoteController mRemoteController; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + Display d = getWindowManager().getDefaultDisplay(); // set display size ThumbSize.setScreenSize(d.getWidth(), d.getHeight()); - + final int w = d.getWidth(); final int h = d.getHeight(); final double ar = w > h ? (double) w / (double) h : (double) h / (double) w; @@ -75,15 +73,15 @@ public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "AR = " + ar + ", normal layout."); setContentView(R.layout.remote_gesture); } - + // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); topFrame.setForeground(null); - - GestureRemoteView view = (GestureRemoteView)findViewById(R.id.RemoteXboxGestureZone); + + GestureRemoteView view = (GestureRemoteView) findViewById(R.id.RemoteXboxGestureZone); mRemoteController = new RemoteController(getApplicationContext()); view.setGestureListener(mRemoteController.startGestureThread(this.getApplicationContext())); - + mConfigurationManager = ConfigurationManager.getInstance(this); // mConfigurationManager.initKeyguard(true); setupButtons(); @@ -105,20 +103,21 @@ public void onPrepareDialog(int id, Dialog dialog) { public boolean onTrackballEvent(MotionEvent event) { return mRemoteController.onTrackballEvent(event); } - + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mRemoteController.onKeyDown(keyCode, event) ? true : super.onKeyDown(keyCode, event); } - + @Override protected void onResume() { super.onResume(); - getSharedPreferences("global", Context.MODE_PRIVATE).edit().putInt(RemoteController.LAST_REMOTE_PREFNAME, RemoteController.LAST_REMOTE_GESTURE).commit(); + getSharedPreferences("global", Context.MODE_PRIVATE).edit().putInt(RemoteController.LAST_REMOTE_PREFNAME, + RemoteController.LAST_REMOTE_GESTURE).commit(); mRemoteController.onActivityResume(this); mConfigurationManager.onActivityResume(this); } - + @Override protected void onPause() { super.onPause(); @@ -132,7 +131,7 @@ protected void onPause() { private void setupButtons() { // display mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnDisplay), ButtonCodes.REMOTE_DISPLAY); - + // seek back mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnSeekBack), ButtonCodes.REMOTE_REVERSE); // play @@ -149,7 +148,7 @@ private void setupButtons() { // next mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnNext), ButtonCodes.REMOTE_SKIP_PLUS); } - + public boolean onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_SWITCH_BUTTONS, 0, "Switch to buttons").setIcon(R.drawable.menu_remote); menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); diff --git a/src/org/xbmc/android/remote/presentation/activity/GridActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/GridActivity.java similarity index 96% rename from src/org/xbmc/android/remote/presentation/activity/GridActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/GridActivity.java index 55a79fcf..e464520d 100644 --- a/src/org/xbmc/android/remote/presentation/activity/GridActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/GridActivity.java @@ -1,43 +1,44 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; - -import android.os.Bundle; - -/** - * TODO do that properly - * @author Team XBMC - */ -public class GridActivity extends AbsListActivity { - - public GridActivity() { - super(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setupLists(R.layout.blankgrid); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.os.Bundle; + +import org.xbmc.android.remote.R; + +/** + * TODO do that properly + * + * @author Team XBMC + */ +public class GridActivity extends AbsListActivity { + + public GridActivity() { + super(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setupLists(R.layout.blankgrid); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/HomeActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/HomeActivity.java similarity index 74% rename from src/org/xbmc/android/remote/presentation/activity/HomeActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/HomeActivity.java index 87d89855..14bb3b79 100644 --- a/src/org/xbmc/android/remote/presentation/activity/HomeActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/HomeActivity.java @@ -21,27 +21,14 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.CacheManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.business.receiver.AndroidBroadcastReceiver; -import org.xbmc.android.remote.presentation.controller.HomeController; -import org.xbmc.android.remote.presentation.controller.HomeController.ProgressThread; -import org.xbmc.android.remote.presentation.notification.NowPlayingNotificationManager; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; -import android.content.IntentFilter; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; +import android.content.IntentFilter; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -60,15 +47,22 @@ import android.widget.GridView; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.CacheManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.business.receiver.AndroidBroadcastReceiver; +import org.xbmc.android.remote.presentation.controller.HomeController; +import org.xbmc.android.remote.presentation.controller.HomeController.ProgressThread; +import org.xbmc.android.remote.presentation.notification.NowPlayingNotificationManager; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + public class HomeActivity extends Activity { - - private static final String TAG = "HomeActivity"; - private static final int MENU_ABOUT = 1; - private static final int MENU_SETTINGS = 2; - private static final int MENU_EXIT = 3; - private static final int MENU_SWITCH_XBMC = 5; -// private static final int MENU_INPUT_TEXT = 6; + // private static final int MENU_INPUT_TEXT = 6; public static final int MENU_COVER_DOWNLOAD = 4; public static final int MENU_COVER_DOWNLOAD_MUSIC = 41; public static final int MENU_COVER_DOWNLOAD_MOVIES = 42; @@ -77,65 +71,82 @@ public class HomeActivity extends Activity { public static final int MENU_COVER_DOWNLOAD_TVSHOWS = 45; public static final int MENU_COVER_DOWNLOAD_TVSEASONS = 46; public static final int MENU_COVER_DOWNLOAD_TVEPISODES = 47; - + private static final String TAG = "HomeActivity"; + private static final int MENU_ABOUT = 1; + private static final int MENU_SETTINGS = 2; + private static final int MENU_EXIT = 3; + private static final int MENU_SWITCH_XBMC = 5; private ConfigurationManager mConfigurationManager; private HomeController mHomeController; - + private IEventClientManager mEventClientManager; private ProgressThread mProgressThread; - private ProgressDialog mProgressDialog; - + private ProgressDialog mProgressDialog; + final Handler mHandler = new Handler() { + public void handleMessage(final Message msg) { + mHomeController.onHandleMessage(msg, mProgressDialog, mProgressThread); + } + }; + private AndroidBroadcastReceiver receiver; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.home); - + if (Build.VERSION.SDK_INT >= 9) { final StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); } - + // set display size - final Display display = getWindowManager().getDefaultDisplay(); + final Display display = getWindowManager().getDefaultDisplay(); ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - final Button versionButton = (Button)findViewById(R.id.home_version_button); - final GridView menuGrid = (GridView)findViewById(R.id.HomeItemGridView); + + final Button versionButton = (Button) findViewById(R.id.home_version_button); + final GridView menuGrid = (GridView) findViewById(R.id.HomeItemGridView); mHomeController = new HomeController(this, new Handler(), menuGrid); mHomeController.setupVersionHandler(new Handler(), versionButton, menuGrid); - + mEventClientManager = ManagerFactory.getEventClientManager(mHomeController); mConfigurationManager = ConfigurationManager.getInstance(this); - + versionButton.setText("Connecting..."); versionButton.setOnClickListener(mHomeController.getOnHostChangeListener()); - - ((Button)findViewById(R.id.home_about_button)).setOnClickListener(new OnClickListener() { + + ((Button) findViewById(R.id.home_about_button)).setOnClickListener(new OnClickListener() { public void onClick(View v) { startActivity(new Intent(HomeActivity.this, AboutActivity.class)); } }); - // Listen for screen on and off broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_SCREEN_OFF); - filter.addAction(Intent.ACTION_SCREEN_ON); + // Listen for screen on and off broadcasts + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); - registerReceiver(new AndroidBroadcastReceiver(), filter); + receiver = new AndroidBroadcastReceiver(); + registerReceiver(receiver, filter); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unregisterReceiver(receiver); } - @Override public boolean onCreateOptionsMenu(Menu menu) { - + menu.add(0, MENU_SWITCH_XBMC, 0, "Switch XBMC").setIcon(R.drawable.menu_switch); - SubMenu downloadMenu = menu.addSubMenu(0, MENU_COVER_DOWNLOAD, 0, "Download Covers").setIcon(R.drawable.menu_download); + SubMenu downloadMenu = menu.addSubMenu(0, MENU_COVER_DOWNLOAD, 0, "Download Covers").setIcon(R.drawable + .menu_download); menu.add(0, MENU_ABOUT, 0, "About").setIcon(R.drawable.menu_about); menu.add(0, MENU_SETTINGS, 0, "Settings").setIcon(R.drawable.menu_settings); menu.add(0, MENU_EXIT, 0, "Exit").setIcon(R.drawable.menu_exit); // menu.add(0, MENU_INPUT_TEXT, 0, "Send Text"); - + downloadMenu.add(2, MENU_COVER_DOWNLOAD_MOVIES, 0, "Movie Posters"); downloadMenu.add(2, MENU_COVER_DOWNLOAD_MUSIC, 0, "Album Covers"); downloadMenu.add(2, MENU_COVER_DOWNLOAD_TVSHOWS, 0, "TV Show Banners"); @@ -143,60 +154,62 @@ public boolean onCreateOptionsMenu(Menu menu) { downloadMenu.add(2, MENU_COVER_DOWNLOAD_TVEPISODES, 0, "TV Episode Posters"); downloadMenu.add(2, MENU_COVER_DOWNLOAD_ACTORS, 0, "Actor Shots"); downloadMenu.add(2, MENU_COVER_PURGE_CACHE, 0, "Clear Cache"); - + return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_ABOUT: - startActivity(new Intent(this, AboutActivity.class)); - return true; - case MENU_SWITCH_XBMC: - mHomeController.openHostChanger(); - return true; - case MENU_SETTINGS: - startActivity(new Intent(this, SettingsActivity.class)); - return true; - case MENU_EXIT: - Log.i(TAG, "Exiting XBMC Remote."); - NowPlayingNotificationManager.getInstance(getBaseContext()).removeNotification(); - android.os.Process.killProcess(android.os.Process.myPid()); + case MENU_ABOUT: + startActivity(new Intent(this, AboutActivity.class)); + return true; + case MENU_SWITCH_XBMC: + mHomeController.openHostChanger(); + return true; + case MENU_SETTINGS: + startActivity(new Intent(this, SettingsActivity.class)); + return true; + case MENU_EXIT: + Log.i(TAG, "Exiting XBMC Remote."); + NowPlayingNotificationManager.getInstance(getBaseContext()).removeNotification(); + android.os.Process.killProcess(android.os.Process.myPid()); // System.exit(0); - return true; + return true; // case MENU_INPUT_TEXT: // startActivity(new Intent(this, KeyboardAndMouseActivity.class)); // return true; - case MENU_COVER_DOWNLOAD_MOVIES: - case MENU_COVER_DOWNLOAD_MUSIC: - case MENU_COVER_DOWNLOAD_ACTORS: - case MENU_COVER_DOWNLOAD_TVSHOWS: - case MENU_COVER_DOWNLOAD_TVSEASONS: - case MENU_COVER_DOWNLOAD_TVEPISODES: - showDialog(item.getItemId()); - return true; - case MENU_COVER_PURGE_CACHE: - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setMessage("All downloaded covers, thumbs and posters will be deleted. Are you really sure you want to do this?"); - builder.setCancelable(false); - builder.setPositiveButton("Absolutely.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - CacheManager.get().purgeCache(); - Toast.makeText(HomeActivity.this, "Cache purged.", Toast.LENGTH_SHORT).show(); - } - }); - builder.setNegativeButton("Please, no!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - builder.create().show(); - return true; + case MENU_COVER_DOWNLOAD_MOVIES: + case MENU_COVER_DOWNLOAD_MUSIC: + case MENU_COVER_DOWNLOAD_ACTORS: + case MENU_COVER_DOWNLOAD_TVSHOWS: + case MENU_COVER_DOWNLOAD_TVSEASONS: + case MENU_COVER_DOWNLOAD_TVEPISODES: + showDialog(item.getItemId()); + return true; + case MENU_COVER_PURGE_CACHE: + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage("All downloaded covers, thumbs and posters will be deleted. Are you really sure " + + "you" + + " want to do this?"); + builder.setCancelable(false); + builder.setPositiveButton("Absolutely.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + CacheManager.get().purgeCache(); + Toast.makeText(HomeActivity.this, "Cache purged.", Toast.LENGTH_SHORT).show(); + } + }); + builder.setNegativeButton("Please, no!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.create().show(); + return true; } return false; } - + @Override public Dialog onCreateDialog(int id) { mProgressDialog = new ProgressDialog(this); @@ -208,20 +221,21 @@ public void onCancel(DialogInterface dialog) { } }); mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - mProgressDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + mProgressDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); return mProgressDialog; } - + @Override protected void onPrepareDialog(int id, Dialog dialog) { super.onPrepareDialog(id, dialog); - final ProgressDialog d = (ProgressDialog)dialog; + final ProgressDialog d = (ProgressDialog) dialog; d.setProgress(0); switch (id) { case MENU_COVER_DOWNLOAD_MOVIES: d.setMessage("Downloading movie posters..."); mProgressThread = mHomeController.new ProgressThread(mHandler, MENU_COVER_DOWNLOAD_MOVIES, d); - break; + break; case MENU_COVER_DOWNLOAD_MUSIC: d.setMessage("Downloading album covers..."); mProgressThread = mHomeController.new ProgressThread(mHandler, MENU_COVER_DOWNLOAD_MUSIC, d); @@ -249,12 +263,12 @@ protected void onPrepareDialog(int id, Dialog dialog) { } @Override - public void onResume(){ + public void onResume() { super.onResume(); mHomeController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); + mConfigurationManager.onActivityResume(this); } - + @Override protected void onPause() { super.onPause(); @@ -262,40 +276,35 @@ protected void onPause() { mConfigurationManager.onActivityPause(); mEventClientManager.setController(null); } - - + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, + (byte) 0); return true; case KeyEvent.KEYCODE_VOLUME_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, + (byte) 0); return true; case KeyEvent.KEYCODE_BACK: - if(OnLongPressBackKeyTracker.lastStage == Stage.LONG_REPEAT) { + if (OnLongPressBackKeyTracker.lastStage == Stage.LONG_REPEAT) { return true; } } return super.onKeyDown(keyCode, event); } - + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { switch (keyCode) { - case KeyEvent.KEYCODE_BACK: - if(OnLongPressBackKeyTracker.lastStage == Stage.LONG_REPEAT) { - OnLongPressBackKeyTracker.lastStage = Stage.SHORT_REPEAT; - return true; - } + case KeyEvent.KEYCODE_BACK: + if (OnLongPressBackKeyTracker.lastStage == Stage.LONG_REPEAT) { + OnLongPressBackKeyTracker.lastStage = Stage.SHORT_REPEAT; + return true; + } } return super.onKeyUp(keyCode, event); } - - final Handler mHandler = new Handler() { - public void handleMessage(final Message msg) { - mHomeController.onHandleMessage(msg, mProgressDialog, mProgressThread); - } - }; } diff --git a/src/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java similarity index 93% rename from src/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java index 314e96bb..0eb3e762 100644 --- a/src/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/HostSettingsActivity.java @@ -1,112 +1,113 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.SettingsController; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceActivity; -import android.view.Display; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; - -/** - * Because we can't add menus to child PreferenceScreens, we're forced to - * create a separate activity for it. - * - * @author Team XBMC - */ -public class HostSettingsActivity extends PreferenceActivity { - - private ConfigurationManager mConfigurationManager; - private SettingsController mSettingsController; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - setTitle("XBMC Hosts"); - mSettingsController = new SettingsController(this, new Handler()); - mConfigurationManager = ConfigurationManager.getInstance(this); - setPreferenceScreen(mSettingsController.createHostsPreferences(getPreferenceManager().createPreferenceScreen(this), this)); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - mSettingsController.onCreateOptionsMenu(menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onMenuItemSelected(int featureId, MenuItem item) { - mSettingsController.onMenuItemSelected(featureId, item); - return super.onMenuItemSelected(featureId, item); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - mSettingsController.onActivityResult(requestCode, resultCode, data); - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onResume() { - super.onResume(); - mSettingsController.onActivityResume(this); - mSettingsController.updateSummaries(); - mConfigurationManager.onActivityResume(this); - getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(mSettingsController); - } - - @Override - protected void onPause() { - super.onPause(); - // Unregister the listener whenever a key changes - getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(mSettingsController); - mSettingsController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mSettingsController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - return super.onKeyDown(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceActivity; +import android.view.Display; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; + +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.SettingsController; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +/** + * Because we can't add menus to child PreferenceScreens, we're forced to + * create a separate activity for it. + * + * @author Team XBMC + */ +public class HostSettingsActivity extends PreferenceActivity { + + private ConfigurationManager mConfigurationManager; + private SettingsController mSettingsController; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + setTitle("XBMC Hosts"); + mSettingsController = new SettingsController(this, new Handler()); + mConfigurationManager = ConfigurationManager.getInstance(this); + setPreferenceScreen(mSettingsController.createHostsPreferences(getPreferenceManager().createPreferenceScreen + (this), this)); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + mSettingsController.onCreateOptionsMenu(menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onMenuItemSelected(int featureId, MenuItem item) { + mSettingsController.onMenuItemSelected(featureId, item); + return super.onMenuItemSelected(featureId, item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + mSettingsController.onActivityResult(requestCode, resultCode, data); + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + protected void onResume() { + super.onResume(); + mSettingsController.onActivityResume(this); + mSettingsController.updateSummaries(); + mConfigurationManager.onActivityResume(this); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(mSettingsController); + } + + @Override + protected void onPause() { + super.onPause(); + // Unregister the listener whenever a key changes + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(mSettingsController); + mSettingsController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mSettingsController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + return super.onKeyDown(keyCode, event); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/ListActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/ListActivity.java similarity index 96% rename from src/org/xbmc/android/remote/presentation/activity/ListActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/ListActivity.java index eef3349c..67e30ea9 100644 --- a/src/org/xbmc/android/remote/presentation/activity/ListActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/ListActivity.java @@ -1,43 +1,44 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; - -import android.os.Bundle; - -/** - * TODO do that properly - * @author Team XBMC - */ -public class ListActivity extends AbsListActivity { - - public ListActivity() { - super(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setupLists(R.layout.blanklist); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.os.Bundle; + +import org.xbmc.android.remote.R; + +/** + * TODO do that properly + * + * @author Team XBMC + */ +public class ListActivity extends AbsListActivity { + + public ListActivity() { + super(); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setupLists(R.layout.blanklist); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java similarity index 93% rename from src/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java index 45410ed0..70e80af1 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MediaIntentActivity.java @@ -22,44 +22,43 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.presentation.controller.MediaIntentController; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.Display; +import org.xbmc.android.remote.presentation.controller.MediaIntentController; +import org.xbmc.api.type.ThumbSize; + /** * @author Team XBMC - * */ public class MediaIntentActivity extends Activity { public static final String ACTION = "android.intent.action.VIEW"; - + private ConfigurationManager mConfigurationManager; private MediaIntentController mMediaIntentController; - + @Override public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + super.onCreate(savedInstanceState); // set display size - final Display display = getWindowManager().getDefaultDisplay(); + final Display display = getWindowManager().getDefaultDisplay(); ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - mConfigurationManager = ConfigurationManager.getInstance(this); + + mConfigurationManager = ConfigurationManager.getInstance(this); mMediaIntentController = new MediaIntentController(this, new Handler()); mMediaIntentController.setupStatusHandler(); } - + @Override protected void onPause() { super.onPause(); mMediaIntentController.onActivityPause(); mConfigurationManager.onActivityPause(); } - + @Override protected void onResume() { super.onResume(); diff --git a/src/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java similarity index 69% rename from src/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java index d720fc08..a6b46255 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieDetailsActivity.java @@ -1,329 +1,338 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AbstractController; -import org.xbmc.android.remote.presentation.controller.IController; -import org.xbmc.android.remote.presentation.controller.ListController; -import org.xbmc.android.remote.presentation.controller.MovieListController; -import org.xbmc.android.remote.presentation.widget.JewelView; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Movie; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.Display; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnCreateContextMenuListener; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -public class MovieDetailsActivity extends Activity { - - private static final String NO_DATA = "-"; - - public static final int CAST_CONTEXT_IMDB = 1; - private static View selectedView; - private static Actor selectedAcotr; - - private ConfigurationManager mConfigurationManager; - private MovieDetailsController mMovieDetailsController; - - private KeyTracker mKeyTracker; - - private static final int[] sStarImages = { R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10 }; - - public MovieDetailsActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { - mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - - @Override - public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - onKeyLongPress(keyCode, event); - } - - @Override - public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - MovieDetailsActivity.super.onKeyDown(keyCode, event); - } - - }); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.moviedetails); - - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - final Movie movie = (Movie)getIntent().getSerializableExtra(ListController.EXTRA_MOVIE); - mMovieDetailsController = new MovieDetailsController(this, movie); - - ((TextView)findViewById(R.id.titlebar_text)).setText(movie.getName()); - - Log.i("MovieDetailsActivity", "rating = " + movie.rating + ", index = " + ((int)Math.round(movie.rating % 10)) + "."); - if (movie.rating > -1) { - ((ImageView)findViewById(R.id.moviedetails_rating_stars)).setImageResource(sStarImages[(int)Math.round(movie.rating % 10)]); - } - ((TextView)findViewById(R.id.moviedetails_director)).setText(movie.director); - ((TextView)findViewById(R.id.moviedetails_genre)).setText(movie.genres); - ((TextView)findViewById(R.id.moviedetails_runtime)).setText(movie.runtime); - ((TextView)findViewById(R.id.moviedetails_rating)).setText(String.valueOf(movie.rating)); - - mMovieDetailsController.setupPlayButton((Button)findViewById(R.id.moviedetails_playbutton)); - mMovieDetailsController.loadCover((JewelView)findViewById(R.id.moviedetails_jewelcase)); - mMovieDetailsController.updateMovieDetails(new Handler(), - (TextView)findViewById(R.id.moviedetails_rating_numvotes), - (TextView)findViewById(R.id.moviedetails_studio), - (TextView)findViewById(R.id.moviedetails_plot), - (TextView)findViewById(R.id.moviedetails_parental), - (Button)findViewById(R.id.moviedetails_trailerbutton), - (LinearLayout)findViewById(R.id.moviedetails_datalayout)); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - private static class MovieDetailsController extends AbstractController implements INotifiableController, IController { - - private IVideoManager mVideoManager; - private IControlManager mControlManager; - private final Movie mMovie; - - MovieDetailsController(Activity activity, Movie movie) { - super.onCreate(activity, new Handler()); - mActivity = activity; - mMovie = movie; - mVideoManager = ManagerFactory.getVideoManager(this); - mControlManager = ManagerFactory.getControlManager(this); - } - - public void setupPlayButton(Button button) { - button.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mControlManager.playFile(new DataResponse() { - public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); - } - } - }, mMovie.getPath(), 1, mActivity.getApplicationContext()); - } - }); - } - - public void loadCover(final JewelView jewelView) { - mVideoManager.getCover(new DataResponse() { - public void run() { - if (value != null) { - jewelView.setCover(value); - } - } - }, mMovie, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); - } - - public void updateMovieDetails(final Handler handler, final TextView numVotesView, final TextView studioView, final TextView plotView, final TextView parentalView, final Button trailerButton, final LinearLayout dataLayout) { - mVideoManager.updateMovieDetails(new DataResponse() { - public void run() { - final Movie movie = value; - if (movie == null) { - Log.w(TAG, "updateMovieDetails: value is null."); - return; - } - numVotesView.setText(movie.numVotes > 0 ? " (" + movie.numVotes + " votes)" : ""); - studioView.setText(movie.studio.equals("") ? NO_DATA : movie.studio); - plotView.setText(movie.plot.equals("") ? NO_DATA : movie.plot); - parentalView.setText(movie.rated.equals("") ? NO_DATA : movie.rated); - if (movie.trailerUrl != null && !movie.trailerUrl.equals("")) { - trailerButton.setEnabled(true); - trailerButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mControlManager.playFile(new DataResponse() { - public void run() { - if (value) { - Toast toast = Toast.makeText(mActivity, "Playing trailer for \"" + movie.getName() + "\"...", Toast.LENGTH_LONG); - toast.show(); - } - } - }, movie.trailerUrl, 1, mActivity.getApplicationContext()); - } - }); - } - - if (movie.actors != null) { - final LayoutInflater inflater = mActivity.getLayoutInflater(); - //int n = 0; - for (Actor actor : movie.actors) { - final View view = inflater.inflate(R.layout.actor_item, null); - - ((TextView)view.findViewById(R.id.actor_name)).setText(actor.name); - ((TextView)view.findViewById(R.id.actor_role)).setText("as " + actor.role); - ImageButton img = ((ImageButton)view.findViewById(R.id.actor_image)); - mVideoManager.getCover(new DataResponse() { - public void run() { - if (value != null) { - handler.post(new Runnable() { - public void run() { - ((ImageButton)view.findViewById(R.id.actor_image)).setImageBitmap(value); - } - }); - } - } - }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); - - img.setTag(actor); - img.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - Intent nextActivity; - Actor actor = (Actor)v.getTag(); - nextActivity = new Intent(view.getContext(), ListActivity.class); - nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new MovieListController()); - nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); - mActivity.startActivity(nextActivity); - } - }); - img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - - selectedAcotr = (Actor) v.getTag(); - selectedView = v; - - menu.setHeaderTitle(selectedAcotr.getShortName()); - menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new OnMenuItemClickListener() { - public boolean onMenuItemClick(MenuItem item) { - Intent intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); - if (selectedView.getContext().getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/find?s=nm&q=" + selectedAcotr.getName())); - } - selectedView.getContext().startActivity(intentIMDb); - - return false; - } - }); - } - }); - - dataLayout.addView(view); - //n++; - } - } - } - }, mMovie, mActivity.getApplicationContext()); - } - - public void onActivityPause() { - mVideoManager.setController(null); - mVideoManager.postActivity(); - mControlManager.setController(null); - } - - public void onActivityResume(Activity activity) { - mVideoManager.setController(this); - mControlManager.setController(this); - } - } - - @Override - protected void onResume() { - super.onResume(); - mMovieDetailsController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mMovieDetailsController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; - return handled || super.onKeyUp(keyCode, event); - } - - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - Intent intent = new Intent(MovieDetailsActivity.this, HomeActivity.class); - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mMovieDetailsController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; - return handled || super.onKeyDown(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AbstractController; +import org.xbmc.android.remote.presentation.controller.IController; +import org.xbmc.android.remote.presentation.controller.ListController; +import org.xbmc.android.remote.presentation.controller.MovieListController; +import org.xbmc.android.remote.presentation.widget.JewelView; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Movie; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +public class MovieDetailsActivity extends Activity { + + public static final int CAST_CONTEXT_IMDB = 1; + private static final String NO_DATA = "-"; + private static final int[] sStarImages = {R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, + R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, + R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10}; + private static View selectedView; + private static Actor selectedAcotr; + private ConfigurationManager mConfigurationManager; + private MovieDetailsController mMovieDetailsController; + private KeyTracker mKeyTracker; + + public MovieDetailsActivity() { + if (Integer.parseInt(VERSION.SDK) < 5) { + mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { + + @Override + public void onLongPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + onKeyLongPress(keyCode, event); + } + + @Override + public void onShortPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + MovieDetailsActivity.super.onKeyDown(keyCode, event); + } + + }); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.moviedetails); + + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + final Movie movie = (Movie) getIntent().getSerializableExtra(ListController.EXTRA_MOVIE); + mMovieDetailsController = new MovieDetailsController(this, movie); + + ((TextView) findViewById(R.id.titlebar_text)).setText(movie.getName()); + + Log.i("MovieDetailsActivity", "rating = " + movie.rating + ", index = " + ((int) Math.round(movie.rating % 10) + ) + "."); + if (movie.rating > -1) { + ((ImageView) findViewById(R.id.moviedetails_rating_stars)).setImageResource(sStarImages[(int) Math.round + (movie.rating % 10)]); + } + ((TextView) findViewById(R.id.moviedetails_director)).setText(movie.director); + ((TextView) findViewById(R.id.moviedetails_genre)).setText(movie.genres); + ((TextView) findViewById(R.id.moviedetails_runtime)).setText(movie.runtime); + ((TextView) findViewById(R.id.moviedetails_rating)).setText(String.valueOf(movie.rating)); + + mMovieDetailsController.setupPlayButton((Button) findViewById(R.id.moviedetails_playbutton)); + mMovieDetailsController.loadCover((JewelView) findViewById(R.id.moviedetails_jewelcase)); + mMovieDetailsController.updateMovieDetails(new Handler(), + (TextView) findViewById(R.id.moviedetails_rating_numvotes), + (TextView) findViewById(R.id.moviedetails_studio), + (TextView) findViewById(R.id.moviedetails_plot), + (TextView) findViewById(R.id.moviedetails_parental), + (Button) findViewById(R.id.moviedetails_trailerbutton), + (LinearLayout) findViewById(R.id.moviedetails_datalayout)); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + protected void onResume() { + super.onResume(); + mMovieDetailsController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mMovieDetailsController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; + return handled || super.onKeyUp(keyCode, event); + } + + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + Intent intent = new Intent(MovieDetailsActivity.this, HomeActivity.class); + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mMovieDetailsController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; + return handled || super.onKeyDown(keyCode, event); + } + + private static class MovieDetailsController extends AbstractController implements INotifiableController, + IController { + + private final Movie mMovie; + private IVideoManager mVideoManager; + private IControlManager mControlManager; + + MovieDetailsController(Activity activity, Movie movie) { + super.onCreate(activity, new Handler()); + mActivity = activity; + mMovie = movie; + mVideoManager = ManagerFactory.getVideoManager(this); + mControlManager = ManagerFactory.getControlManager(this); + } + + public void setupPlayButton(Button button) { + button.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + } + } + }, mMovie.getPath(), 1, mActivity.getApplicationContext()); + } + }); + } + + public void loadCover(final JewelView jewelView) { + mVideoManager.getCover(new DataResponse() { + public void run() { + if (value != null) { + jewelView.setCover(value); + } + } + }, mMovie, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); + } + + public void updateMovieDetails(final Handler handler, final TextView numVotesView, final TextView studioView, + final TextView plotView, final TextView parentalView, + final Button trailerButton, final LinearLayout dataLayout) { + mVideoManager.updateMovieDetails(new DataResponse() { + public void run() { + final Movie movie = value; + if (movie == null) { + Log.w(TAG, "updateMovieDetails: value is null."); + return; + } + numVotesView.setText(movie.numVotes > 0 ? " (" + movie.numVotes + " votes)" : ""); + studioView.setText(movie.studio.equals("") ? NO_DATA : movie.studio); + plotView.setText(movie.plot.equals("") ? NO_DATA : movie.plot); + parentalView.setText(movie.rated.equals("") ? NO_DATA : movie.rated); + if (movie.trailerUrl != null && !movie.trailerUrl.equals("")) { + trailerButton.setEnabled(true); + trailerButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + Toast toast = Toast.makeText(mActivity, "Playing trailer for \"" + movie + .getName() + "\"...", Toast.LENGTH_LONG); + toast.show(); + } + } + }, movie.trailerUrl, 1, mActivity.getApplicationContext()); + } + }); + } + + if (movie.actors != null) { + final LayoutInflater inflater = mActivity.getLayoutInflater(); + //int n = 0; + for (Actor actor : movie.actors) { + final View view = inflater.inflate(R.layout.actor_item, null); + + ((TextView) view.findViewById(R.id.actor_name)).setText(actor.name); + ((TextView) view.findViewById(R.id.actor_role)).setText("as " + actor.role); + ImageButton img = ((ImageButton) view.findViewById(R.id.actor_image)); + mVideoManager.getCover(new DataResponse() { + public void run() { + if (value != null) { + handler.post(new Runnable() { + public void run() { + ((ImageButton) view.findViewById(R.id.actor_image)).setImageBitmap + (value); + } + }); + } + } + }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); + + img.setTag(actor); + img.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + Intent nextActivity; + Actor actor = (Actor) v.getTag(); + nextActivity = new Intent(view.getContext(), ListActivity.class); + nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, + new MovieListController()); + nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); + mActivity.startActivity(nextActivity); + } + }); + img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + selectedAcotr = (Actor) v.getTag(); + selectedView = v; + + menu.setHeaderTitle(selectedAcotr.getShortName()); + menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new + OnMenuItemClickListener() { + public boolean onMenuItemClick(MenuItem item) { + Intent intentIMDb = new Intent(Intent.ACTION_VIEW, + Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); + if (selectedView.getContext().getPackageManager().resolveActivity + (intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb" + + ".com/find?s=nm&q=" + selectedAcotr.getName())); + } + selectedView.getContext().startActivity(intentIMDb); + + return false; + } + }); + } + }); + + dataLayout.addView(view); + //n++; + } + } + } + }, mMovie, mActivity.getApplicationContext()); + } + + public void onActivityPause() { + mVideoManager.setController(null); + mVideoManager.postActivity(); + mControlManager.setController(null); + } + + public void onActivityResume(Activity activity) { + mVideoManager.setController(this); + mControlManager.setController(this); + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java similarity index 80% rename from src/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java index 37dcec6b..905137bb 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MovieLibraryActivity.java @@ -1,289 +1,297 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -//import org.xbmc.android.remote.presentation.controller.ActorListController; -import org.xbmc.android.remote.presentation.controller.FileListController; -import org.xbmc.android.remote.presentation.controller.MovieGenreListController; -import org.xbmc.android.remote.presentation.controller.MovieListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.MediaType; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; -import android.widget.ListView; - -public class MovieLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { - - private SlidingTabHost mTabHost; - - private MovieListController mMovieController; - //private ActorListController mActorController; - private MovieGenreListController mGenresController; - private FileListController mFileController; - - private static final int MENU_NOW_PLAYING = 301; - private static final int MENU_UPDATE_LIBRARY = 302; - private static final int MENU_REMOTE = 303; - - private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; - private static final String LAST_MOVIE_TAB_ID = "last_movie_tab_id"; - - private ConfigurationManager mConfigurationManager; - private Handler mHandler; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.movielibrary); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - mTabHost = getTabHost(); - - // add the tabs - mTabHost.addTab(mTabHost.newTabSpec("tab_movies", "Movies", R.drawable.st_movie_on, R.drawable.st_movie_off).setBigIcon(R.drawable.st_movie_over).setContent(R.id.movielist_outer_layout)); - //mTabHost.addTab(mTabHost.newTabSpec("tab_actors", "Actors", R.drawable.st_actor_on, R.drawable.st_actor_off).setBigIcon(R.drawable.st_actor_over).setContent(R.id.actorlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genrelist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id.filelist_outer_layout)); - - mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); - - // assign the gui logic to each tab - mHandler = new Handler(); - mMovieController = new MovieListController(); - mMovieController.findTitleView(findViewById(R.id.movielist_outer_layout)); - mMovieController.findMessageView(findViewById(R.id.movielist_outer_layout)); - - //mActorController = new ActorListController(ActorListController.TYPE_MOVIE); - //mActorController.findTitleView(findViewById(R.id.actorlist_outer_layout)); - //mActorController.findMessageView(findViewById(R.id.actorlist_outer_layout)); - - mGenresController = new MovieGenreListController(MovieGenreListController.TYPE_MOVIE); - mGenresController.findTitleView(findViewById(R.id.genrelist_outer_layout)); - mGenresController.findMessageView(findViewById(R.id.genrelist_outer_layout)); - - mFileController = new FileListController(MediaType.VIDEO); - mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); - mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); - - mTabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - - initTab(tabId); - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_MOVIE_TAB_ID, tabId).commit(); - } - } - }); - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - public void onGlobalLayout() { - mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); - - String lastTab = "tab_movies"; - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_MOVIE_TAB_ID, "tab_movies")); - mTabHost.selectTabByTag(lastTab); - } - - initTab(lastTab); - } - - private void initTab(String tabId) { - if (tabId.equals("tab_movies")) { - mMovieController.onCreate(MovieLibraryActivity.this, mHandler, (ListView)findViewById(R.id.movielist_list)); - } - //if (tabId.equals("tab_actors")) { - // mActorController.onCreate(MovieLibraryActivity.this, mHandler, (ListView)findViewById(R.id.actorlist_list)); - //} - if (tabId.equals("tab_genres")) { - mGenresController.onCreate(MovieLibraryActivity.this, mHandler, (ListView)findViewById(R.id.genrelist_list)); - } - if (tabId.equals("tab_files")) { - mFileController.onCreate(MovieLibraryActivity.this, mHandler, (ListView)findViewById(R.id.filelist_list)); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - switch (mTabHost.getCurrentTab()) { - case 0: - mMovieController.onCreateOptionsMenu(menu); - break; - //case 1: - // mActorController.onCreateOptionsMenu(menu); - // break; - case 1: - mGenresController.onCreateOptionsMenu(menu); - break; - case 2: - mFileController.onCreateOptionsMenu(menu); - break; - } - menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // first, process individual menu events - switch (mTabHost.getCurrentTab()) { - case 0: - mMovieController.onOptionsItemSelected(item); - break; - //case 1: - // mActorController.onOptionsItemSelected(item); - // break; - case 1: - mGenresController.onOptionsItemSelected(item); - break; - case 2: - mFileController.onOptionsItemSelected(item); - break; - } - - // then the generic ones. - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_UPDATE_LIBRARY: - mMovieController.refreshMovieLibrary(this); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - switch (mTabHost.getCurrentTab()) { - case 0: - mMovieController.onCreateContextMenu(menu, v, menuInfo); - break; - //case 1: - // mActorController.onCreateContextMenu(menu, v, menuInfo); - // break; - case 1: - mGenresController.onCreateContextMenu(menu, v, menuInfo); - break; - case 2: - mFileController.onCreateContextMenu(menu, v, menuInfo); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (mTabHost.getCurrentTab()) { - case 0: - mMovieController.onContextItemSelected(item); - break; - //case 1: - // mActorController.onContextItemSelected(item); - // break; - case 1: - mGenresController.onContextItemSelected(item); - break; - case 2: - mFileController.onContextItemSelected(item); - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mMovieController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } - - - @Override - protected void onResume() { - super.onResume(); - mMovieController.onActivityResume(this); - //mActorController.onActivityResume(this); - mGenresController.onActivityResume(this); - mFileController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mMovieController.onActivityPause(); - //mActorController.onActivityPause(); - mGenresController.onActivityPause(); - mFileController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.FileListController; +import org.xbmc.android.remote.presentation.controller.MovieGenreListController; +import org.xbmc.android.remote.presentation.controller.MovieListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.MediaType; +import org.xbmc.eventclient.ButtonCodes; + +//import org.xbmc.android.remote.presentation.controller.ActorListController; + +public class MovieLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { + + private static final int MENU_NOW_PLAYING = 301; + private static final int MENU_UPDATE_LIBRARY = 302; + private static final int MENU_REMOTE = 303; + private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; + private static final String LAST_MOVIE_TAB_ID = "last_movie_tab_id"; + private SlidingTabHost mTabHost; + private MovieListController mMovieController; + //private ActorListController mActorController; + private MovieGenreListController mGenresController; + private FileListController mFileController; + private ConfigurationManager mConfigurationManager; + private Handler mHandler; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.movielibrary); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + mTabHost = getTabHost(); + + // add the tabs + mTabHost.addTab(mTabHost.newTabSpec("tab_movies", "Movies", R.drawable.st_movie_on, + R.drawable.st_movie_off).setBigIcon(R.drawable.st_movie_over).setContent(R.id.movielist_outer_layout)); + //mTabHost.addTab(mTabHost.newTabSpec("tab_actors", "Actors", R.drawable.st_actor_on, + // R.drawable.st_actor_off).setBigIcon(R.drawable.st_actor_over).setContent(R.id.actorlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, + R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genrelist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, + R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id + .filelist_outer_layout)); + + mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); + + // assign the gui logic to each tab + mHandler = new Handler(); + mMovieController = new MovieListController(); + mMovieController.findTitleView(findViewById(R.id.movielist_outer_layout)); + mMovieController.findMessageView(findViewById(R.id.movielist_outer_layout)); + + //mActorController = new ActorListController(ActorListController.TYPE_MOVIE); + //mActorController.findTitleView(findViewById(R.id.actorlist_outer_layout)); + //mActorController.findMessageView(findViewById(R.id.actorlist_outer_layout)); + + mGenresController = new MovieGenreListController(MovieGenreListController.TYPE_MOVIE); + mGenresController.findTitleView(findViewById(R.id.genrelist_outer_layout)); + mGenresController.findMessageView(findViewById(R.id.genrelist_outer_layout)); + + mFileController = new FileListController(MediaType.VIDEO); + mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); + mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); + + mTabHost.setOnTabChangedListener(new OnTabChangeListener() { + public void onTabChanged(String tabId) { + + initTab(tabId); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_MOVIE_TAB_ID, + tabId).commit(); + } + } + }); + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + public void onGlobalLayout() { + mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); + + String lastTab = "tab_movies"; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_MOVIE_TAB_ID, + "tab_movies")); + mTabHost.selectTabByTag(lastTab); + } + + initTab(lastTab); + } + + private void initTab(String tabId) { + if (tabId.equals("tab_movies")) { + mMovieController.onCreate(MovieLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .movielist_list)); + } + //if (tabId.equals("tab_actors")) { + // mActorController.onCreate(MovieLibraryActivity.this, mHandler, + // (ListView)findViewById(R.id.actorlist_list)); + //} + if (tabId.equals("tab_genres")) { + mGenresController.onCreate(MovieLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .genrelist_list)); + } + if (tabId.equals("tab_files")) { + mFileController.onCreate(MovieLibraryActivity.this, mHandler, (ListView) findViewById(R.id.filelist_list)); + } + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + switch (mTabHost.getCurrentTab()) { + case 0: + mMovieController.onCreateOptionsMenu(menu); + break; + //case 1: + // mActorController.onCreateOptionsMenu(menu); + // break; + case 1: + mGenresController.onCreateOptionsMenu(menu); + break; + case 2: + mFileController.onCreateOptionsMenu(menu); + break; + } + menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // first, process individual menu events + switch (mTabHost.getCurrentTab()) { + case 0: + mMovieController.onOptionsItemSelected(item); + break; + //case 1: + // mActorController.onOptionsItemSelected(item); + // break; + case 1: + mGenresController.onOptionsItemSelected(item); + break; + case 2: + mFileController.onOptionsItemSelected(item); + break; + } + + // then the generic ones. + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_UPDATE_LIBRARY: + mMovieController.refreshMovieLibrary(this); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + switch (mTabHost.getCurrentTab()) { + case 0: + mMovieController.onCreateContextMenu(menu, v, menuInfo); + break; + //case 1: + // mActorController.onCreateContextMenu(menu, v, menuInfo); + // break; + case 1: + mGenresController.onCreateContextMenu(menu, v, menuInfo); + break; + case 2: + mFileController.onCreateContextMenu(menu, v, menuInfo); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (mTabHost.getCurrentTab()) { + case 0: + mMovieController.onContextItemSelected(item); + break; + //case 1: + // mActorController.onContextItemSelected(item); + // break; + case 1: + mGenresController.onContextItemSelected(item); + break; + case 2: + mFileController.onContextItemSelected(item); + break; + } + return super.onContextItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mMovieController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } + + + @Override + protected void onResume() { + super.onResume(); + mMovieController.onActivityResume(this); + //mActorController.onActivityResume(this); + mGenresController.onActivityResume(this); + mFileController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mMovieController.onActivityPause(); + //mActorController.onActivityPause(); + mGenresController.onActivityPause(); + mFileController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } +} diff --git a/src/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java similarity index 75% rename from src/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java index 2c96a5e5..feae6d77 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicArtistActivity.java @@ -1,204 +1,208 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AlbumListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.remote.presentation.controller.SongListController; -import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ListView; - -public class MusicArtistActivity extends SlidingTabActivity { - - private SlidingTabHost mTabHost; - private AlbumListController mAlbumController; - private SongListController mSongController; - - private ConfigurationManager mConfigurationManager; - - private static final int MENU_NOW_PLAYING = 101; - private static final int MENU_REMOTE = 102; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.musicartist); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - mTabHost = getTabHost(); - - mTabHost.addTab(mTabHost.newTabSpec("musictab1", "Albums", R.drawable.st_album_on, R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("musictab2", "Songs", R.drawable.st_song_on, R.drawable.st_song_off).setBigIcon(R.drawable.st_song_over).setContent(R.id.songlist_outer_layout)); - mTabHost.setCurrentTab(0); - - final Handler handler = new Handler(); - mAlbumController = new AlbumListController(); - mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); - mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); - mAlbumController.onCreate(this, handler, (ListView)findViewById(R.id.albumlist_list)); // first tab can be updated now. - - mSongController = new SongListController(); - mSongController.findTitleView(findViewById(R.id.songlist_outer_layout)); - mSongController.findMessageView(findViewById(R.id.songlist_outer_layout)); - - mTabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - if (tabId.equals("musictab1")) { - mAlbumController.onCreate(MusicArtistActivity.this, handler, (ListView)findViewById(R.id.albumlist_list)); - } - if (tabId.equals("musictab2")) { - mSongController.onCreate(MusicArtistActivity.this, handler, (ListView)findViewById(R.id.songlist_list)); - } - } - }); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onCreateOptionsMenu(menu); - break; - case 1: - mSongController.onCreateOptionsMenu(menu); - break; - } - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // first, process individual menu events - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onOptionsItemSelected(item); - break; - case 1: - mSongController.onOptionsItemSelected(item); - break; - } - - // then the generic ones. - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onCreateContextMenu(menu, v, menuInfo); - break; - case 1: - mSongController.onCreateContextMenu(menu, v, menuInfo); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onContextItemSelected(item); - break; - case 1: - mSongController.onContextItemSelected(item); - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mAlbumController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onResume() { - super.onResume(); - mAlbumController.onActivityResume(this); - mSongController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mAlbumController.onActivityPause(); - mSongController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AlbumListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.remote.presentation.controller.SongListController; +import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.eventclient.ButtonCodes; + +public class MusicArtistActivity extends SlidingTabActivity { + + private static final int MENU_NOW_PLAYING = 101; + private static final int MENU_REMOTE = 102; + private SlidingTabHost mTabHost; + private AlbumListController mAlbumController; + private SongListController mSongController; + private ConfigurationManager mConfigurationManager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.musicartist); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + mTabHost = getTabHost(); + + mTabHost.addTab(mTabHost.newTabSpec("musictab1", "Albums", R.drawable.st_album_on, + R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("musictab2", "Songs", R.drawable.st_song_on, + R.drawable.st_song_off).setBigIcon(R.drawable.st_song_over).setContent(R.id.songlist_outer_layout)); + mTabHost.setCurrentTab(0); + + final Handler handler = new Handler(); + mAlbumController = new AlbumListController(); + mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); + mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); + mAlbumController.onCreate(this, handler, (ListView) findViewById(R.id.albumlist_list)); // first tab can be + // updated now. + + mSongController = new SongListController(); + mSongController.findTitleView(findViewById(R.id.songlist_outer_layout)); + mSongController.findMessageView(findViewById(R.id.songlist_outer_layout)); + + mTabHost.setOnTabChangedListener(new OnTabChangeListener() { + public void onTabChanged(String tabId) { + if (tabId.equals("musictab1")) { + mAlbumController.onCreate(MusicArtistActivity.this, handler, (ListView) findViewById(R.id + .albumlist_list)); + } + if (tabId.equals("musictab2")) { + mSongController.onCreate(MusicArtistActivity.this, handler, (ListView) findViewById(R.id + .songlist_list)); + } + } + }); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onCreateOptionsMenu(menu); + break; + case 1: + mSongController.onCreateOptionsMenu(menu); + break; + } + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // first, process individual menu events + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onOptionsItemSelected(item); + break; + case 1: + mSongController.onOptionsItemSelected(item); + break; + } + + // then the generic ones. + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onCreateContextMenu(menu, v, menuInfo); + break; + case 1: + mSongController.onCreateContextMenu(menu, v, menuInfo); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onContextItemSelected(item); + break; + case 1: + mSongController.onContextItemSelected(item); + break; + } + return super.onContextItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mAlbumController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onResume() { + super.onResume(); + mAlbumController.onActivityResume(this); + mSongController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mAlbumController.onActivityPause(); + mSongController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } +} diff --git a/src/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java similarity index 74% rename from src/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java index f6046085..e728d722 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicGenreActivity.java @@ -1,227 +1,234 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AlbumListController; -import org.xbmc.android.remote.presentation.controller.ArtistListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.remote.presentation.controller.SongListController; -import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ListView; - -public class MusicGenreActivity extends SlidingTabActivity { - - private SlidingTabHost mTabHost; - private ArtistListController mArtistController; - private AlbumListController mAlbumController; - private SongListController mSongController; - - private static final int MENU_NOW_PLAYING = 201; - private static final int MENU_REMOTE = 202; - - private ConfigurationManager mConfigurationManager; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.musicgenre); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - mTabHost = getTabHost(); - - mTabHost.addTab(mTabHost.newTabSpec("genretab_artists", "Artists", R.drawable.st_artist_on, R.drawable.st_artist_off).setBigIcon(R.drawable.st_artist_over).setContent(R.id.artistlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("genretab_albums", "Albums", R.drawable.st_album_on, R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("genretab_songs", "Songs", R.drawable.st_song_on, R.drawable.st_song_off).setBigIcon(R.drawable.st_song_over).setContent(R.id.songlist_outer_layout)); - mTabHost.setCurrentTab(0); - - final Handler handler = new Handler(); - mArtistController = new ArtistListController(); - mArtistController.findTitleView(findViewById(R.id.artistlist_outer_layout)); - mArtistController.findMessageView(findViewById(R.id.artistlist_outer_layout)); - mArtistController.onCreate(this, handler, (ListView)findViewById(R.id.artistlist_list)); // first tab can be updated now. - - mAlbumController = new AlbumListController(); - mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); - mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); - - mSongController = new SongListController(); - mSongController.findTitleView(findViewById(R.id.songlist_outer_layout)); - mSongController.findMessageView(findViewById(R.id.songlist_outer_layout)); - - mTabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - if (tabId.equals("genretab_artists")) { - mArtistController.onCreate(MusicGenreActivity.this, handler, (ListView)findViewById(R.id.artistlist_list)); - } - if (tabId.equals("genretab_albums")) { - mAlbumController.onCreate(MusicGenreActivity.this, handler, (ListView)findViewById(R.id.albumlist_list)); - } - if (tabId.equals("genretab_songs")) { - mSongController.onCreate(MusicGenreActivity.this, handler, (ListView)findViewById(R.id.songlist_list)); - } - } - }); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - switch (mTabHost.getCurrentTab()) { - case 0: - mArtistController.onCreateOptionsMenu(menu); - break; - case 1: - mAlbumController.onCreateOptionsMenu(menu); - break; - case 2: - mSongController.onCreateOptionsMenu(menu); - break; - } - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // first, process individual menu events - switch (mTabHost.getCurrentTab()) { - case 0: - mArtistController.onOptionsItemSelected(item); - break; - case 1: - mAlbumController.onOptionsItemSelected(item); - break; - case 2: - mSongController.onOptionsItemSelected(item); - break; - } - - // then the generic ones. - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - switch (mTabHost.getCurrentTab()) { - case 0: - mArtistController.onCreateContextMenu(menu, v, menuInfo); - break; - case 1: - mAlbumController.onCreateContextMenu(menu, v, menuInfo); - break; - case 2: - mSongController.onCreateContextMenu(menu, v, menuInfo); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (mTabHost.getCurrentTab()) { - case 0: - mArtistController.onContextItemSelected(item); - break; - case 1: - mAlbumController.onContextItemSelected(item); - break; - case 2: - mSongController.onContextItemSelected(item); - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mArtistController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onResume() { - super.onResume(); - mArtistController.onActivityResume(this); - mAlbumController.onActivityResume(this); - mSongController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mArtistController.onActivityPause(); - mAlbumController.onActivityPause(); - mSongController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AlbumListController; +import org.xbmc.android.remote.presentation.controller.ArtistListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.remote.presentation.controller.SongListController; +import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.eventclient.ButtonCodes; + +public class MusicGenreActivity extends SlidingTabActivity { + + private static final int MENU_NOW_PLAYING = 201; + private static final int MENU_REMOTE = 202; + private SlidingTabHost mTabHost; + private ArtistListController mArtistController; + private AlbumListController mAlbumController; + private SongListController mSongController; + private ConfigurationManager mConfigurationManager; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.musicgenre); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + mTabHost = getTabHost(); + + mTabHost.addTab(mTabHost.newTabSpec("genretab_artists", "Artists", R.drawable.st_artist_on, + R.drawable.st_artist_off).setBigIcon(R.drawable.st_artist_over).setContent(R.id + .artistlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("genretab_albums", "Albums", R.drawable.st_album_on, + R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("genretab_songs", "Songs", R.drawable.st_song_on, + R.drawable.st_song_off).setBigIcon(R.drawable.st_song_over).setContent(R.id.songlist_outer_layout)); + mTabHost.setCurrentTab(0); + + final Handler handler = new Handler(); + mArtistController = new ArtistListController(); + mArtistController.findTitleView(findViewById(R.id.artistlist_outer_layout)); + mArtistController.findMessageView(findViewById(R.id.artistlist_outer_layout)); + mArtistController.onCreate(this, handler, (ListView) findViewById(R.id.artistlist_list)); // first tab can be + // updated now. + + mAlbumController = new AlbumListController(); + mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); + mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); + + mSongController = new SongListController(); + mSongController.findTitleView(findViewById(R.id.songlist_outer_layout)); + mSongController.findMessageView(findViewById(R.id.songlist_outer_layout)); + + mTabHost.setOnTabChangedListener(new OnTabChangeListener() { + public void onTabChanged(String tabId) { + if (tabId.equals("genretab_artists")) { + mArtistController.onCreate(MusicGenreActivity.this, handler, (ListView) findViewById(R.id + .artistlist_list)); + } + if (tabId.equals("genretab_albums")) { + mAlbumController.onCreate(MusicGenreActivity.this, handler, (ListView) findViewById(R.id + .albumlist_list)); + } + if (tabId.equals("genretab_songs")) { + mSongController.onCreate(MusicGenreActivity.this, handler, (ListView) findViewById(R.id + .songlist_list)); + } + } + }); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + switch (mTabHost.getCurrentTab()) { + case 0: + mArtistController.onCreateOptionsMenu(menu); + break; + case 1: + mAlbumController.onCreateOptionsMenu(menu); + break; + case 2: + mSongController.onCreateOptionsMenu(menu); + break; + } + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // first, process individual menu events + switch (mTabHost.getCurrentTab()) { + case 0: + mArtistController.onOptionsItemSelected(item); + break; + case 1: + mAlbumController.onOptionsItemSelected(item); + break; + case 2: + mSongController.onOptionsItemSelected(item); + break; + } + + // then the generic ones. + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + switch (mTabHost.getCurrentTab()) { + case 0: + mArtistController.onCreateContextMenu(menu, v, menuInfo); + break; + case 1: + mAlbumController.onCreateContextMenu(menu, v, menuInfo); + break; + case 2: + mSongController.onCreateContextMenu(menu, v, menuInfo); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (mTabHost.getCurrentTab()) { + case 0: + mArtistController.onContextItemSelected(item); + break; + case 1: + mAlbumController.onContextItemSelected(item); + break; + case 2: + mSongController.onContextItemSelected(item); + break; + } + return super.onContextItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mArtistController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } + + @Override + protected void onResume() { + super.onResume(); + mArtistController.onActivityResume(this); + mAlbumController.onActivityResume(this); + mSongController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mArtistController.onActivityPause(); + mAlbumController.onActivityPause(); + mSongController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } +} diff --git a/src/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java similarity index 75% rename from src/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java index 9a3f62bc..042fe6ce 100644 --- a/src/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/MusicLibraryActivity.java @@ -1,313 +1,322 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AlbumListController; -import org.xbmc.android.remote.presentation.controller.ArtistListController; -import org.xbmc.android.remote.presentation.controller.FileListController; -import org.xbmc.android.remote.presentation.controller.MusicGenreListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; -import android.widget.ListView; - -public class MusicLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { - - private SlidingTabHost mTabHost; - private AlbumListController mAlbumController; - private ArtistListController mArtistController; - private MusicGenreListController mGenreController; - private AlbumListController mCompilationsController; - private FileListController mFileController; - - private static final int MENU_NOW_PLAYING = 301; - private static final int MENU_UPDATE_LIBRARY = 302; - private static final int MENU_REMOTE = 303; - - private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; - private static final String LAST_MUSIC_TAB_ID = "last_music_tab_id"; - - private ConfigurationManager mConfigurationManager; - private Handler mHandler; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.musiclibrary); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - mTabHost = getTabHost(); - - // add the tabs - mTabHost.addTab(mTabHost.newTabSpec("tab_albums", "Albums", R.drawable.st_album_on, R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_artists", "Artists", R.drawable.st_artist_on, R.drawable.st_artist_off).setBigIcon(R.drawable.st_artist_over).setContent(R.id.artists_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genres_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_compilations", "Compilations", R.drawable.st_va_on, R.drawable.st_va_off).setBigIcon(R.drawable.st_va_over).setContent(R.id.compilations_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id.filelist_outer_layout)); - - mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); - - // assign the gui logic to each tab - mHandler = new Handler(); - mAlbumController = new AlbumListController(); - mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); - mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); -// mAlbumController.setGrid((GridView)findViewById(R.id.albumlist_grid)); - - mFileController = new FileListController(); - mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); - mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); - - mArtistController = new ArtistListController(); - mArtistController.findTitleView(findViewById(R.id.artists_outer_layout)); - mArtistController.findMessageView(findViewById(R.id.artists_outer_layout)); - - mGenreController = new MusicGenreListController(); - mGenreController.findTitleView(findViewById(R.id.genres_outer_layout)); - mGenreController.findMessageView(findViewById(R.id.genres_outer_layout)); - - mCompilationsController = new AlbumListController(); - mCompilationsController.findTitleView(findViewById(R.id.compilations_outer_layout)); - mCompilationsController.findMessageView(findViewById(R.id.compilations_outer_layout)); - mCompilationsController.setCompilationsOnly(true); - - mTabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - - initTab(tabId); - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_MUSIC_TAB_ID, tabId).commit(); - } - } - }); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - public void onGlobalLayout() { - mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); - - String lastTab = "tab_albums"; - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_MUSIC_TAB_ID, "tab_albums")); - mTabHost.selectTabByTag(lastTab); - } - - initTab(lastTab); - } - - private void initTab(String tabId) { - if (tabId.equals("tab_albums")) { - mAlbumController.onCreate(MusicLibraryActivity.this, mHandler, (ListView)findViewById(R.id.albumlist_list)); - } - if (tabId.equals("tab_files")) { - mFileController.onCreate(MusicLibraryActivity.this, mHandler, (ListView)findViewById(R.id.filelist_list)); - } - if (tabId.equals("tab_artists")) { - mArtistController.onCreate(MusicLibraryActivity.this, mHandler, (ListView)findViewById(R.id.artists_list)); - } - if (tabId.equals("tab_genres")) { - mGenreController.onCreate(MusicLibraryActivity.this, mHandler, (ListView)findViewById(R.id.genres_list)); - } - if (tabId.equals("tab_compilations")) { - mCompilationsController.onCreate(MusicLibraryActivity.this, mHandler, (ListView)findViewById(R.id.compilations_list)); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onCreateOptionsMenu(menu); - break; - case 1: - mArtistController.onCreateOptionsMenu(menu); - break; - case 2: - mGenreController.onCreateOptionsMenu(menu); - break; - case 3: - mCompilationsController.onCreateOptionsMenu(menu); - break; - case 4: - mFileController.onCreateOptionsMenu(menu); - break; - } - menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // first, process individual menu events - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onOptionsItemSelected(item); - break; - case 1: - mArtistController.onOptionsItemSelected(item); - break; - case 2: - mGenreController.onOptionsItemSelected(item); - break; - case 3: - mCompilationsController.onOptionsItemSelected(item); - break; - case 4: - mFileController.onOptionsItemSelected(item); - break; - } - - // then the generic ones. - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_UPDATE_LIBRARY: - mAlbumController.updateLibrary(); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onCreateContextMenu(menu, v, menuInfo); - break; - case 1: - mArtistController.onCreateContextMenu(menu, v, menuInfo); - break; - case 2: - mGenreController.onCreateContextMenu(menu, v, menuInfo); - break; - case 3: - mCompilationsController.onCreateContextMenu(menu, v, menuInfo); - break; - case 4: - mFileController.onCreateContextMenu(menu, v, menuInfo); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (mTabHost.getCurrentTab()) { - case 0: - mAlbumController.onContextItemSelected(item); - break; - case 1: - mArtistController.onContextItemSelected(item); - break; - case 2: - mGenreController.onContextItemSelected(item); - break; - case 3: - mCompilationsController.onContextItemSelected(item); - break; - case 4: - mFileController.onContextItemSelected(item); - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mAlbumController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } - - - @Override - protected void onResume() { - super.onResume(); - mAlbumController.onActivityResume(this); - mArtistController.onActivityResume(this); - mGenreController.onActivityResume(this); - mCompilationsController.onActivityResume(this); - mFileController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mAlbumController.onActivityPause(); - mArtistController.onActivityPause(); - mGenreController.onActivityPause(); - mCompilationsController.onActivityPause(); - mFileController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AlbumListController; +import org.xbmc.android.remote.presentation.controller.ArtistListController; +import org.xbmc.android.remote.presentation.controller.FileListController; +import org.xbmc.android.remote.presentation.controller.MusicGenreListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.eventclient.ButtonCodes; + +public class MusicLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { + + private static final int MENU_NOW_PLAYING = 301; + private static final int MENU_UPDATE_LIBRARY = 302; + private static final int MENU_REMOTE = 303; + private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; + private static final String LAST_MUSIC_TAB_ID = "last_music_tab_id"; + private SlidingTabHost mTabHost; + private AlbumListController mAlbumController; + private ArtistListController mArtistController; + private MusicGenreListController mGenreController; + private AlbumListController mCompilationsController; + private FileListController mFileController; + private ConfigurationManager mConfigurationManager; + private Handler mHandler; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.musiclibrary); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + mTabHost = getTabHost(); + + // add the tabs + mTabHost.addTab(mTabHost.newTabSpec("tab_albums", "Albums", R.drawable.st_album_on, + R.drawable.st_album_off).setBigIcon(R.drawable.st_album_over).setContent(R.id.albumlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_artists", "Artists", R.drawable.st_artist_on, + R.drawable.st_artist_off).setBigIcon(R.drawable.st_artist_over).setContent(R.id.artists_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, + R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genres_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_compilations", "Compilations", R.drawable.st_va_on, + R.drawable.st_va_off).setBigIcon(R.drawable.st_va_over).setContent(R.id.compilations_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, + R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id + .filelist_outer_layout)); + + mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); + + // assign the gui logic to each tab + mHandler = new Handler(); + mAlbumController = new AlbumListController(); + mAlbumController.findTitleView(findViewById(R.id.albumlist_outer_layout)); + mAlbumController.findMessageView(findViewById(R.id.albumlist_outer_layout)); +// mAlbumController.setGrid((GridView)findViewById(R.id.albumlist_grid)); + + mFileController = new FileListController(); + mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); + mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); + + mArtistController = new ArtistListController(); + mArtistController.findTitleView(findViewById(R.id.artists_outer_layout)); + mArtistController.findMessageView(findViewById(R.id.artists_outer_layout)); + + mGenreController = new MusicGenreListController(); + mGenreController.findTitleView(findViewById(R.id.genres_outer_layout)); + mGenreController.findMessageView(findViewById(R.id.genres_outer_layout)); + + mCompilationsController = new AlbumListController(); + mCompilationsController.findTitleView(findViewById(R.id.compilations_outer_layout)); + mCompilationsController.findMessageView(findViewById(R.id.compilations_outer_layout)); + mCompilationsController.setCompilationsOnly(true); + + mTabHost.setOnTabChangedListener(new OnTabChangeListener() { + public void onTabChanged(String tabId) { + + initTab(tabId); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_MUSIC_TAB_ID, + tabId).commit(); + } + } + }); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + public void onGlobalLayout() { + mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); + + String lastTab = "tab_albums"; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_MUSIC_TAB_ID, + "tab_albums")); + mTabHost.selectTabByTag(lastTab); + } + + initTab(lastTab); + } + + private void initTab(String tabId) { + if (tabId.equals("tab_albums")) { + mAlbumController.onCreate(MusicLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .albumlist_list)); + } + if (tabId.equals("tab_files")) { + mFileController.onCreate(MusicLibraryActivity.this, mHandler, (ListView) findViewById(R.id.filelist_list)); + } + if (tabId.equals("tab_artists")) { + mArtistController.onCreate(MusicLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .artists_list)); + } + if (tabId.equals("tab_genres")) { + mGenreController.onCreate(MusicLibraryActivity.this, mHandler, (ListView) findViewById(R.id.genres_list)); + } + if (tabId.equals("tab_compilations")) { + mCompilationsController.onCreate(MusicLibraryActivity.this, mHandler, + (ListView) findViewById(R.id.compilations_list)); + } + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onCreateOptionsMenu(menu); + break; + case 1: + mArtistController.onCreateOptionsMenu(menu); + break; + case 2: + mGenreController.onCreateOptionsMenu(menu); + break; + case 3: + mCompilationsController.onCreateOptionsMenu(menu); + break; + case 4: + mFileController.onCreateOptionsMenu(menu); + break; + } + menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // first, process individual menu events + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onOptionsItemSelected(item); + break; + case 1: + mArtistController.onOptionsItemSelected(item); + break; + case 2: + mGenreController.onOptionsItemSelected(item); + break; + case 3: + mCompilationsController.onOptionsItemSelected(item); + break; + case 4: + mFileController.onOptionsItemSelected(item); + break; + } + + // then the generic ones. + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_UPDATE_LIBRARY: + mAlbumController.updateLibrary(); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onCreateContextMenu(menu, v, menuInfo); + break; + case 1: + mArtistController.onCreateContextMenu(menu, v, menuInfo); + break; + case 2: + mGenreController.onCreateContextMenu(menu, v, menuInfo); + break; + case 3: + mCompilationsController.onCreateContextMenu(menu, v, menuInfo); + break; + case 4: + mFileController.onCreateContextMenu(menu, v, menuInfo); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (mTabHost.getCurrentTab()) { + case 0: + mAlbumController.onContextItemSelected(item); + break; + case 1: + mArtistController.onContextItemSelected(item); + break; + case 2: + mGenreController.onContextItemSelected(item); + break; + case 3: + mCompilationsController.onContextItemSelected(item); + break; + case 4: + mFileController.onContextItemSelected(item); + break; + } + return super.onContextItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mAlbumController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } + + + @Override + protected void onResume() { + super.onResume(); + mAlbumController.onActivityResume(this); + mArtistController.onActivityResume(this); + mGenreController.onActivityResume(this); + mCompilationsController.onActivityResume(this); + mFileController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mAlbumController.onActivityPause(); + mArtistController.onActivityPause(); + mGenreController.onActivityPause(); + mCompilationsController.onActivityPause(); + mFileController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } +} diff --git a/src/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java similarity index 85% rename from src/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java index c3b9bb5e..c4b4d21d 100644 --- a/src/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/NowPlayingActivity.java @@ -21,19 +21,6 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.NowPlayingController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.remote.presentation.widget.JewelView; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.object.Song; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -51,8 +38,23 @@ import android.widget.SeekBar; import android.widget.TextView; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.NowPlayingController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.remote.presentation.widget.JewelView; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.object.Song; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + public class NowPlayingActivity extends Activity { + private static final int MENU_REMOTE = 303; + private static final int MENU_MONITOR_MODE = 304; private TextView mTopTitleView; private TextView mBottomTitleView; private TextView mBottomSubtitleView; @@ -60,43 +62,39 @@ public class NowPlayingActivity extends Activity { private TextView mCounterRightView; private ImageButton mPlayPauseView; private SeekBar mSeekBar; - private ConfigurationManager mConfigurationManager; private NowPlayingController mNowPlayingController; private KeyTracker mKeyTracker; - private boolean mMonitorMode = false; - private static final int MENU_REMOTE = 303; - private static final int MENU_MONITOR_MODE = 304; - public NowPlayingActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { + if (Integer.parseInt(VERSION.SDK) < 5) { mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - + @Override public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { + Stage stage, int duration) { onKeyLongPress(keyCode, event); } - + @Override public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { + Stage stage, int duration) { callSuperOnKeyDown(keyCode, event); } - + }); - }; - } - + } + ; + } + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + setContentView(R.layout.nowplaying); mNowPlayingController = new NowPlayingController(this, new Handler()); @@ -108,13 +106,13 @@ public void onCreate(Bundle savedInstanceState) { mCounterLeftView = (TextView) findViewById(R.id.now_playing_counter_left); mCounterRightView = (TextView) findViewById(R.id.now_playing_counter_right); mPlayPauseView = (ImageButton) findViewById(R.id.MediaPlayPauseButton); - + // JewelView jewelCase = (JewelView)findViewById(R.id.now_playing_jewelcase); - + // RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(arg0, arg1) // layoutParams.height = 140; // layoutParams.width = RelativeLayout.LayoutParams.WRAP_CONTENT; - + /// layoutParams.addRule(RelativeLayout.ABOVE, R.id.now_playing_bottombar); // jewelCase.setLayoutParams(layoutParams); @@ -127,13 +125,13 @@ public void onCreate(Bundle savedInstanceState) { mConfigurationManager = ConfigurationManager.getInstance(this); - mNowPlayingController.setupButtons(mSeekBar, - findViewById(R.id.MediaPreviousButton), - findViewById(R.id.MediaStopButton), - findViewById(R.id.MediaPlayPauseButton), - findViewById(R.id.MediaNextButton), - findViewById(R.id.MediaPlaylistButton) - ); + mNowPlayingController.setupButtons(mSeekBar, + findViewById(R.id.MediaPreviousButton), + findViewById(R.id.MediaStopButton), + findViewById(R.id.MediaPlayPauseButton), + findViewById(R.id.MediaNextButton), + findViewById(R.id.MediaPlaylistButton) + ); } @@ -156,7 +154,7 @@ public void updateProgress(int duration, int time, boolean paused) { mCounterLeftView.setText(Song.getDuration(time + 1)); mCounterRightView.setVisibility(View.VISIBLE); mCounterRightView.setText(duration <= 0 ? "unknown" : "-" + Song.getDuration(duration - time - 1)); - if(paused) + if (paused) mPlayPauseView.setBackgroundResource(R.drawable.now_playing_play); else mPlayPauseView.setBackgroundResource(R.drawable.now_playing_pause); @@ -190,19 +188,20 @@ public boolean onPrepareOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_MONITOR_MODE: - switchMonitorMode(); - return true; + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_MONITOR_MODE: + switchMonitorMode(); + return true; } return super.onOptionsItemSelected(item); } @@ -211,15 +210,15 @@ public boolean onOptionsItemSelected(MenuItem item) { public boolean onKeyDown(int keyCode, KeyEvent event) { IEventClientManager client = ManagerFactory.getEventClientManager(mNowPlayingController); switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); - return true; - case KeyEvent.KEYCODE_SEARCH: - switchMonitorMode(); - return true; + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_SEARCH: + switchMonitorMode(); + return true; /* case KeyEvent.KEYCODE_PAGE_UP: switchMonitorMode(); return true;*/ @@ -274,16 +273,16 @@ public boolean onKeyUp(int keyCode, KeyEvent event) { boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; return handled || super.onKeyUp(keyCode, event); } - + @Override public void onBackPressed() { if (isTaskRoot()) { - Intent intent = new Intent(NowPlayingActivity.this, HomeActivity.class ); + Intent intent = new Intent(NowPlayingActivity.this, HomeActivity.class); NowPlayingActivity.this.startActivity(intent); } - + finish(); - - return; + + return; } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java similarity index 90% rename from src/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java index 06f748c7..3d345d0d 100644 --- a/src/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/PlaylistActivity.java @@ -21,16 +21,6 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.PlaylistController; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.content.Intent; import android.os.Build.VERSION; @@ -48,6 +38,16 @@ import android.widget.ListView; import android.widget.TextView; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.PlaylistController; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + public class PlaylistActivity extends Activity { private PlaylistController mPlaylistController; @@ -59,37 +59,37 @@ public class PlaylistActivity extends Activity { private ConfigurationManager mConfigurationManager; private KeyTracker mKeyTracker; - + public PlaylistActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { + if (Integer.parseInt(VERSION.SDK) < 5) { mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - + @Override public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { + Stage stage, int duration) { onKeyLongPress(keyCode, event); } - + @Override public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { + Stage stage, int duration) { callSuperOnKeyDown(keyCode, event); } - + }); } } - + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.playlist); // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); topFrame.setForeground(null); // cache references for faster access @@ -105,23 +105,23 @@ public void onCreate(Bundle savedInstanceState) { // setup buttons mPlaylistController.setupButtons( - findViewById(R.id.MediaPreviousButton), - findViewById(R.id.MediaStopButton), - findViewById(R.id.MediaPlayPauseButton), - findViewById(R.id.MediaNextButton)); - + findViewById(R.id.MediaPreviousButton), + findViewById(R.id.MediaStopButton), + findViewById(R.id.MediaPlayPauseButton), + findViewById(R.id.MediaNextButton)); + mConfigurationManager = ConfigurationManager.getInstance(this); } - + public void setTime(String time) { mLabel1.setText(time); mPlayPauseView.setBackgroundResource(R.drawable.now_playing_pause); } - + public void setNumItems(String numItems) { mLabel2.setText(numItems); } - + public void clear() { mLabel1.setText("--:--"); mPlayPauseView.setBackgroundResource(R.drawable.now_playing_play); @@ -164,37 +164,37 @@ public boolean onContextItemSelected(MenuItem item) { mPlaylistController.onContextItemSelected(item); return super.onContextItemSelected(item); } - + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { IEventClientManager client = ManagerFactory.getEventClientManager(mPlaylistController); switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); return true; case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); return true; } client.setController(null); - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; return handled || super.onKeyDown(keyCode, event); } - + protected void callSuperOnKeyDown(int keyCode, KeyEvent event) { super.onKeyDown(keyCode, event); } - + public boolean onKeyLongPress(int keyCode, KeyEvent event) { Intent intent = new Intent(PlaylistActivity.this, HomeActivity.class); intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); return true; } - + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; return handled || super.onKeyUp(keyCode, event); } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/RemoteActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/RemoteActivity.java similarity index 95% rename from src/org/xbmc/android/remote/presentation/activity/RemoteActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/RemoteActivity.java index 4830c755..81fdaa3b 100644 --- a/src/org/xbmc/android/remote/presentation/activity/RemoteActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/RemoteActivity.java @@ -21,20 +21,12 @@ package org.xbmc.android.remote.presentation.activity; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.Intent; -import android.os.Bundle; import android.os.Build.VERSION; +import android.os.Bundle; import android.util.Log; import android.view.Display; import android.view.KeyEvent; @@ -48,10 +40,18 @@ import android.widget.FrameLayout; import android.widget.ViewFlipper; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + /** * Activity for remote control. At the moment that's the good ol' Xbox remote * control, more to come... - * + * * @author Team XBMC */ public class RemoteActivity extends Activity { @@ -70,14 +70,14 @@ public class RemoteActivity extends Activity { private float mOldTouchValue; public RemoteActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { + if (Integer.parseInt(VERSION.SDK) < 5) { mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - + @Override public void onLongPressBack(int keyCode, KeyEvent event, Stage stage, int duration) { onKeyLongPress(keyCode, event); } - + @Override public void onShortPressBack(int keyCode, KeyEvent event, Stage stage, int duration) { RemoteActivity.super.onKeyDown(keyCode, event); @@ -89,10 +89,10 @@ public void onShortPressBack(int keyCode, KeyEvent event, Stage stage, int durat @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + Display d = getWindowManager().getDefaultDisplay(); // set display size - ThumbSize.setScreenSize(d.getWidth(), d.getHeight()); + ThumbSize.setScreenSize(d.getWidth(), d.getHeight()); final int w = d.getWidth(); final int h = d.getHeight(); final double ar = w > h ? (double) w / (double) h : (double) h / (double) w; @@ -103,7 +103,7 @@ public void onCreate(Bundle savedInstanceState) { Log.i(TAG, "AR = " + ar + ", normal layout."); setContentView(R.layout.remote_xbox); } - + // mViewFlipper = (ViewFlipper) findViewById(R.id.remote_flipper); @@ -149,7 +149,7 @@ public boolean onTrackballEvent(MotionEvent event) { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; return handled || mRemoteController.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); } @@ -157,7 +157,8 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override protected void onResume() { super.onResume(); - getSharedPreferences("global", Context.MODE_PRIVATE).edit().putInt(RemoteController.LAST_REMOTE_PREFNAME, RemoteController.LAST_REMOTE_BUTTON).commit(); + getSharedPreferences("global", Context.MODE_PRIVATE).edit().putInt(RemoteController.LAST_REMOTE_PREFNAME, + RemoteController.LAST_REMOTE_BUTTON).commit(); mRemoteController.onActivityResume(this); mConfigurationManager.onActivityResume(this); } @@ -175,7 +176,7 @@ protected void onPause() { private void setupButtons() { // display - mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnDisplay),ButtonCodes.REMOTE_DISPLAY); + mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnDisplay), ButtonCodes.REMOTE_DISPLAY); mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnVideo), ButtonCodes.REMOTE_MY_VIDEOS); mRemoteController.setupButton(findViewById(R.id.RemoteXboxImgBtnMusic), ButtonCodes.REMOTE_MY_MUSIC); @@ -243,7 +244,7 @@ public boolean onOptionsItemSelected(MenuItem item) { @Override public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; return handled || super.onKeyUp(keyCode, event); } @@ -253,14 +254,14 @@ public boolean onKeyLongPress(int keyCode, KeyEvent event) { startActivity(intent); return true; } - + @Override public boolean onTouchEvent(MotionEvent touchEvent) { // ignore all that on hdpi displays if (mViewFlipper == null) { return false; } - + // determine the current view and // who is to the right and to the left. final View currentView = mViewFlipper.getCurrentView(); @@ -287,7 +288,7 @@ public boolean onTouchEvent(MotionEvent touchEvent) { } switch (touchEvent.getAction()) { - case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_DOWN: // freezy: the mousepad seems to always flicker // at the start of the move action (i.e. action_down) // so i tried this but it doesn't seem to work. @@ -298,11 +299,11 @@ public boolean onTouchEvent(MotionEvent touchEvent) { * mMousePadView.setVisibility(View.INVISIBLE); } */ mOldTouchValue = touchEvent.getX(); - break; - - case MotionEvent.ACTION_UP: + break; + + case MotionEvent.ACTION_UP: float currentX = touchEvent.getX(); - + if (mOldTouchValue < currentX) { mViewFlipper.setInAnimation(AnimationHelper.inFromLeftAnimation()); mViewFlipper.setOutAnimation(AnimationHelper.outToRightAnimation()); @@ -313,13 +314,13 @@ public boolean onTouchEvent(MotionEvent touchEvent) { mViewFlipper.setOutAnimation(AnimationHelper.outToLeftAnimation()); mViewFlipper.showNext(); } - - break; - - case MotionEvent.ACTION_MOVE: + + break; + + case MotionEvent.ACTION_MOVE: leftView.setVisibility(View.VISIBLE); rightView.setVisibility(View.VISIBLE); - + Log.d("current layout:", "left: " + Integer.toString(currentView.getLeft()) + " right: " + Integer.toString(currentView.getRight())); @@ -329,22 +330,22 @@ public boolean onTouchEvent(MotionEvent touchEvent) { Log.d("next layout:", "left: " + Integer.toString(rightView.getLeft()) + " right: " + Integer.toString(rightView.getRight())); - + // move the current view to the left or right. currentView.layout((int) (touchEvent.getX() - mOldTouchValue), currentView.getTop(), (int) (touchEvent.getX() - mOldTouchValue) + 320, currentView.getBottom()); - + // place this view just left of the currentView leftView.layout(currentView.getLeft() - 320, leftView.getTop(), currentView.getLeft(), leftView.getBottom()); - + // place this view just right of the currentView rightView.layout(currentView.getRight(), rightView.getTop(), currentView.getRight() + 320, rightView.getBottom()); - break; - + break; + } return false; } diff --git a/src/org/xbmc/android/remote/presentation/activity/SettingsActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/SettingsActivity.java similarity index 91% rename from src/org/xbmc/android/remote/presentation/activity/SettingsActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/SettingsActivity.java index 709946d4..1e6ec114 100644 --- a/src/org/xbmc/android/remote/presentation/activity/SettingsActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/SettingsActivity.java @@ -1,110 +1,110 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.SettingsController; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceActivity; -import android.preference.PreferenceScreen; -import android.view.Display; -import android.view.KeyEvent; - -/** - * The XBMC remote's preferences page. This is a little special since we want - * the actual value of the setting in the summary text. It can be set using the - * %value% place holder. - *

- * For that we needed to cache the original (with %value% intact) summaries, - * which then will be replaced upon change or application start. - * - * @author Team XBMC - */ -public class SettingsActivity extends PreferenceActivity { - - public final static String SUMMARY_VALUE_PLACEHOLDER = "%value%"; - public final static String JUMP_TO = "jump_to"; - public final static int JUMP_TO_INSTANCES = 1; - - private ConfigurationManager mConfigurationManager; - private SettingsController mSettingsController; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.preferences); - - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - mSettingsController = new SettingsController(this, new Handler()); - mSettingsController.registerOnSharedPreferenceChangeListener(this); - mConfigurationManager = ConfigurationManager.getInstance(this); - final int jumpTo = getIntent().getIntExtra(JUMP_TO, 0); - switch (jumpTo) { - case JUMP_TO_INSTANCES: - setPreferenceScreen((PreferenceScreen)getPreferenceScreen().findPreference("setting_instances")); - break; - default: - } - } - - @Override - protected void onResume() { - super.onResume(); - mSettingsController.onActivityResume(this); - mSettingsController.updateSummaries(); - mConfigurationManager.onActivityResume(this); - getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(mSettingsController); - } - - @Override - protected void onPause() { - super.onPause(); - // Unregister the listener whenever a key changes - getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(mSettingsController); - mSettingsController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mSettingsController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceActivity; +import android.preference.PreferenceScreen; +import android.view.Display; +import android.view.KeyEvent; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.SettingsController; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +/** + * The XBMC remote's preferences page. This is a little special since we want + * the actual value of the setting in the summary text. It can be set using the + * %value% place holder. + *

+ * For that we needed to cache the original (with %value% intact) summaries, + * which then will be replaced upon change or application start. + * + * @author Team XBMC + */ +public class SettingsActivity extends PreferenceActivity { + + public final static String SUMMARY_VALUE_PLACEHOLDER = "%value%"; + public final static String JUMP_TO = "jump_to"; + public final static int JUMP_TO_INSTANCES = 1; + + private ConfigurationManager mConfigurationManager; + private SettingsController mSettingsController; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + mSettingsController = new SettingsController(this, new Handler()); + mSettingsController.registerOnSharedPreferenceChangeListener(this); + mConfigurationManager = ConfigurationManager.getInstance(this); + final int jumpTo = getIntent().getIntExtra(JUMP_TO, 0); + switch (jumpTo) { + case JUMP_TO_INSTANCES: + setPreferenceScreen((PreferenceScreen) getPreferenceScreen().findPreference("setting_instances")); + break; + default: + } + } + + @Override + protected void onResume() { + super.onResume(); + mSettingsController.onActivityResume(this); + mSettingsController.updateSummaries(); + mConfigurationManager.onActivityResume(this); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(mSettingsController); + } + + @Override + protected void onPause() { + super.onPause(); + // Unregister the listener whenever a key changes + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(mSettingsController); + mSettingsController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mSettingsController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java similarity index 67% rename from src/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java index dc0c65a1..a6a81e3b 100644 --- a/src/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowDetailsActivity.java @@ -1,295 +1,306 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.AbstractController; -import org.xbmc.android.remote.presentation.controller.IController; -import org.xbmc.android.remote.presentation.controller.ListController; -import org.xbmc.android.remote.presentation.controller.TvShowListController; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.TvShow; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.net.Uri; -import android.os.Build.VERSION; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.ContextMenu; -import android.view.Display; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.View.OnClickListener; -import android.view.View.OnCreateContextMenuListener; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -public class TvShowDetailsActivity extends Activity { - - private static final String NO_DATA = "-"; - - public static final int CAST_CONTEXT_IMDB = 1; - private static View selectedView; - private static Actor selectedAcotr; - - private ConfigurationManager mConfigurationManager; - private TvShowDetailsController mTvShowDetailsController; - - private KeyTracker mKeyTracker; - - private static final int[] sStarImages = { R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10 }; - - public TvShowDetailsActivity() { - if(Integer.parseInt(VERSION.SDK) < 5) { - mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - - @Override - public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - onKeyLongPress(keyCode, event); - } - - @Override - public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - TvShowDetailsActivity.super.onKeyDown(keyCode, event); - } - - }); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.tvdetails); - - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - final TvShow show = (TvShow)getIntent().getSerializableExtra(ListController.EXTRA_TVSHOW); - mTvShowDetailsController = new TvShowDetailsController(this, show); - - ((TextView)findViewById(R.id.titlebar_text)).setText(show.getName()); - - Log.i("EpisodeDetailsActivity", "rating = " + show.rating + ", index = " + ((int)Math.round(show.rating % 10)) + "."); - if (show.rating > -1) { - ((ImageView)findViewById(R.id.tvdetails_rating_stars)).setImageResource(sStarImages[(int)Math.round(show.rating % 10)]); - } - ((TextView)findViewById(R.id.tvdetails_first_aired)).setText(show.firstAired); - ((TextView)findViewById(R.id.tvdetails_genre)).setText(show.genre); - ((TextView)findViewById(R.id.tvdetails_rating)).setText(String.valueOf(show.rating)); - - mTvShowDetailsController.setupPlayButton((Button)findViewById(R.id.tvdetails_playbutton)); - mTvShowDetailsController.loadCover((ImageView)findViewById(R.id.tvdetails_thumb)); - mTvShowDetailsController.updateTvShowDetails( - (TextView)findViewById(R.id.tvdetails_episodes), - (TextView)findViewById(R.id.tvdetails_studio), - (TextView)findViewById(R.id.tvdetails_parental), - (TextView)findViewById(R.id.tvdetails_plot), - (LinearLayout)findViewById(R.id.tvdetails_datalayout)); - - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - private static class TvShowDetailsController extends AbstractController implements INotifiableController, IController { - - private ITvShowManager mShowManager; - private IControlManager mControlManager; - private final TvShow mShow; - - TvShowDetailsController(Activity activity, TvShow show) { - super.onCreate(activity, new Handler()); - mActivity = activity; - mShow = show; - mShowManager = ManagerFactory.getTvManager(this); - mControlManager = ManagerFactory.getControlManager(this); - } - - public void setupPlayButton(Button button) { - button.setText("Play Show"); - button.setEnabled(false); - } - - public void loadCover(final ImageView imageView) { - mShowManager.getCover(new DataResponse() { - public void run() { - if (value == null) { - imageView.setImageResource(R.drawable.nocover); - } else { - imageView.setImageBitmap(value); - } - } - }, mShow, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); - } - - public void updateTvShowDetails(final TextView episodesVew, final TextView studioView, final TextView parentalView, final TextView plotView, final LinearLayout dataLayout) { - mShowManager.updateTvShowDetails(new DataResponse() { - public void run() { - final TvShow show = value; - episodesVew.setText(show.numEpisodes + " (" + show.watchedEpisodes + " Watched - " + (show.numEpisodes - show.watchedEpisodes) + " Unwatched)"); - studioView.setText(show.network); - parentalView.setText(show.contentRating.equals("") ? NO_DATA : show.contentRating); - plotView.setText(show.summary.equals("") ? NO_DATA : show.summary); - - if (show.actors != null) { - final LayoutInflater inflater = mActivity.getLayoutInflater(); - for (Actor actor : show.actors) { - final View view = inflater.inflate(R.layout.actor_item, null); - - ((TextView)view.findViewById(R.id.actor_name)).setText(actor.name); - ((TextView)view.findViewById(R.id.actor_role)).setText("as " + actor.role); - ImageButton img = ((ImageButton)view.findViewById(R.id.actor_image)); - mShowManager.getCover(new DataResponse() { - public void run() { - if (value != null) { - ((ImageButton)view.findViewById(R.id.actor_image)).setImageBitmap(value); - } - } - }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); - - img.setTag(actor); - img.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - Intent nextActivity; - Actor actor = (Actor)v.getTag(); - nextActivity = new Intent(view.getContext(), ListActivity.class); - nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new TvShowListController()); - nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); - mActivity.startActivity(nextActivity); - } - }); - img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { - - selectedAcotr = (Actor) v.getTag(); - selectedView = v; - - // final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; - menu.setHeaderTitle(selectedAcotr.getShortName()); - menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new OnMenuItemClickListener( ) { - - public boolean onMenuItemClick(MenuItem item) { - Intent intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); - if (selectedView.getContext().getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/find?s=nm&q=" + selectedAcotr.getName())); - } - selectedView.getContext().startActivity(intentIMDb); - - return false; - } - }); - }; - }); - - dataLayout.addView(view); - } - } - } - }, mShow, mActivity.getApplicationContext()); - } - - public void onActivityPause() { - mShowManager.setController(null); -// mShowManager.postActivity(); - mControlManager.setController(null); - } - - public void onActivityResume(Activity activity) { - mShowManager.setController(this); - mControlManager.setController(this); - } - } - - @Override - protected void onResume() { - super.onResume(); - mTvShowDetailsController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mTvShowDetailsController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - Intent intent = new Intent(TvShowDetailsActivity.this, HomeActivity.class); - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; - return handled || super.onKeyUp(keyCode, event); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mTvShowDetailsController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; - return handled || super.onKeyDown(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.Display; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MenuItem.OnMenuItemClickListener; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnCreateContextMenuListener; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.AbstractController; +import org.xbmc.android.remote.presentation.controller.IController; +import org.xbmc.android.remote.presentation.controller.ListController; +import org.xbmc.android.remote.presentation.controller.TvShowListController; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.TvShow; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.eventclient.ButtonCodes; + +public class TvShowDetailsActivity extends Activity { + + public static final int CAST_CONTEXT_IMDB = 1; + private static final String NO_DATA = "-"; + private static final int[] sStarImages = {R.drawable.stars_0, R.drawable.stars_1, R.drawable.stars_2, + R.drawable.stars_3, R.drawable.stars_4, R.drawable.stars_5, R.drawable.stars_6, R.drawable.stars_7, + R.drawable.stars_8, R.drawable.stars_9, R.drawable.stars_10}; + private static View selectedView; + private static Actor selectedAcotr; + private ConfigurationManager mConfigurationManager; + private TvShowDetailsController mTvShowDetailsController; + private KeyTracker mKeyTracker; + + public TvShowDetailsActivity() { + if (Integer.parseInt(VERSION.SDK) < 5) { + mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { + + @Override + public void onLongPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + onKeyLongPress(keyCode, event); + } + + @Override + public void onShortPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + TvShowDetailsActivity.super.onKeyDown(keyCode, event); + } + + }); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tvdetails); + + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + final TvShow show = (TvShow) getIntent().getSerializableExtra(ListController.EXTRA_TVSHOW); + mTvShowDetailsController = new TvShowDetailsController(this, show); + + ((TextView) findViewById(R.id.titlebar_text)).setText(show.getName()); + + Log.i("EpisodeDetailsActivity", "rating = " + show.rating + ", index = " + ((int) Math.round(show.rating % 10) + ) + "."); + if (show.rating > -1) { + ((ImageView) findViewById(R.id.tvdetails_rating_stars)).setImageResource(sStarImages[(int) Math.round(show + .rating % 10)]); + } + ((TextView) findViewById(R.id.tvdetails_first_aired)).setText(show.firstAired); + ((TextView) findViewById(R.id.tvdetails_genre)).setText(show.genre); + ((TextView) findViewById(R.id.tvdetails_rating)).setText(String.valueOf(show.rating)); + + mTvShowDetailsController.setupPlayButton((Button) findViewById(R.id.tvdetails_playbutton)); + mTvShowDetailsController.loadCover((ImageView) findViewById(R.id.tvdetails_thumb)); + mTvShowDetailsController.updateTvShowDetails( + (TextView) findViewById(R.id.tvdetails_episodes), + (TextView) findViewById(R.id.tvdetails_studio), + (TextView) findViewById(R.id.tvdetails_parental), + (TextView) findViewById(R.id.tvdetails_plot), + (LinearLayout) findViewById(R.id.tvdetails_datalayout)); + + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + @Override + protected void onResume() { + super.onResume(); + mTvShowDetailsController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mTvShowDetailsController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + Intent intent = new Intent(TvShowDetailsActivity.this, HomeActivity.class); + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; + return handled || super.onKeyUp(keyCode, event); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mTvShowDetailsController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; + return handled || super.onKeyDown(keyCode, event); + } + + private static class TvShowDetailsController extends AbstractController implements INotifiableController, + IController { + + private final TvShow mShow; + private ITvShowManager mShowManager; + private IControlManager mControlManager; + + TvShowDetailsController(Activity activity, TvShow show) { + super.onCreate(activity, new Handler()); + mActivity = activity; + mShow = show; + mShowManager = ManagerFactory.getTvManager(this); + mControlManager = ManagerFactory.getControlManager(this); + } + + public void setupPlayButton(Button button) { + button.setText("Play Show"); + button.setEnabled(false); + } + + public void loadCover(final ImageView imageView) { + mShowManager.getCover(new DataResponse() { + public void run() { + if (value == null) { + imageView.setImageResource(R.drawable.nocover); + } else { + imageView.setImageBitmap(value); + } + } + }, mShow, ThumbSize.BIG, null, mActivity.getApplicationContext(), false); + } + + public void updateTvShowDetails(final TextView episodesVew, final TextView studioView, + final TextView parentalView, final TextView plotView, + final LinearLayout dataLayout) { + mShowManager.updateTvShowDetails(new DataResponse() { + public void run() { + final TvShow show = value; + episodesVew.setText(show.numEpisodes + " (" + show.watchedEpisodes + " Watched - " + (show + .numEpisodes - show.watchedEpisodes) + " Unwatched)"); + studioView.setText(show.network); + parentalView.setText(show.contentRating.equals("") ? NO_DATA : show.contentRating); + plotView.setText(show.summary.equals("") ? NO_DATA : show.summary); + + if (show.actors != null) { + final LayoutInflater inflater = mActivity.getLayoutInflater(); + for (Actor actor : show.actors) { + final View view = inflater.inflate(R.layout.actor_item, null); + + ((TextView) view.findViewById(R.id.actor_name)).setText(actor.name); + ((TextView) view.findViewById(R.id.actor_role)).setText("as " + actor.role); + ImageButton img = ((ImageButton) view.findViewById(R.id.actor_image)); + mShowManager.getCover(new DataResponse() { + public void run() { + if (value != null) { + ((ImageButton) view.findViewById(R.id.actor_image)).setImageBitmap(value); + } + } + }, actor, ThumbSize.SMALL, null, mActivity.getApplicationContext(), false); + + img.setTag(actor); + img.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + Intent nextActivity; + Actor actor = (Actor) v.getTag(); + nextActivity = new Intent(view.getContext(), ListActivity.class); + nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, + new TvShowListController()); + nextActivity.putExtra(ListController.EXTRA_ACTOR, actor); + mActivity.startActivity(nextActivity); + } + }); + img.setOnCreateContextMenuListener(new OnCreateContextMenuListener() { + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + selectedAcotr = (Actor) v.getTag(); + selectedView = v; + + // final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo) + // menuInfo).targetView; + menu.setHeaderTitle(selectedAcotr.getShortName()); + menu.add(0, CAST_CONTEXT_IMDB, 1, "Open IMDb").setOnMenuItemClickListener(new + OnMenuItemClickListener() { + + public boolean onMenuItemClick(MenuItem item) { + Intent intentIMDb = new Intent(Intent.ACTION_VIEW, + Uri.parse("imdb:///find?s=nm&q=" + selectedAcotr.getName())); + if (selectedView.getContext().getPackageManager().resolveActivity + (intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb" + + ".com/find?s=nm&q=" + selectedAcotr.getName())); + } + selectedView.getContext().startActivity(intentIMDb); + + return false; + } + }); + } + + ; + }); + + dataLayout.addView(view); + } + } + } + }, mShow, mActivity.getApplicationContext()); + } + + public void onActivityPause() { + mShowManager.setController(null); +// mShowManager.postActivity(); + mControlManager.setController(null); + } + + public void onActivityResume(Activity activity) { + mShowManager.setController(this); + mControlManager.setController(this); + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java similarity index 79% rename from src/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java index deb3f751..1b78d1a4 100644 --- a/src/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/TvShowLibraryActivity.java @@ -1,289 +1,295 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.controller.ActorListController; -import org.xbmc.android.remote.presentation.controller.FileListController; -import org.xbmc.android.remote.presentation.controller.MovieGenreListController; -import org.xbmc.android.remote.presentation.controller.RemoteController; -import org.xbmc.android.remote.presentation.controller.TvShowListController; -import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.type.MediaType; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewTreeObserver; -import android.widget.FrameLayout; -import android.widget.ListView; - -public class TvShowLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { - - private SlidingTabHost mTabHost; - - private TvShowListController mTvShowController; - //private ActorListController mActorController; - private MovieGenreListController mGenresController; - private FileListController mFileController; - - private static final int MENU_NOW_PLAYING = 301; - private static final int MENU_UPDATE_LIBRARY = 302; - private static final int MENU_REMOTE = 303; - - private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; - private static final String LAST_TVSHOW_TAB_ID = "last_tvshow_tab_id"; - - private ConfigurationManager mConfigurationManager; - private Handler mHandler; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.tvlibrary); - - // remove nasty top fading edge - FrameLayout topFrame = (FrameLayout)findViewById(android.R.id.content); - topFrame.setForeground(null); - - mTabHost = getTabHost(); - - // add the tabs - mTabHost.addTab(mTabHost.newTabSpec("tab_tv", "TV Shows", R.drawable.st_tv_on, R.drawable.st_tv_off).setBigIcon(R.drawable.st_tv_over).setContent(R.id.tvshowlist_outer_layout)); - //mTabHost.addTab(mTabHost.newTabSpec("tab_actors", "Actors", R.drawable.st_actor_on, R.drawable.st_actor_off).setBigIcon(R.drawable.st_actor_over).setContent(R.id.actorlist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genrelist_outer_layout)); - mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id.filelist_outer_layout)); - - mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); - - // assign the gui logic to each tab - mHandler = new Handler(); - mTvShowController = new TvShowListController(); - mTvShowController.findTitleView(findViewById(R.id.tvshowlist_outer_layout)); - mTvShowController.findMessageView(findViewById(R.id.tvshowlist_outer_layout)); - - //mActorController = new ActorListController(ActorListController.TYPE_TVSHOW); - //mActorController.findTitleView(findViewById(R.id.actorlist_outer_layout)); - //mActorController.findMessageView(findViewById(R.id.actorlist_outer_layout)); - - mGenresController = new MovieGenreListController(MovieGenreListController.TYPE_TVSHOW); - mGenresController.findTitleView(findViewById(R.id.genrelist_outer_layout)); - mGenresController.findMessageView(findViewById(R.id.genrelist_outer_layout)); - - mFileController = new FileListController(MediaType.VIDEO); - mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); - mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); - - mTabHost.setOnTabChangedListener(new OnTabChangeListener() { - public void onTabChanged(String tabId) { - - initTab(tabId); - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_TVSHOW_TAB_ID, tabId).commit(); - } - } - }); - mConfigurationManager = ConfigurationManager.getInstance(this); - } - - public void onGlobalLayout() { - mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); - - String lastTab = "tab_tv"; - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); - if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { - lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_TVSHOW_TAB_ID, "tab_tv")); - mTabHost.selectTabByTag(lastTab); - } - - initTab(lastTab); - } - - private void initTab(String tabId) { - if (tabId.equals("tab_tv")) { - mTvShowController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView)findViewById(R.id.tvshowlist_list)); - } - //if (tabId.equals("tab_actors")) { - // mActorController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView)findViewById(R.id.actorlist_list)); - //} - if (tabId.equals("tab_genres")) { - mGenresController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView)findViewById(R.id.genrelist_list)); - } - if (tabId.equals("tab_files")) { - mFileController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView)findViewById(R.id.filelist_list)); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - menu.clear(); - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - switch (mTabHost.getCurrentTab()) { - case 0: - mTvShowController.onCreateOptionsMenu(menu); - break; - //case 1: - // mActorController.onCreateOptionsMenu(menu); - // break; - case 1: - mGenresController.onCreateOptionsMenu(menu); - break; - case 2: - mFileController.onCreateOptionsMenu(menu); - break; - } - menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); - menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); - return super.onPrepareOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - // first, process individual menu events - switch (mTabHost.getCurrentTab()) { - case 0: - mTvShowController.onOptionsItemSelected(item); - break; - //case 1: - // mActorController.onOptionsItemSelected(item); - // break; - case 1: - mGenresController.onOptionsItemSelected(item); - break; - case 2: - mFileController.onOptionsItemSelected(item); - break; - } - - // then the generic ones. - switch (item.getItemId()) { - case MENU_REMOTE: - final Intent intent; - if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1) == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(this, GestureRemoteActivity.class); - } else { - intent = new Intent(this, RemoteActivity.class); - } - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - startActivity(intent); - return true; - case MENU_UPDATE_LIBRARY: - mTvShowController.refreshMovieLibrary(this); - return true; - case MENU_NOW_PLAYING: - startActivity(new Intent(this, NowPlayingActivity.class)); - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, v, menuInfo); - switch (mTabHost.getCurrentTab()) { - case 0: - mTvShowController.onCreateContextMenu(menu, v, menuInfo); - break; - //case 1: - // mActorController.onCreateContextMenu(menu, v, menuInfo); - // break; - case 1: - mGenresController.onCreateContextMenu(menu, v, menuInfo); - break; - case 2: - mFileController.onCreateContextMenu(menu, v, menuInfo); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem item) { - switch (mTabHost.getCurrentTab()) { - case 0: - mTvShowController.onContextItemSelected(item); - break; - //case 1: - // mActorController.onContextItemSelected(item); - // break; - case 1: - mGenresController.onContextItemSelected(item); - break; - case 2: - mFileController.onContextItemSelected(item); - break; - } - return super.onContextItemSelected(item); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - IEventClientManager client = ManagerFactory.getEventClientManager(mTvShowController); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - } - client.setController(null); - return super.onKeyDown(keyCode, event); - } - - - @Override - protected void onResume() { - super.onResume(); - mTvShowController.onActivityResume(this); - //mActorController.onActivityResume(this); - mGenresController.onActivityResume(this); - mFileController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } - - @Override - protected void onPause() { - super.onPause(); - mTvShowController.onActivityPause(); - //mActorController.onActivityPause(); - mGenresController.onActivityPause(); - mFileController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewTreeObserver; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.controller.FileListController; +import org.xbmc.android.remote.presentation.controller.MovieGenreListController; +import org.xbmc.android.remote.presentation.controller.RemoteController; +import org.xbmc.android.remote.presentation.controller.TvShowListController; +import org.xbmc.android.widget.slidingtabs.SlidingTabActivity; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.OnTabChangeListener; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.type.MediaType; +import org.xbmc.eventclient.ButtonCodes; + +public class TvShowLibraryActivity extends SlidingTabActivity implements ViewTreeObserver.OnGlobalLayoutListener { + + private static final int MENU_NOW_PLAYING = 301; + private static final int MENU_UPDATE_LIBRARY = 302; + private static final int MENU_REMOTE = 303; + private static final String PREF_REMEMBER_TAB = "setting_remember_last_tab"; + private static final String LAST_TVSHOW_TAB_ID = "last_tvshow_tab_id"; + private SlidingTabHost mTabHost; + private TvShowListController mTvShowController; + //private ActorListController mActorController; + private MovieGenreListController mGenresController; + private FileListController mFileController; + private ConfigurationManager mConfigurationManager; + private Handler mHandler; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.tvlibrary); + + // remove nasty top fading edge + FrameLayout topFrame = (FrameLayout) findViewById(android.R.id.content); + topFrame.setForeground(null); + + mTabHost = getTabHost(); + + // add the tabs + mTabHost.addTab(mTabHost.newTabSpec("tab_tv", "TV Shows", R.drawable.st_tv_on, + R.drawable.st_tv_off).setBigIcon(R.drawable.st_tv_over).setContent(R.id.tvshowlist_outer_layout)); + //mTabHost.addTab(mTabHost.newTabSpec("tab_actors", "Actors", R.drawable.st_actor_on, + // R.drawable.st_actor_off).setBigIcon(R.drawable.st_actor_over).setContent(R.id.actorlist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_genres", "Genres", R.drawable.st_genre_on, + R.drawable.st_genre_off).setBigIcon(R.drawable.st_genre_over).setContent(R.id.genrelist_outer_layout)); + mTabHost.addTab(mTabHost.newTabSpec("tab_files", "File Mode", R.drawable.st_filemode_on, + R.drawable.st_filemode_off).setBigIcon(R.drawable.st_filemode_over).setContent(R.id + .filelist_outer_layout)); + + mTabHost.getViewTreeObserver().addOnGlobalLayoutListener(this); + + // assign the gui logic to each tab + mHandler = new Handler(); + mTvShowController = new TvShowListController(); + mTvShowController.findTitleView(findViewById(R.id.tvshowlist_outer_layout)); + mTvShowController.findMessageView(findViewById(R.id.tvshowlist_outer_layout)); + + //mActorController = new ActorListController(ActorListController.TYPE_TVSHOW); + //mActorController.findTitleView(findViewById(R.id.actorlist_outer_layout)); + //mActorController.findMessageView(findViewById(R.id.actorlist_outer_layout)); + + mGenresController = new MovieGenreListController(MovieGenreListController.TYPE_TVSHOW); + mGenresController.findTitleView(findViewById(R.id.genrelist_outer_layout)); + mGenresController.findMessageView(findViewById(R.id.genrelist_outer_layout)); + + mFileController = new FileListController(MediaType.VIDEO); + mFileController.findTitleView(findViewById(R.id.filelist_outer_layout)); + mFileController.findMessageView(findViewById(R.id.filelist_outer_layout)); + + mTabHost.setOnTabChangedListener(new OnTabChangeListener() { + public void onTabChanged(String tabId) { + + initTab(tabId); + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + getSharedPreferences("global", Context.MODE_PRIVATE).edit().putString(LAST_TVSHOW_TAB_ID, + tabId).commit(); + } + } + }); + mConfigurationManager = ConfigurationManager.getInstance(this); + } + + public void onGlobalLayout() { + mTabHost.getViewTreeObserver().removeGlobalOnLayoutListener(this); + + String lastTab = "tab_tv"; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getApplicationContext()); + if (prefs.getBoolean(PREF_REMEMBER_TAB, false)) { + lastTab = (getSharedPreferences("global", Context.MODE_PRIVATE).getString(LAST_TVSHOW_TAB_ID, "tab_tv")); + mTabHost.selectTabByTag(lastTab); + } + + initTab(lastTab); + } + + private void initTab(String tabId) { + if (tabId.equals("tab_tv")) { + mTvShowController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .tvshowlist_list)); + } + //if (tabId.equals("tab_actors")) { + // mActorController.onCreate(TvShowLibraryActivity.this, mHandler, + // (ListView)findViewById(R.id.actorlist_list)); + //} + if (tabId.equals("tab_genres")) { + mGenresController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .genrelist_list)); + } + if (tabId.equals("tab_files")) { + mFileController.onCreate(TvShowLibraryActivity.this, mHandler, (ListView) findViewById(R.id + .filelist_list)); + } + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + menu.clear(); + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + switch (mTabHost.getCurrentTab()) { + case 0: + mTvShowController.onCreateOptionsMenu(menu); + break; + //case 1: + // mActorController.onCreateOptionsMenu(menu); + // break; + case 1: + mGenresController.onCreateOptionsMenu(menu); + break; + case 2: + mFileController.onCreateOptionsMenu(menu); + break; + } + menu.add(0, MENU_UPDATE_LIBRARY, 0, "Update Library").setIcon(R.drawable.menu_refresh); + menu.add(0, MENU_REMOTE, 0, "Remote control").setIcon(R.drawable.menu_remote); + return super.onPrepareOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + + // first, process individual menu events + switch (mTabHost.getCurrentTab()) { + case 0: + mTvShowController.onOptionsItemSelected(item); + break; + //case 1: + // mActorController.onOptionsItemSelected(item); + // break; + case 1: + mGenresController.onOptionsItemSelected(item); + break; + case 2: + mFileController.onOptionsItemSelected(item); + break; + } + + // then the generic ones. + switch (item.getItemId()) { + case MENU_REMOTE: + final Intent intent; + if (getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, + -1) == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(this, GestureRemoteActivity.class); + } else { + intent = new Intent(this, RemoteActivity.class); + } + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + startActivity(intent); + return true; + case MENU_UPDATE_LIBRARY: + mTvShowController.refreshMovieLibrary(this); + return true; + case MENU_NOW_PLAYING: + startActivity(new Intent(this, NowPlayingActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + switch (mTabHost.getCurrentTab()) { + case 0: + mTvShowController.onCreateContextMenu(menu, v, menuInfo); + break; + //case 1: + // mActorController.onCreateContextMenu(menu, v, menuInfo); + // break; + case 1: + mGenresController.onCreateContextMenu(menu, v, menuInfo); + break; + case 2: + mFileController.onCreateContextMenu(menu, v, menuInfo); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (mTabHost.getCurrentTab()) { + case 0: + mTvShowController.onContextItemSelected(item); + break; + //case 1: + // mActorController.onContextItemSelected(item); + // break; + case 1: + mGenresController.onContextItemSelected(item); + break; + case 2: + mFileController.onContextItemSelected(item); + break; + } + return super.onContextItemSelected(item); + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + IEventClientManager client = ManagerFactory.getEventClientManager(mTvShowController); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + client.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, (byte) 0); + return true; + } + client.setController(null); + return super.onKeyDown(keyCode, event); + } + + + @Override + protected void onResume() { + super.onResume(); + mTvShowController.onActivityResume(this); + //mActorController.onActivityResume(this); + mGenresController.onActivityResume(this); + mFileController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } + + @Override + protected void onPause() { + super.onPause(); + mTvShowController.onActivityPause(); + //mActorController.onActivityPause(); + mGenresController.onActivityPause(); + mFileController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } +} diff --git a/src/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java b/app/src/main/java/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java similarity index 85% rename from src/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java rename to app/src/main/java/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java index 899b237c..b7884501 100644 --- a/src/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/activity/UrlIntentActivity.java @@ -1,68 +1,67 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.activity; - - -import org.xbmc.android.remote.presentation.controller.UrlIntentController; -import org.xbmc.api.type.ThumbSize; - -import android.app.Activity; -import android.os.Bundle; -import android.os.Handler; -import android.view.Display; - -/** - * @author Team XBMC - * - */ -public class UrlIntentActivity extends Activity { - - public static final String ACTION = "android.intent.action.SEND"; - - private ConfigurationManager mConfigurationManager; - private UrlIntentController mUrlIntentController; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - mConfigurationManager = ConfigurationManager.getInstance(this); - mUrlIntentController = new UrlIntentController(this, new Handler()); - mUrlIntentController.setupStatusHandler(); - } - - @Override - protected void onPause() { - super.onPause(); - mUrlIntentController.onActivityPause(); - mConfigurationManager.onActivityPause(); - } - - @Override - protected void onResume() { - super.onResume(); - mUrlIntentController.onActivityResume(this); - mConfigurationManager.onActivityResume(this); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.activity; + + +import android.app.Activity; +import android.os.Bundle; +import android.os.Handler; +import android.view.Display; + +import org.xbmc.android.remote.presentation.controller.UrlIntentController; +import org.xbmc.api.type.ThumbSize; + +/** + * @author Team XBMC + */ +public class UrlIntentActivity extends Activity { + + public static final String ACTION = "android.intent.action.SEND"; + + private ConfigurationManager mConfigurationManager; + private UrlIntentController mUrlIntentController; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + mConfigurationManager = ConfigurationManager.getInstance(this); + mUrlIntentController = new UrlIntentController(this, new Handler()); + mUrlIntentController.setupStatusHandler(); + } + + @Override + protected void onPause() { + super.onPause(); + mUrlIntentController.onActivityPause(); + mConfigurationManager.onActivityPause(); + } + + @Override + protected void onResume() { + super.onResume(); + mUrlIntentController.onActivityResume(this); + mConfigurationManager.onActivityResume(this); + } +} diff --git a/src/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java b/app/src/main/java/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java similarity index 98% rename from src/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java rename to app/src/main/java/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java index de78c638..a04b4411 100644 --- a/src/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/appwidget/RemoteControllerWidget.java @@ -1,10 +1,5 @@ package org.xbmc.android.remote.presentation.appwidget; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.controller.AppWidgetRemoteController; -import org.xbmc.android.util.HostFactory; -import org.xbmc.eventclient.ButtonCodes; - import android.annotation.TargetApi; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; @@ -17,12 +12,16 @@ import android.widget.RemoteViews; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.controller.AppWidgetRemoteController; +import org.xbmc.android.util.HostFactory; +import org.xbmc.eventclient.ButtonCodes; + /** * Base class for the remote controller widget based on RemoteController * activity in portrait mode. - * + * * @author Heikki Hämäläinen - * */ public class RemoteControllerWidget extends AppWidgetProvider { @@ -34,11 +33,11 @@ public class RemoteControllerWidget extends AppWidgetProvider { @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, - int[] appWidgetIds) { + int[] appWidgetIds) { // If the app is not initialized this should cause it to try connect to // the latest host and we also avoid noSettings exceptions HostFactory.readHost(context); - + ComponentName thisWidget = new ComponentName(context, RemoteControllerWidget.class); int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget); @@ -52,13 +51,13 @@ public void onUpdate(Context context, AppWidgetManager appWidgetManager, /** * Attaches pending intents to widget buttons - * + * * @param context * @param remoteView * @param widgetId */ private void attachPendingIntents(Context context, RemoteViews remoteView, - int widgetId) { + int widgetId) { // First row AppWidgetRemoteController.setupWidgetButton(remoteView, R.id.RemoteXboxWidgetImgBtnDisplay, context, this, @@ -70,7 +69,7 @@ private void attachPendingIntents(Context context, RemoteViews remoteView, R.id.RemoteXboxWidgetImgBtnSeekBack, context, this, ButtonCodes.REMOTE_REVERSE, widgetId, URI_SCHEME, ACTION_WIDGET_CONTROL); - + AppWidgetRemoteController.setupWidgetButton(remoteView, R.id.RemoteXboxWidgetImgBtnPlay, context, this, ButtonCodes.REMOTE_PLAY, widgetId, URI_SCHEME, @@ -163,7 +162,7 @@ public void onReceive(Context context, Intent intent) { if (extras.containsKey(AppWidgetRemoteController.ERROR_MESSAGE)) { // Error is most probably connection refused or socket timeout // TODO Different error, different message - + Toast.makeText(context, context.getString(extras.getInt(AppWidgetRemoteController.ERROR_MESSAGE)), Toast.LENGTH_SHORT).show(); } @@ -174,7 +173,8 @@ public void onReceive(Context context, Intent intent) { @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override - public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) { + public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, + Bundle newOptions) { int minHeight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT); // https://developer.android.com/guide/practices/ui_guidelines/widget_design.html#cellstable diff --git a/src/org/xbmc/android/remote/presentation/controller/AbstractController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AbstractController.java similarity index 64% rename from src/org/xbmc/android/remote/presentation/controller/AbstractController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/AbstractController.java index f35ddef6..0569f5cd 100644 --- a/src/org/xbmc/android/remote/presentation/controller/AbstractController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AbstractController.java @@ -1,333 +1,340 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import java.io.IOException; -import java.net.ConnectException; -import java.net.SocketTimeoutException; - -import org.apache.http.HttpException; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; -import org.xbmc.android.remote.presentation.activity.SettingsActivity; -import org.xbmc.android.util.HostFactory; -import org.xbmc.android.util.WifiHelper; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.Host; -import org.xbmc.httpapi.NoNetworkException; -import org.xbmc.httpapi.NoSettingsException; -import org.xbmc.httpapi.WrongDataFormatException; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.DialogInterface.OnDismissListener; -import android.content.Intent; -import android.net.wifi.WifiManager; -import android.os.Handler; -import android.util.Log; -import android.widget.Toast; - -/** - * Every controller should extend this class. Takes care of the messages. - * - * @author Team XBMC - */ -public abstract class AbstractController { - - public static final int MAX_WAIT_FOR_WIFI = 20; - public static final String TAG = "AbstractController"; - - protected Activity mActivity; - protected Handler mHandler; - - private boolean mDialogShowing = false; - protected boolean mPaused = true; - - private Thread mWaitForWifi; - - public void onCreate(Activity activity, Handler handler) { - mActivity = activity; - mHandler = handler; - HostFactory.readHost(activity.getApplicationContext()); - //ClientFactory.resetClient(HostFactory.host); - } - - public void onWrongConnectionState(int state, final INotifiableManager manager, final Command source) { - final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - switch (state) { - case WifiHelper.WIFI_STATE_DISABLED: - builder.setTitle("Wifi disabled"); - builder.setMessage("This host is Wifi only. Should I activate Wifi?"); - builder.setNeutralButton("Activate Wifi", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - final ProgressDialog pd = new ProgressDialog(mActivity); - pd.setCancelable(true); - pd.setTitle("Activating Wifi"); - pd.setMessage("Please wait while Wifi is activated."); - pd.show(); - (new Thread() { - public void run() { - final WifiHelper helper = WifiHelper.getInstance(mActivity); - helper.enableWifi(true); - int wait = 0; - while(wait <= MAX_WAIT_FOR_WIFI * 1000 && helper.getWifiState() != WifiHelper.WIFI_STATE_ENABLED) { - try { - sleep(500); - wait += 500; - } catch (InterruptedException e) {} - } - manager.retryAll(); - pd.cancel(); - mDialogShowing = false; - - } - }).start(); - } - }); - showDialog(builder); - break; - case WifiHelper.WIFI_STATE_ENABLED: - final Host host = HostFactory.host; - final WifiHelper helper = WifiHelper.getInstance(mActivity); - final String msg; - if(host != null && host.access_point != null && !host.access_point.equals("")) { - helper.connect(host); - msg = "Connecting to " + host.access_point + ". Please wait"; - } else { - msg = "Waiting for Wifi to connect to your LAN."; - } - final ProgressDialog pd = new ProgressDialog(mActivity); - pd.setCancelable(true); - pd.setTitle("Connecting"); - pd.setMessage(msg); - mWaitForWifi = new Thread() { - public void run() { - mDialogShowing = true; - pd.show(); - (new Thread( ) { - public void run() { - int wait = 0; - while(wait <= MAX_WAIT_FOR_WIFI * 1000 && helper.getWifiState() != WifiHelper.WIFI_STATE_CONNECTED) { - try { - sleep(500); - wait += 500; - } catch (InterruptedException e) {} - } - pd.cancel(); - mDialogShowing = false; - } - }).start(); - pd.setOnDismissListener(new OnDismissListener() { - public void onDismiss(DialogInterface dialog) { - if(helper.getWifiState() != WifiHelper.WIFI_STATE_CONNECTED) { - builder.setTitle("Wifi doesn't seem to connect"); - builder.setMessage("You can open the Wifi settings or wait "+ MAX_WAIT_FOR_WIFI +" seconds"); - builder.setNeutralButton("Wifi Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - mDialogShowing = false; - mActivity.startActivity(new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)); - } - }); - builder.setCancelable(true); - builder.setNegativeButton("Wait", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mDialogShowing = false; - mActivity.runOnUiThread(mWaitForWifi); //had to make the Thread a field because of this line - } - }); - - mActivity.runOnUiThread(new Runnable() { - public void run() { - final AlertDialog alert = builder.create(); - try { - if (!mDialogShowing) { - alert.show(); - mDialogShowing = true; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - } - - }); - } - }; - mActivity.runOnUiThread(mWaitForWifi); - } - - } - - public void onError(Exception exception) { - if (mActivity == null) { - return; - } - final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - try { - throw exception; - } catch (NoSettingsException e) { - builder.setTitle("No hosts detected"); - builder.setMessage(e.getMessage()); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - final Intent intent = new Intent(mActivity, HostSettingsActivity.class); -// intent.putExtra(SettingsActivity.JUMP_TO, SettingsActivity.JUMP_TO_INSTANCES); - mActivity.startActivity(intent); - mDialogShowing = false; - } - }); - } catch (NoNetworkException e) { - builder.setTitle("No Network"); - builder.setMessage(e.getMessage()); - builder.setCancelable(true); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS)); - mDialogShowing = false; - } - }); - } catch (WrongDataFormatException e) { - builder.setTitle("Internal Error"); - builder.setMessage("Wrong data from HTTP API; expected '" + e.getExpected() + "', got '" + e.getReceived() + "'."); - } catch (SocketTimeoutException e) { - builder.setTitle("Socket Timeout"); - builder.setMessage("Make sure XBMC webserver is enabled and XBMC is running."); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); - mDialogShowing = false; - } - }); - } catch (ConnectException e) { - builder.setTitle("Connection Refused"); - builder.setMessage("Make sure XBMC webserver is enabled and XBMC is running."); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); - mDialogShowing = false; - } - }); - } catch (IOException e) { - if (e.getMessage() != null && e.getMessage().startsWith("Network unreachable")) { - builder.setTitle("No network"); - builder.setMessage("XBMC Remote needs local network access. Please make sure that your wireless network is activated. You can click on the Settings button below to directly access your network settings."); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS)); - mDialogShowing = false; - } - }); - } else { - builder.setTitle("I/O Exception (" + e.getClass().getCanonicalName() + ")"); - if (e.getMessage() != null) { - builder.setMessage(e.getMessage().toString()); - } - Log.e(TAG, e.getStackTrace().toString()); - } - } catch (HttpException e) { - if (e.getMessage().startsWith("401")) { - builder.setTitle("HTTP 401: Unauthorized"); - builder.setMessage("The supplied username and/or password is incorrect. Please check your settings."); - builder.setNeutralButton("Settings", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); - mDialogShowing = false; - } - }); - } - } catch (Exception e) { - final String name = e.getClass().getName(); - builder.setTitle(name.substring(name.lastIndexOf(".") + 1)); - builder.setMessage(e.getMessage()); - } finally { - - exception.printStackTrace(); - } - showDialog(builder); - } - - protected void showDialog(final AlertDialog.Builder builder) { - builder.setCancelable(true); - builder.setNegativeButton("Close", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - mDialogShowing = false; -// ConnectionManager.resetClient(); - } - }); - - mActivity.runOnUiThread(new Runnable() { - public void run() { - final AlertDialog alert = builder.create(); - try { - if (!mDialogShowing) { - alert.show(); - mDialogShowing = true; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } - - protected void showDialog(int id){ - mActivity.showDialog(id); - } - - protected void dismissDialog(int id){ - mActivity.dismissDialog(id); - } - - public void onMessage(final String message) { - mActivity.runOnUiThread(new Runnable() { - public void run() { - Toast toast = Toast.makeText(mActivity, message, Toast.LENGTH_LONG); - toast.show(); - } - }); - } - - public void runOnUI(Runnable action) { - if (mHandler != null) { - //Log.i(TAG, "### running on UI at " + mActivity.getClass().getSimpleName()); - mHandler.post(action); - //mActivity.runOnUiThread(action); - } - } - - public void onActivityPause() { -// mActivity = null; - mPaused = true; - } - - public void onActivityResume(Activity activity) { - mActivity = activity; - mPaused = false; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.DialogInterface.OnDismissListener; +import android.content.Intent; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.util.Log; +import android.widget.Toast; + +import org.apache.http.HttpException; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; +import org.xbmc.android.remote.presentation.activity.SettingsActivity; +import org.xbmc.android.util.HostFactory; +import org.xbmc.android.util.WifiHelper; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.Host; +import org.xbmc.httpapi.NoNetworkException; +import org.xbmc.httpapi.NoSettingsException; +import org.xbmc.httpapi.WrongDataFormatException; + +import java.io.IOException; +import java.net.ConnectException; +import java.net.SocketTimeoutException; + +/** + * Every controller should extend this class. Takes care of the messages. + * + * @author Team XBMC + */ +public abstract class AbstractController { + + public static final int MAX_WAIT_FOR_WIFI = 20; + public static final String TAG = "AbstractController"; + + protected Activity mActivity; + protected Handler mHandler; + protected boolean mPaused = true; + private boolean mDialogShowing = false; + private Thread mWaitForWifi; + + public void onCreate(Activity activity, Handler handler) { + mActivity = activity; + mHandler = handler; + HostFactory.readHost(activity.getApplicationContext()); + //ClientFactory.resetClient(HostFactory.host); + } + + public void onWrongConnectionState(int state, final INotifiableManager manager, final Command source) { + final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + switch (state) { + case WifiHelper.WIFI_STATE_DISABLED: + builder.setTitle("Wifi disabled"); + builder.setMessage("This host is Wifi only. Should I activate Wifi?"); + builder.setNeutralButton("Activate Wifi", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + final ProgressDialog pd = new ProgressDialog(mActivity); + pd.setCancelable(true); + pd.setTitle("Activating Wifi"); + pd.setMessage("Please wait while Wifi is activated."); + pd.show(); + (new Thread() { + public void run() { + final WifiHelper helper = WifiHelper.getInstance(mActivity); + helper.enableWifi(true); + int wait = 0; + while (wait <= MAX_WAIT_FOR_WIFI * 1000 && helper.getWifiState() != WifiHelper + .WIFI_STATE_ENABLED) { + try { + sleep(500); + wait += 500; + } catch (InterruptedException e) { + } + } + manager.retryAll(); + pd.cancel(); + mDialogShowing = false; + + } + }).start(); + } + }); + showDialog(builder); + break; + case WifiHelper.WIFI_STATE_ENABLED: + final Host host = HostFactory.host; + final WifiHelper helper = WifiHelper.getInstance(mActivity); + final String msg; + if (host != null && host.access_point != null && !host.access_point.equals("")) { + helper.connect(host); + msg = "Connecting to " + host.access_point + ". Please wait"; + } else { + msg = "Waiting for Wifi to connect to your LAN."; + } + final ProgressDialog pd = new ProgressDialog(mActivity); + pd.setCancelable(true); + pd.setTitle("Connecting"); + pd.setMessage(msg); + mWaitForWifi = new Thread() { + public void run() { + mDialogShowing = true; + pd.show(); + (new Thread() { + public void run() { + int wait = 0; + while (wait <= MAX_WAIT_FOR_WIFI * 1000 && helper.getWifiState() != WifiHelper + .WIFI_STATE_CONNECTED) { + try { + sleep(500); + wait += 500; + } catch (InterruptedException e) { + } + } + pd.cancel(); + mDialogShowing = false; + } + }).start(); + pd.setOnDismissListener(new OnDismissListener() { + public void onDismiss(DialogInterface dialog) { + if (helper.getWifiState() != WifiHelper.WIFI_STATE_CONNECTED) { + builder.setTitle("Wifi doesn't seem to connect"); + builder.setMessage("You can open the Wifi settings or wait " + MAX_WAIT_FOR_WIFI + + " seconds"); + builder.setNeutralButton("Wifi Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + mDialogShowing = false; + mActivity.startActivity(new Intent(WifiManager.ACTION_PICK_WIFI_NETWORK)); + } + }); + builder.setCancelable(true); + builder.setNegativeButton("Wait", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mDialogShowing = false; + mActivity.runOnUiThread(mWaitForWifi); //had to make the Thread a field + // because of this line + } + }); + + mActivity.runOnUiThread(new Runnable() { + public void run() { + final AlertDialog alert = builder.create(); + try { + if (!mDialogShowing) { + alert.show(); + mDialogShowing = true; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + } + + }); + } + }; + mActivity.runOnUiThread(mWaitForWifi); + } + + } + + public void onError(Exception exception) { + if (mActivity == null) { + return; + } + final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + try { + throw exception; + } catch (NoSettingsException e) { + builder.setTitle("No hosts detected"); + builder.setMessage(e.getMessage()); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + final Intent intent = new Intent(mActivity, HostSettingsActivity.class); +// intent.putExtra(SettingsActivity.JUMP_TO, SettingsActivity.JUMP_TO_INSTANCES); + mActivity.startActivity(intent); + mDialogShowing = false; + } + }); + } catch (NoNetworkException e) { + builder.setTitle("No Network"); + builder.setMessage(e.getMessage()); + builder.setCancelable(true); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS)); + mDialogShowing = false; + } + }); + } catch (WrongDataFormatException e) { + builder.setTitle("Internal Error"); + builder.setMessage("Wrong data from HTTP API; expected '" + e.getExpected() + "', " + + "got '" + e.getReceived() + "'."); + } catch (SocketTimeoutException e) { + builder.setTitle("Socket Timeout"); + builder.setMessage("Make sure XBMC webserver is enabled and XBMC is running."); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); + mDialogShowing = false; + } + }); + } catch (ConnectException e) { + builder.setTitle("Connection Refused"); + builder.setMessage("Make sure XBMC webserver is enabled and XBMC is running."); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); + mDialogShowing = false; + } + }); + } catch (IOException e) { + if (e.getMessage() != null && e.getMessage().startsWith("Network unreachable")) { + builder.setTitle("No network"); + builder.setMessage("XBMC Remote needs local network access. Please make sure that your wireless " + + "network is activated. You can click on the Settings button below to directly access your " + + "network settings."); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.startActivity(new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS)); + mDialogShowing = false; + } + }); + } else { + builder.setTitle("I/O Exception (" + e.getClass().getCanonicalName() + ")"); + if (e.getMessage() != null) { + builder.setMessage(e.getMessage().toString()); + } + Log.e(TAG, e.getStackTrace().toString()); + } + } catch (HttpException e) { + if (e.getMessage().startsWith("401")) { + builder.setTitle("HTTP 401: Unauthorized"); + builder.setMessage("The supplied username and/or password is incorrect. Please check your settings."); + builder.setNeutralButton("Settings", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.startActivity(new Intent(mActivity, SettingsActivity.class)); + mDialogShowing = false; + } + }); + } + } catch (Exception e) { + final String name = e.getClass().getName(); + builder.setTitle(name.substring(name.lastIndexOf(".") + 1)); + builder.setMessage(e.getMessage()); + } finally { + + exception.printStackTrace(); + } + showDialog(builder); + } + + protected void showDialog(final AlertDialog.Builder builder) { + builder.setCancelable(true); + builder.setNegativeButton("Close", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + mDialogShowing = false; +// ConnectionManager.resetClient(); + } + }); + + mActivity.runOnUiThread(new Runnable() { + public void run() { + final AlertDialog alert = builder.create(); + try { + if (!mDialogShowing) { + alert.show(); + mDialogShowing = true; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + } + + protected void showDialog(int id) { + mActivity.showDialog(id); + } + + protected void dismissDialog(int id) { + mActivity.dismissDialog(id); + } + + public void onMessage(final String message) { + mActivity.runOnUiThread(new Runnable() { + public void run() { + Toast toast = Toast.makeText(mActivity, message, Toast.LENGTH_LONG); + toast.show(); + } + }); + } + + public void runOnUI(Runnable action) { + if (mHandler != null) { + //Log.i(TAG, "### running on UI at " + mActivity.getClass().getSimpleName()); + mHandler.post(action); + //mActivity.runOnUiThread(action); + } + } + + public void onActivityPause() { +// mActivity = null; + mPaused = true; + } + + public void onActivityResume(Activity activity) { + mActivity = activity; + mPaused = false; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/ActorListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ActorListController.java similarity index 93% rename from src/org/xbmc/android/remote/presentation/controller/ActorListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/ActorListController.java index a3e9f1cf..00ed8ef5 100644 --- a/src/org/xbmc/android/remote/presentation/controller/ActorListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ActorListController.java @@ -21,19 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Artist; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.content.Intent; import android.graphics.BitmapFactory; @@ -50,27 +37,39 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Artist; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class ActorListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; + public static final int TYPE_ALL = 1; public static final int TYPE_MOVIE = 2; public static final int TYPE_TVSHOW = 3; public static final int TYPE_EPISODE = 4; - - private boolean mLoadCovers = false; + private static final int mThumbSize = ThumbSize.SMALL; + private static final long serialVersionUID = 4360738733222799619L; private final int mType; - + private boolean mLoadCovers = false; private IVideoManager mVideoManager; - + public ActorListController(int type) { mType = type; } - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mVideoManager = ManagerFactory.getVideoManager(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); final String sdError = ImportUtilities.assertSdCard(); @@ -79,10 +78,10 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.person_black_small); setupIdleListener(); - + final String title = mType == TYPE_MOVIE ? "Movie " : mType == TYPE_TVSHOW ? "TV " : "" + "Actors"; DataResponse> response = new DataResponse>() { public void run() { @@ -95,11 +94,11 @@ public void run() { } } }; - - mList.setOnKeyListener(new ListControllerOnKeyListener()); - + + mList.setOnKeyListener(new ListControllerOnKeyListener()); + showOnLoading(); - setTitle(title + "..."); + setTitle(title + "..."); switch (mType) { case TYPE_ALL: mVideoManager.getActors(response, mActivity.getApplicationContext()); @@ -113,14 +112,14 @@ public void run() { case TYPE_EPISODE: break; } - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; Intent nextActivity; - final Actor actor = (Actor)mList.getAdapter().getItem(((OneLabelItemView)view).position); + final Actor actor = (Actor) mList.getAdapter().getItem(((OneLabelItemView) view).position); nextActivity = new Intent(view.getContext(), ListActivity.class); - if(mType == TYPE_TVSHOW) + if (mType == TYPE_TVSHOW) nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new TvShowListController()); else nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new MovieListController()); @@ -130,36 +129,6 @@ public void onItemClick(AdapterView parent, View view, int position, long id) }); } } - - private class ActorAdapter extends ArrayAdapter { - ActorAdapter(Activity activity, ArrayList items) { - super(activity, 0, items); - } - public View getView(int position, View convertView, ViewGroup parent) { - final OneLabelItemView view; - if (convertView == null) { - view = new OneLabelItemView(mActivity, mVideoManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); - } else { - view = (OneLabelItemView)convertView; - } - final Actor actor = this.getItem(position); - view.reset(); - view.position = position; - view.title = actor.name; - - if (mLoadCovers) { - if(mVideoManager.coverLoaded(actor, mThumbSize)){ - view.setCover(mVideoManager.getCoverSync(actor, mThumbSize)); - }else{ - view.setCover(null); - view.getResponse().load(actor, !mPostScrollLoader.isListIdle()); - } - } - - return view; - } - } - private static final long serialVersionUID = 4360738733222799619L; @Override public void onContextItemSelected(MenuItem item) { @@ -184,4 +153,35 @@ public void onActivityResume(Activity activity) { mVideoManager.setController(this); } } + + private class ActorAdapter extends ArrayAdapter { + ActorAdapter(Activity activity, ArrayList items) { + super(activity, 0, items); + } + + public View getView(int position, View convertView, ViewGroup parent) { + final OneLabelItemView view; + if (convertView == null) { + view = new OneLabelItemView(mActivity, mVideoManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), true); + } else { + view = (OneLabelItemView) convertView; + } + final Actor actor = this.getItem(position); + view.reset(); + view.position = position; + view.title = actor.name; + + if (mLoadCovers) { + if (mVideoManager.coverLoaded(actor, mThumbSize)) { + view.setCover(mVideoManager.getCoverSync(actor, mThumbSize)); + } else { + view.setCover(null); + view.getResponse().load(actor, !mPostScrollLoader.isListIdle()); + } + } + + return view; + } + } } diff --git a/src/org/xbmc/android/remote/presentation/controller/AlbumListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AlbumListController.java similarity index 67% rename from src/org/xbmc/android/remote/presentation/controller/AlbumListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/AlbumListController.java index fadad379..4b91a630 100644 --- a/src/org/xbmc/android/remote/presentation/controller/AlbumListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AlbumListController.java @@ -21,25 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.DialogFactory; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.widget.ThreeLabelsItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -65,19 +46,33 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.DialogFactory; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.widget.ThreeLabelsItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + /** - * TODO Once we move to 1.6+, waste the deprecated code. + * TODO Once we move to 1.6+, waste the deprecated code. */ public class AlbumListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; - private static final String TAG = "AlbumListController"; - public static final int ITEM_CONTEXT_QUEUE = 1; public static final int ITEM_CONTEXT_PLAY = 2; public static final int ITEM_CONTEXT_INFO = 3; - public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_ARTIST_ASC = 21; @@ -87,48 +82,46 @@ public class AlbumListController extends ListController implements IController { public static final int MENU_SORT_BY_YEAR_ASC = 25; public static final int MENU_SORT_BY_YEAR_DESC = 26; public static final int MENU_SWITCH_VIEW = 3; - + private static final int mThumbSize = ThumbSize.SMALL; + private static final String TAG = "AlbumListController"; private static final int VIEW_LIST = 1; - private static final int VIEW_GRID = 2; - private int mCurrentView = VIEW_LIST; - + private static final int VIEW_GRID = 2; + private static final long serialVersionUID = 1088971882661811256L; private Artist mArtist; private Genre mGenre; - private IMusicManager mMusicManager; private IControlManager mControlManager; - private boolean mCompilationsOnly = false; private boolean mLoadCovers = false; - private GridView mGrid = null; - - + /** * Defines if only compilations should be listed. + * * @param co True if compilations only should be listed, false otherwise. */ public void setCompilationsOnly(boolean co) { mCompilationsOnly = co; } - + /** * If grid reference is set, albums can be displayed as wall view. + * * @param grid Reference to GridView */ public void setGrid(GridView grid) { mGrid = grid; } - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mMusicManager = ManagerFactory.getMusicManager(this); mControlManager = ManagerFactory.getControlManager(this); - - ((ISortableManager)mMusicManager).setSortKey(AbstractManager.PREF_SORT_KEY_ALBUM); - ((ISortableManager)mMusicManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); - + + ((ISortableManager) mMusicManager).setSortKey(AbstractManager.PREF_SORT_KEY_ALBUM); + ((ISortableManager) mMusicManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; @@ -139,19 +132,19 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mArtist = (Artist)activity.getIntent().getSerializableExtra(ListController.EXTRA_ARTIST); - mGenre = (Genre)activity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); + + mArtist = (Artist) activity.getIntent().getSerializableExtra(ListController.EXTRA_ARTIST); + mGenre = (Genre) activity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_album); setupIdleListener(); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; Intent nextActivity; - final Album album = (Album)mList.getAdapter().getItem(((ThreeLabelsItemView)view).position); + final Album album = (Album) mList.getAdapter().getItem(((ThreeLabelsItemView) view).position); nextActivity = new Intent(view.getContext(), ListActivity.class); nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new SongListController()); nextActivity.putExtra(ListController.EXTRA_ALBUM, album); @@ -162,7 +155,7 @@ public void onItemClick(AdapterView parent, View view, int position, long id) fetch(); } } - + private void setAdapter(ArrayList value) { switch (mCurrentView) { case VIEW_LIST: @@ -181,41 +174,42 @@ private void setAdapter(ArrayList value) { mList.setVisibility(View.VISIBLE); ((AdapterView) mList).setAdapter(new AlbumAdapter(mActivity, value)); } - break; + break; } } - + public void updateLibrary() { final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); builder.setMessage("Are you sure you want XBMC to rescan your music library?") - .setCancelable(false) - .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mControlManager.updateLibrary(new DataResponse() { - public void run() { - final String message; - if (value) { - message = "Music library updated has been launched."; - } else { - message = "Error launching music library update."; + .setCancelable(false) + .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mControlManager.updateLibrary(new DataResponse() { + public void run() { + final String message; + if (value) { + message = "Music library updated has been launched."; + } else { + message = "Error launching music library update."; + } + Toast toast = Toast.makeText(mActivity, message, Toast.LENGTH_SHORT); + toast.show(); } - Toast toast = Toast.makeText(mActivity, message, Toast.LENGTH_SHORT); - toast.show(); - } - }, "music", mActivity.getApplicationContext()); - } - }) - .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + }, "music", mActivity.getApplicationContext()); + } + }) + .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); builder.create().show(); } - + private void fetch() { - final String title = mArtist != null ? mArtist.name + " - " : mGenre != null ? mGenre.name + " - " : "" + (mCompilationsOnly ? "Compilations" : "Albums"); + final String title = mArtist != null ? mArtist.name + " - " : mGenre != null ? mGenre.name + " - " : "" + + (mCompilationsOnly ? "Compilations" : "Albums"); DataResponse> response = new DataResponse>() { public void run() { if (value.size() > 0) { @@ -227,55 +221,57 @@ public void run() { } } }; - + showOnLoading(); - setTitle(title + "..."); - if (mArtist != null) { // albums of an artist - mMusicManager.getAlbums(response, mArtist, mActivity.getApplicationContext()); - } else if (mGenre != null) { // albums of a genre - mMusicManager.getAlbums(response, mGenre, mActivity.getApplicationContext()); - } else if (mCompilationsOnly) { // compilations + setTitle(title + "..."); + if (mArtist != null) { // albums of an artist + mMusicManager.getAlbums(response, mArtist, mActivity.getApplicationContext()); + } else if (mGenre != null) { // albums of a genre + mMusicManager.getAlbums(response, mGenre, mActivity.getApplicationContext()); + } else if (mCompilationsOnly) { // compilations mMusicManager.getCompilations(response, mActivity.getApplicationContext()); } else { mMusicManager.getAlbums(response, mActivity.getApplicationContext()); } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - final ThreeLabelsItemView view = (ThreeLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; - menu.setHeaderTitle(((Album)mList.getItemAtPosition(view.getPosition())).name); + final ThreeLabelsItemView view = (ThreeLabelsItemView) ((AdapterContextMenuInfo) menuInfo).targetView; + menu.setHeaderTitle(((Album) mList.getItemAtPosition(view.getPosition())).name); menu.add(0, ITEM_CONTEXT_QUEUE, 1, "Queue Album"); menu.add(0, ITEM_CONTEXT_PLAY, 2, "Play Album"); menu.add(0, ITEM_CONTEXT_INFO, 3, "View Details"); } - + public void onContextItemSelected(MenuItem item) { - final Album album = (Album)mList.getAdapter().getItem(((ThreeLabelsItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final Album album = (Album) mList.getAdapter().getItem(((ThreeLabelsItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_QUEUE: mMusicManager.addToPlaylist(new QueryResponse( - mActivity, - "Adding album \"" + album.name + "\" by " + album.artist + " to playlist...", + mActivity, + "Adding album \"" + album.name + "\" by " + album.artist + " to playlist...", "Error adding album!" - ), album, mActivity.getApplicationContext()); + ), album, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_PLAY: mMusicManager.play(new QueryResponse( - mActivity, - "Playing album \"" + album.name + "\" by " + album.artist + "...", + mActivity, + "Playing album \"" + album.name + "\" by " + album.artist + "...", "Error playing album!", true - ), album, mActivity.getApplicationContext()); + ), album, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_INFO: - DialogFactory.getAlbumDetail(mMusicManager, mActivity, album, mActivity.getApplicationContext()).show(); + DialogFactory.getAlbumDetail(mMusicManager, mActivity, album, mActivity.getApplicationContext()) + .show(); break; default: return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { if (mArtist != null || mGenre != null) { @@ -284,7 +280,7 @@ public void onCreateOptionsMenu(Menu menu) { SubMenu sortMenu = menu.addSubMenu(0, MENU_SORT, 0, "Sort").setIcon(R.drawable.menu_sort); sortMenu.add(2, MENU_SORT_BY_ALBUM_ASC, 0, "by Album ascending"); sortMenu.add(2, MENU_SORT_BY_ALBUM_DESC, 0, "by Album descending"); - + if (mArtist != null) { sortMenu.add(2, MENU_SORT_BY_YEAR_ASC, 0, "by Year ascending"); sortMenu.add(2, MENU_SORT_BY_YEAR_DESC, 0, "by Year descending"); @@ -294,98 +290,127 @@ public void onCreateOptionsMenu(Menu menu) { } // menu.add(0, MENU_SWITCH_VIEW, 0, "Switch view").setIcon(R.drawable.menu_view); } - + @Override public void onOptionsItemSelected(MenuItem item) { final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - final Artist artist = mArtist; - final Genre genre = mGenre; - if (artist != null && genre == null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all albums by " + artist.name + "...", - "Error playing songs!", - true - ), genre, mActivity.getApplicationContext()); - } else if (genre != null && artist == null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all albums of genre " + genre.name + "...", - "Error playing songs!", - true + case MENU_PLAY_ALL: + final Artist artist = mArtist; + final Genre genre = mGenre; + if (artist != null && genre == null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all albums by " + artist.name + "...", + "Error playing songs!", + true ), genre, mActivity.getApplicationContext()); - } else if (genre != null && artist != null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs of genre " + genre.name + " by " + artist.name + "...", - "Error playing songs!", - true + } else if (genre != null && artist == null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all albums of genre " + genre.name + "...", + "Error playing songs!", + true + ), genre, mActivity.getApplicationContext()); + } else if (genre != null && artist != null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all songs of genre " + genre.name + " by " + artist.name + "...", + "Error playing songs!", + true ), artist, genre, mActivity.getApplicationContext()); - } - break; - case MENU_SORT_BY_ALBUM_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ALBUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ALBUM_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ALBUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ARTIST_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ARTIST); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ARTIST_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ARTIST); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SWITCH_VIEW: - mCurrentView = (mCurrentView % 2) + 1; - fetch(); - break; + } + break; + case MENU_SORT_BY_ALBUM_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ALBUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ALBUM_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ALBUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ARTIST_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ARTIST); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ARTIST_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.ARTIST); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_ALBUM, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SWITCH_VIEW: + mCurrentView = (mCurrentView % 2) + 1; + fetch(); + break; } } - + + public void onActivityPause() { + if (mMusicManager != null) { + mMusicManager.setController(null); + mMusicManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mMusicManager != null) { + mMusicManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + private class AlbumAdapter extends ArrayAdapter { AlbumAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final ThreeLabelsItemView view; if (convertView == null) { - view = new ThreeLabelsItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), false); + view = new ThreeLabelsItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), false); } else { - view = (ThreeLabelsItemView)convertView; + view = (ThreeLabelsItemView) convertView; } - + final Album album = getItem(position); view.reset(); view.position = position; @@ -394,9 +419,9 @@ public View getView(int position, View convertView, ViewGroup parent) { view.subsubtitle = album.year > 0 ? String.valueOf(album.year) : ""; Log.i(TAG, "isListIdle: " + mPostScrollLoader.isListIdle()); if (mLoadCovers) { - if(mMusicManager.coverLoaded(album, mThumbSize)){ + if (mMusicManager.coverLoaded(album, mThumbSize)) { view.setCover(mMusicManager.getCoverSync(album, mThumbSize)); - }else{ + } else { view.setCover(null); view.getResponse().load(album, !mPostScrollLoader.isListIdle()); } @@ -404,23 +429,23 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - + private class AlbumGridAdapter extends ArrayAdapter { AlbumGridAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } - + public View getView(int position, View convertView, ViewGroup parent) { /* final ImageView row; final OneHolder holder; - + if (convertView == null) { row = new ImageView(mActivity); - + holder = new OneHolder(row, null); row.setTag(holder); - + CrossFadeDrawable transition = new CrossFadeDrawable(mFallbackBitmap, null); transition.setCrossFadeEnabled(true); holder.transition = transition; @@ -429,12 +454,12 @@ public View getView(int position, View convertView, ViewGroup parent) { row = (ImageView)convertView; holder = (OneHolder)convertView.getTag(); } - + final Album album = getItem(position); holder.holderItem = album; holder.coverItem = album; holder.id = album.getCrc(); - + if (mLoadCovers) { row.setImageResource(R.drawable.icon_album_dark_big); holder.tempBind = true; @@ -445,27 +470,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return convertView/*row*/; } } - - public void onActivityPause() { - if (mMusicManager != null) { - mMusicManager.setController(null); - mMusicManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mMusicManager != null) { - mMusicManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } - - private static final long serialVersionUID = 1088971882661811256L; } diff --git a/src/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java similarity index 52% rename from src/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java index 9bb55ff5..84e915f8 100644 --- a/src/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/AppWidgetRemoteController.java @@ -1,11 +1,5 @@ package org.xbmc.android.remote.presentation.controller; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.presentation.appwidget.RemoteControllerWidget; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.presentation.INotifiableController; - -import org.xbmc.android.remote.R; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -14,69 +8,76 @@ import android.util.Log; import android.widget.RemoteViews; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.presentation.appwidget.RemoteControllerWidget; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.presentation.INotifiableController; + public class AppWidgetRemoteController extends RemoteController implements INotifiableController { public static final String COMMAND = "remote.controller.widget.command"; public static final String ERROR_MESSAGE = "remote.controller.widget.error_message"; private static long ERROR_TIME_MILLISEC = 0; private Context context; - - + + public AppWidgetRemoteController(Context context) { super(context); // We need context to send broadcast to the system this.context = context; } + /** + * Attaches pendingIntents to widget buttons + * Static method because there is no need to make Controller object in widget update + * + * @param viewId + * @param buttonCode + * @param widgetId + */ + public static void setupWidgetButton(RemoteViews remoteView, int viewId, Context context, Object caller, + String buttonCode, int widgetId, String uri, String action) { + + Intent active = new Intent(context, caller.getClass()); + active.setAction(action); + active.putExtra(COMMAND, buttonCode); + + // Make this pending intent unique to prevent updating other intents + Uri data = Uri.withAppendedPath(Uri.parse(uri + "://widget/id/#" + buttonCode), String.valueOf(widgetId)); + active.setData(data); + remoteView.setOnClickPendingIntent(viewId, PendingIntent.getBroadcast(context, 0, active, + PendingIntent.FLAG_UPDATE_CURRENT)); + } + @Override public void onWrongConnectionState(int state, INotifiableManager manager, - Command source) { + Command source) { // TODO Auto-generated method stub - Log.w("onWrongConnectionState","catch"); + Log.w("onWrongConnectionState", "catch"); super.onWrongConnectionState(state, manager, source); } @Override public void onError(Exception exception) { - - if (context != null){ - // Sending error to widget to dot what it likes - Log.w("onCatch","Catch Error on:" + this.getClass().toString()); - // Only send errors if last error has been send over five seconds ago, this prevents toast spamming - if (SystemClock.elapsedRealtime()>ERROR_TIME_MILLISEC+1000*5){ - Intent active = new Intent(context, RemoteControllerWidget.class); - active.setAction(RemoteControllerWidget.ACTION_WIDGET_CONTROL); - active.putExtra(ERROR_MESSAGE, R.string.make_sure_XBMC_webserver_is_enabled_and_XBMC_is_running); - context.sendBroadcast(active); - ERROR_TIME_MILLISEC = SystemClock.elapsedRealtime(); - } + + if (context != null) { + // Sending error to widget to dot what it likes + Log.w("onCatch", "Catch Error on:" + this.getClass().toString()); + // Only send errors if last error has been send over five seconds ago, this prevents toast spamming + if (SystemClock.elapsedRealtime() > ERROR_TIME_MILLISEC + 1000 * 5) { + Intent active = new Intent(context, RemoteControllerWidget.class); + active.setAction(RemoteControllerWidget.ACTION_WIDGET_CONTROL); + active.putExtra(ERROR_MESSAGE, R.string.make_sure_XBMC_webserver_is_enabled_and_XBMC_is_running); + context.sendBroadcast(active); + ERROR_TIME_MILLISEC = SystemClock.elapsedRealtime(); + } } } - + @Override - public void onMessage(final String message){ - Log.i("onMessage",message); + public void onMessage(final String message) { + Log.i("onMessage", message); } - - - - /** - * Attaches pendingIntents to widget buttons - * Static method because there is no need to make Controller object in widget update - * @param viewId - * @param buttonCode - * @param widgetId - */ - public static void setupWidgetButton(RemoteViews remoteView, int viewId, Context context, Object caller, String buttonCode, int widgetId, String uri, String action){ - - Intent active = new Intent(context, caller.getClass()); - active.setAction(action); - active.putExtra(COMMAND, buttonCode); - - // Make this pending intent unique to prevent updating other intents - Uri data = Uri.withAppendedPath(Uri.parse(uri + "://widget/id/#"+buttonCode), String.valueOf(widgetId)); - active.setData(data); - remoteView.setOnClickPendingIntent(viewId, PendingIntent.getBroadcast(context, 0, active, PendingIntent.FLAG_UPDATE_CURRENT)); - } - + } diff --git a/src/org/xbmc/android/remote/presentation/controller/ArtistListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ArtistListController.java similarity index 85% rename from src/org/xbmc/android/remote/presentation/controller/ArtistListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/ArtistListController.java index 009124ce..dfb7a0d5 100644 --- a/src/org/xbmc/android/remote/presentation/controller/ArtistListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ArtistListController.java @@ -21,20 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.DialogFactory; -import org.xbmc.android.remote.presentation.activity.MusicArtistActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.content.Intent; import android.graphics.BitmapFactory; @@ -53,52 +39,66 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.DialogFactory; +import org.xbmc.android.remote.presentation.activity.MusicArtistActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class ArtistListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; + public static final int ITEM_CONTEXT_QUEUE = 1; public static final int ITEM_CONTEXT_PLAY = 2; public static final int ITEM_CONTEXT_QUEUE_GENRE = 3; public static final int ITEM_CONTEXT_PLAY_GENRE = 4; public static final int ITEM_CONTEXT_INFO = 5; - + private static final int mThumbSize = ThumbSize.SMALL; + private static final long serialVersionUID = 4360738733222799619L; private boolean mLoadCovers = false; private Genre mGenre; private IMusicManager mMusicManager; - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mMusicManager = ManagerFactory.getMusicManager(this); - + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; - + if (!isCreated()) { super.onCreate(activity, handler, list); - + if (!mLoadCovers) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mGenre = (Genre)mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); - + + mGenre = (Genre) mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); + mFallbackBitmap = BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.icon_artist); setupIdleListener(); - + activity.registerForContextMenu(mList); mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; Intent nextActivity; - Artist artist = (Artist)mList.getAdapter().getItem(((OneLabelItemView)view).position); + Artist artist = (Artist) mList.getAdapter().getItem(((OneLabelItemView) view).position); nextActivity = new Intent(view.getContext(), MusicArtistActivity.class); nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new AlbumListController()); nextActivity.putExtra(ListController.EXTRA_ARTIST, artist); mActivity.startActivity(nextActivity); } }); - + final String title = mGenre != null ? mGenre.name + " - " : "" + "Artists"; DataResponse> response = new DataResponse>() { public void run() { @@ -112,10 +112,10 @@ public void run() { } }; - mList.setOnKeyListener(new ListControllerOnKeyListener()); - + mList.setOnKeyListener(new ListControllerOnKeyListener()); + showOnLoading(); - setTitle(title + "..."); + setTitle(title + "..."); if (mGenre != null) { mMusicManager.getArtists(response, mGenre, mActivity.getApplicationContext()); } else { @@ -123,11 +123,12 @@ public void run() { } } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! - final Artist artist = (Artist)mList.getAdapter().getItem(((OneLabelItemView)(((AdapterContextMenuInfo)menuInfo).targetView)).position); + final Artist artist = (Artist) mList.getAdapter().getItem(((OneLabelItemView) (((AdapterContextMenuInfo) + menuInfo).targetView)).position); menu.setHeaderTitle(artist.name); menu.add(0, ITEM_CONTEXT_QUEUE, 1, "Queue all songs from Artist"); menu.add(0, ITEM_CONTEXT_PLAY, 2, "Play all songs from Artist"); @@ -137,76 +138,95 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn } menu.add(0, ITEM_CONTEXT_INFO, 5, "View Details"); } - + public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final Artist artist = (Artist)mList.getAdapter().getItem(((OneLabelItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final Artist artist = (Artist) mList.getAdapter().getItem(((OneLabelItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_QUEUE: mMusicManager.addToPlaylist(new QueryResponse( - mActivity, - "Adding all songs by " + artist.name + " to playlist...", + mActivity, + "Adding all songs by " + artist.name + " to playlist...", "Error adding songs!" - ), artist, mActivity.getApplicationContext()); + ), artist, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_PLAY: mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs by " + artist.name + "...", + mActivity, + "Playing all songs by " + artist.name + "...", "Error playing songs!", true - ), artist, mActivity.getApplicationContext()); + ), artist, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_QUEUE_GENRE: mMusicManager.addToPlaylist(new QueryResponse( - mActivity, - "Adding all songs of genre " + mGenre.name + " by " + artist.name + " to playlist...", + mActivity, + "Adding all songs of genre " + mGenre.name + " by " + artist.name + " to playlist...", "Error adding songs!" - ), artist, mGenre, mActivity.getApplicationContext()); + ), artist, mGenre, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_PLAY_GENRE: mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs of genre " + mGenre.name + " by " + artist.name + "...", + mActivity, + "Playing all songs of genre " + mGenre.name + " by " + artist.name + "...", "Error playing songs!", true - ), artist, mGenre, mActivity.getApplicationContext()); + ), artist, mGenre, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_INFO: - DialogFactory.getArtistDetail(mMusicManager, mActivity, artist, mActivity.getApplicationContext()).show(); + DialogFactory.getArtistDetail(mMusicManager, mActivity, artist, mActivity.getApplicationContext()) + .show(); break; default: return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { } - + + public void onActivityPause() { + if (mMusicManager != null) { + mMusicManager.setController(null); + mMusicManager.postActivity(); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mMusicManager != null) { + mMusicManager.setController(this); + } + } + private class ArtistAdapter extends ArrayAdapter { ArtistAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final OneLabelItemView view; if (convertView == null) { - view = new OneLabelItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), false); + view = new OneLabelItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), false); } else { - view = (OneLabelItemView)convertView; + view = (OneLabelItemView) convertView; } final Artist artist = this.getItem(position); view.reset(); view.position = position; view.title = artist.name; - + if (mLoadCovers) { view.getResponse().load(artist, !mPostScrollLoader.isListIdle()); } if (mLoadCovers) { - if(mMusicManager.coverLoaded(artist, mThumbSize)){ + if (mMusicManager.coverLoaded(artist, mThumbSize)) { view.setCover(mMusicManager.getCoverSync(artist, mThumbSize)); - }else{ + } else { view.setCover(null); view.getResponse().load(artist, !mPostScrollLoader.isListIdle()); } @@ -215,21 +235,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - private static final long serialVersionUID = 4360738733222799619L; - - - public void onActivityPause() { - if (mMusicManager != null) { - mMusicManager.setController(null); - mMusicManager.postActivity(); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mMusicManager != null) { - mMusicManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/EpisodeListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/EpisodeListController.java similarity index 66% rename from src/org/xbmc/android/remote/presentation/controller/EpisodeListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/EpisodeListController.java index 47287460..19b077a4 100644 --- a/src/org/xbmc/android/remote/presentation/controller/EpisodeListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/EpisodeListController.java @@ -21,26 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.EpisodeDetailsActivity; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; -import org.xbmc.android.remote.presentation.widget.FlexibleItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.object.Episode; -import org.xbmc.api.object.Movie; -import org.xbmc.api.object.Season; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -65,14 +45,32 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.EpisodeDetailsActivity; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; +import org.xbmc.android.remote.presentation.widget.FlexibleItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.object.Episode; +import org.xbmc.api.object.Movie; +import org.xbmc.api.object.Season; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class EpisodeListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; + public static final int ITEM_CONTEXT_PLAY = 1; public static final int ITEM_CONTEXT_INFO = 2; public static final int ITEM_CONTEXT_PLAY_FROM_HERE = 3; public static final int ITEM_CONTEXT_QUEUE = 4; - public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_TITLE_ASC = 21; @@ -83,25 +81,23 @@ public class EpisodeListController extends ListController implements IController public static final int MENU_SORT_BY_RATING_DESC = 26; public static final int MENU_SORT_BY_EPISODE_ASC = 27; public static final int MENU_SORT_BY_EPISODE_DESC = 28; - + private static final int mThumbSize = ThumbSize.SMALL; + private static final long serialVersionUID = 1088971882661811256L; + private static Bitmap mWatchedBitmap; private Season mSeason; private boolean mRecentEpisodes = false; - private ITvShowManager mTvManager; private IControlManager mControlManager; - private boolean mLoadCovers = false; - - private static Bitmap mWatchedBitmap; - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mTvManager = ManagerFactory.getTvManager(this); mControlManager = ManagerFactory.getControlManager(this); - + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; - + if (!isCreated()) { super.onCreate(activity, handler, list); @@ -109,19 +105,19 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mSeason = (Season)activity.getIntent().getSerializableExtra(ListController.EXTRA_SEASON); - + + mSeason = (Season) activity.getIntent().getSerializableExtra(ListController.EXTRA_SEASON); + activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_poster); mWatchedBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.check_mark); setupIdleListener(); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; - final Episode episode = (Episode)mList.getAdapter().getItem(((FiveLabelsItemView)view).position); + if (isLoading()) return; + final Episode episode = (Episode) mList.getAdapter().getItem(((FiveLabelsItemView) view).position); Intent nextActivity = new Intent(view.getContext(), EpisodeDetailsActivity.class); nextActivity.putExtra(ListController.EXTRA_EPISODE, episode); mActivity.startActivity(nextActivity); @@ -131,12 +127,12 @@ public void onItemClick(AdapterView parent, View view, int position, long id) fetch(); } } - - private void fetch() { + + private void fetch() { // tv show and episode both are using the same manager so set the sort key here - ((ISortableManager)mTvManager).setSortKey(AbstractManager.PREF_SORT_KEY_EPISODE); - ((ISortableManager)mTvManager).setPreferences(mActivity.getPreferences(Context.MODE_PRIVATE)); - + ((ISortableManager) mTvManager).setSortKey(AbstractManager.PREF_SORT_KEY_EPISODE); + ((ISortableManager) mTvManager).setPreferences(mActivity.getPreferences(Context.MODE_PRIVATE)); + final String title = mSeason != null ? mSeason.getName() + " - " : "" + "Episodes"; DataResponse> response = new DataResponse>() { public void run() { @@ -148,70 +144,70 @@ public void run() { } } }; - + showOnLoading(); setTitle(title + "..."); - if(mSeason != null){ + if (mSeason != null) { mTvManager.getEpisodes(response, mSeason, mActivity.getApplicationContext()); - } - else{ + } else { mTvManager.getRecentlyAddedEpisodes(response, mActivity.getApplicationContext()); mRecentEpisodes = true; } - + } - + /** * Shows a dialog and refreshes the movie library if user confirmed. + * * @param activity */ public void refreshMovieLibrary(final Activity activity) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage("Are you sure you want XBMC to rescan your movie library?") - .setCancelable(false) - .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mControlManager.updateLibrary(new DataResponse() { - public void run() { - final String message; - if (value) { - message = "Movie library updated has been launched."; - } else { - message = "Error launching movie library update."; + .setCancelable(false) + .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mControlManager.updateLibrary(new DataResponse() { + public void run() { + final String message; + if (value) { + message = "Movie library updated has been launched."; + } else { + message = "Error launching movie library update."; + } + Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); + toast.show(); } - Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); - toast.show(); - } - }, "video", mActivity.getApplicationContext()); - } - }) - .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + }, "video", mActivity.getApplicationContext()); + } + }) + .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); builder.create().show(); } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; + final FiveLabelsItemView view = (FiveLabelsItemView) ((AdapterContextMenuInfo) menuInfo).targetView; menu.setHeaderTitle(view.title); menu.add(0, ITEM_CONTEXT_PLAY, 1, "Play Episode"); menu.add(0, ITEM_CONTEXT_PLAY_FROM_HERE, 2, "Play From Here"); menu.add(0, ITEM_CONTEXT_QUEUE, 3, "Queue Episode"); menu.add(0, ITEM_CONTEXT_INFO, 4, "View Details"); } - + public void onContextItemSelected(MenuItem item) { - int listpos = ((FiveLabelsItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position; - final Episode episode = (Episode)mList.getAdapter().getItem(listpos); + int listpos = ((FiveLabelsItemView) ((AdapterContextMenuInfo) item.getMenuInfo()).targetView).position; + final Episode episode = (Episode) mList.getAdapter().getItem(listpos); switch (item.getItemId()) { case ITEM_CONTEXT_PLAY: - mControlManager.playFile(new DataResponse(){ + mControlManager.playFile(new DataResponse() { public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + if (value) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); } } }, episode.fileName, 1, mActivity.getApplicationContext()); @@ -222,27 +218,29 @@ public void run() { mActivity.startActivity(nextActivity); break; case ITEM_CONTEXT_PLAY_FROM_HERE: - mControlManager.clearPlaylist(new DataResponse(), 1, mActivity); + mControlManager.clearPlaylist(new DataResponse(), 1, mActivity); //mControlManager.setPlaylistId(new DataResponse(), 1, mActivity); int numitems = mList.getAdapter().getCount(); - for(int i = 0; i < numitems; i++) - mControlManager.addToPlaylist(new DataResponse(), ((Episode)mList.getAdapter().getItem(i)).fileName, 1, mActivity); - mControlManager.setPlaylistPos(new DataResponse(){ + for (int i = 0; i < numitems; i++) + mControlManager.addToPlaylist(new DataResponse(), ((Episode) mList.getAdapter().getItem + (i)).fileName, 1, mActivity); + mControlManager.setPlaylistPos(new DataResponse() { public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + if (value) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); } } }, 1, listpos, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_QUEUE: - mControlManager.addToPlaylist(new QueryResponse(mActivity, "Queued episode: " + episode.getName(), "Error queueing file."), episode.fileName, 1, mActivity); + mControlManager.addToPlaylist(new QueryResponse(mActivity, "Queued episode: " + episode.getName(), + "Error queueing file."), episode.fileName, 1, mActivity); break; default: return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { // if (mActor != null || mGenre != null) { @@ -258,96 +256,132 @@ public void onCreateOptionsMenu(Menu menu) { // menu.add(0, MENU_SWITCH_VIEW, 0, "Switch view").setIcon(R.drawable.menu_view); createShowHideWatchedToggle(menu); } - + @Override public void onOptionsItemSelected(MenuItem item) { final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - break; - case MENU_SORT_BY_EPISODE_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_NUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_EPISODE_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_NUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, SortType.EPISODE_RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - default: - super.onOptionsItemSelected(item); + case MENU_PLAY_ALL: + break; + case MENU_SORT_BY_EPISODE_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_NUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_EPISODE_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_NUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_EPISODE, + SortType.EPISODE_RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + default: + super.onOptionsItemSelected(item); } } - + @Override protected void refreshList() { hideMessage(); fetch(); } - + + public void onActivityPause() { + if (mTvManager != null) { + mTvManager.setController(null); + mTvManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mTvManager != null) { + mTvManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + private class EpisodeAdapter extends ArrayAdapter { EpisodeAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final FlexibleItemView view; if (convertView == null) { - view = new FlexibleItemView(mActivity, mTvManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), false); + view = new FlexibleItemView(mActivity, mTvManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), false); } else { - view = (FlexibleItemView)convertView; + view = (FlexibleItemView) convertView; } - + final Episode episode = getItem(position); view.reset(); view.position = position; view.posterOverlay = episode.numWatched > 0 ? mWatchedBitmap : null; view.title = episode.episode + ". " + episode.title; - if(mRecentEpisodes){ + if (mRecentEpisodes) { view.title = episode.showTitle; - view.subtitle = episode.season + "x" + (episode.episode < 10? "0" : "") + episode.episode + ". " + episode.title; + view.subtitle = episode.season + "x" + (episode.episode < 10 ? "0" : "") + episode.episode + ". " + + episode.title; } - view.subtitleRight = episode.firstAired!=null?episode.firstAired:""; + view.subtitleRight = episode.firstAired != null ? episode.firstAired : ""; // view.bottomtitle = show.numEpisodes + " episodes"; - view.bottomright = String.valueOf(((float)Math.round(episode.rating *10))/ 10); - + view.bottomright = String.valueOf(((float) Math.round(episode.rating * 10)) / 10); + if (mLoadCovers) { - if(mTvManager.coverLoaded(episode, mThumbSize)){ + if (mTvManager.coverLoaded(episode, mThumbSize)) { view.setCover(mTvManager.getCoverSync(episode, mThumbSize)); - }else{ + } else { view.setCover(null); view.getResponse().load(episode, !mPostScrollLoader.isListIdle()); } @@ -355,28 +389,5 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - private static final long serialVersionUID = 1088971882661811256L; - - public void onActivityPause() { - if (mTvManager != null) { - mTvManager.setController(null); - mTvManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mTvManager != null) { - mTvManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/FileListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/FileListController.java similarity index 83% rename from src/org/xbmc/android/remote/presentation/controller/FileListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/FileListController.java index 35b628c8..b3cdda1d 100644 --- a/src/org/xbmc/android/remote/presentation/controller/FileListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/FileListController.java @@ -21,21 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; -import java.util.HashMap; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.info.FileTypes; -import org.xbmc.api.object.FileLocation; -import org.xbmc.api.type.MediaType; - import android.app.Activity; import android.content.Intent; import android.content.res.Resources; @@ -54,54 +39,68 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.info.FileTypes; +import org.xbmc.api.object.FileLocation; +import org.xbmc.api.type.MediaType; + +import java.util.ArrayList; +import java.util.HashMap; + public class FileListController extends ListController implements IController { - + public static final int MESSAGE_HANDLE_DATA = 1; public static final int MESSAGE_CONNECTION_ERROR = 2; private static final int ITEM_CONTEXT_QUEUE = 0; private static final int ITEM_CONTEXT_PLAY = 1; - + private static final long serialVersionUID = -3883887349523448733L; + // from ListActivity.java + protected ListAdapter mAdapter; private HashMap mFileItems; private volatile String mGettingUrl; private int mMediaType = MediaType.UNKNOWN; - - // from ListActivity.java - protected ListAdapter mAdapter; - private IInfoManager mInfoManager; private IControlManager mControlManager; - - public FileListController() {} - + + public FileListController() { + } + public FileListController(int mediaType) { mMediaType = mediaType; } - + public void onCreate(Activity activity, Handler handler, AbsListView list) { mInfoManager = ManagerFactory.getInfoManager(this); mControlManager = ManagerFactory.getControlManager(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); - + if (mMediaType == MediaType.UNKNOWN) { mMediaType = mActivity.getIntent().getIntExtra(EXTRA_SHARE_TYPE, MediaType.MUSIC); } mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_file); - + final String path = mActivity.getIntent().getStringExtra(EXTRA_PATH); final String displayPath = mActivity.getIntent().getStringExtra(EXTRA_DISPLAY_PATH); fillUp(path == null ? "" : path, displayPath); - + activity.registerForContextMenu(mList); mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; if (mFileItems == null) return; - - FileLocation item = mFileItems.get(((FileLocation)parent.getAdapter().getItem(position)).name); + + FileLocation item = mFileItems.get(((FileLocation) parent.getAdapter().getItem(position)).name); if (item.isDirectory) { Intent nextActivity = new Intent(mActivity, ListActivity.class); nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new FileListController()); @@ -110,10 +109,10 @@ public void onItemClick(AdapterView parent, View view, int position, long id) nextActivity.putExtra(ListController.EXTRA_DISPLAY_PATH, item.displayPath); mActivity.startActivity(nextActivity); } else { - switch(item.mediaType) { + switch (item.mediaType) { // case 0: // break; - + case MediaType.PICTURES: mControlManager.showPicture(new DataResponse() { public void run() { @@ -124,13 +123,17 @@ public void run() { }, item.path, mActivity.getApplicationContext()); break; default: - mControlManager.playFile(new DataResponse(){ - public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); - } - } - }, item.path, MediaType.getPlaylistType(item.mediaType), mActivity.getApplicationContext());break; + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + mActivity.startActivity(new Intent(mActivity, + NowPlayingActivity.class)); + } + } + }, item.path, MediaType.getPlaylistType(item.mediaType), + mActivity.getApplicationContext() + ); + break; } } } @@ -138,58 +141,11 @@ public void run() { mList.setOnKeyListener(new ListControllerOnKeyListener()); } } - - private class FileItemAdapter extends ArrayAdapter { - FileItemAdapter(Activity activity, ArrayList items) { - super(activity, 0, items); - } - public View getView(int position, View convertView, ViewGroup parent) { - - final OneLabelItemView view; - if (convertView == null) { - view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); - } else { - view = (OneLabelItemView)convertView; - } - final FileLocation fileItem = this.getItem(position); - view.reset(); - view.position = position; - view.title = fileItem.name; - final Resources res = mActivity.getResources(); - if (fileItem.isArchive) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_zip)); - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_zip)); - } else if (fileItem.isDirectory) { - if (fileItem.path.startsWith("shout://")) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_shoutcast)); - } else if (fileItem.path.startsWith("lastfm://")) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_lastfm)); - } else { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_folder)); - } - } else { - final String ext = FileTypes.getExtension(fileItem.path); - if (FileTypes.isAudio(ext)) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_song)); - } else if (FileTypes.isVideo(ext)) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_video)); - } else if (FileTypes.isPicture(ext)) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_picture)); - } else if (FileTypes.isPlaylist(ext)) { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_playing)); - } else { - view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_file)); - } - } - return view; - } - } - - + private void fillUp(final String url, final String displayPath) { if (mGettingUrl != null) return; - + mGettingUrl = url; mFileItems = null; mList.setTextFilterEnabled(false); @@ -209,41 +165,44 @@ public void run() { } } }; - + if (mGettingUrl.length() == 0) { mInfoManager.getShares(mediaListHandler, mMediaType, mActivity.getApplicationContext()); } else { mInfoManager.getDirectory(mediaListHandler, mGettingUrl, mActivity.getApplicationContext(), mMediaType); } } - - /** - * Provide the cursor for the list view. - */ - public void setListAdapter(ListAdapter adapter) { - synchronized (this) { - mAdapter = adapter; - ((AdapterView) mList).setAdapter(adapter); - } - } + + /** + * Provide the cursor for the list view. + */ + public void setListAdapter(ListAdapter adapter) { + synchronized (this) { + mAdapter = adapter; + ((AdapterView) mList).setAdapter(adapter); + } + } @Override public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final FileLocation loc = (FileLocation) mList.getAdapter().getItem(((OneLabelItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final FileLocation loc = (FileLocation) mList.getAdapter().getItem(((OneLabelItemView) ( + (AdapterContextMenuInfo) item.getMenuInfo()).targetView).position); int playlistid = Integer.valueOf(MediaType.getPlaylistType(mMediaType)); - switch(item.getItemId()) { - case ITEM_CONTEXT_QUEUE: - mControlManager.queueFolder(new QueryResponse(mActivity, "Queueing " + loc.path, "Error queueing " + loc.path), loc.path, playlistid, mActivity); - break; - case ITEM_CONTEXT_PLAY: - mControlManager.playFile(new DataResponse(){ - public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + switch (item.getItemId()) { + case ITEM_CONTEXT_QUEUE: + mControlManager.queueFolder(new QueryResponse(mActivity, "Queueing " + loc.path, + "Error queueing " + loc.path), loc.path, playlistid, mActivity); + break; + case ITEM_CONTEXT_PLAY: + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + } } - } - }, loc.path, playlistid, mActivity.getApplicationContext());break; + }, loc.path, playlistid, mActivity.getApplicationContext()); + break; } } @@ -251,12 +210,12 @@ public void run() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! Log.d("FileListController", "Create Context Menu"); - final OneLabelItemView view = (OneLabelItemView)((AdapterContextMenuInfo)menuInfo).targetView; - menu.setHeaderTitle(((FileLocation)mList.getItemAtPosition(view.getPosition())).name); + final OneLabelItemView view = (OneLabelItemView) ((AdapterContextMenuInfo) menuInfo).targetView; + menu.setHeaderTitle(((FileLocation) mList.getItemAtPosition(view.getPosition())).name); menu.add(0, ITEM_CONTEXT_QUEUE, 1, "Queue"); menu.add(0, ITEM_CONTEXT_PLAY, 2, "Play Now"); } - + public void onActivityPause() { if (mInfoManager != null) { mInfoManager.setController(null); @@ -276,6 +235,51 @@ public void onActivityResume(Activity activity) { } super.onActivityResume(activity); } - - private static final long serialVersionUID = -3883887349523448733L; + + private class FileItemAdapter extends ArrayAdapter { + FileItemAdapter(Activity activity, ArrayList items) { + super(activity, 0, items); + } + + public View getView(int position, View convertView, ViewGroup parent) { + + final OneLabelItemView view; + if (convertView == null) { + view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); + } else { + view = (OneLabelItemView) convertView; + } + final FileLocation fileItem = this.getItem(position); + view.reset(); + view.position = position; + view.title = fileItem.name; + final Resources res = mActivity.getResources(); + if (fileItem.isArchive) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_zip)); + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_zip)); + } else if (fileItem.isDirectory) { + if (fileItem.path.startsWith("shout://")) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_shoutcast)); + } else if (fileItem.path.startsWith("lastfm://")) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_lastfm)); + } else { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_folder)); + } + } else { + final String ext = FileTypes.getExtension(fileItem.path); + if (FileTypes.isAudio(ext)) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_song)); + } else if (FileTypes.isVideo(ext)) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_video)); + } else if (FileTypes.isPicture(ext)) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_picture)); + } else if (FileTypes.isPlaylist(ext)) { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_playing)); + } else { + view.setCover(BitmapFactory.decodeResource(res, R.drawable.icon_file)); + } + } + return view; + } + } } diff --git a/src/org/xbmc/android/remote/presentation/controller/GestureController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/GestureController.java similarity index 80% rename from src/org/xbmc/android/remote/presentation/controller/GestureController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/GestureController.java index cd189705..d862860a 100644 --- a/src/org/xbmc/android/remote/presentation/controller/GestureController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/GestureController.java @@ -1,92 +1,95 @@ -package org.xbmc.android.remote.presentation.controller; - -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Context; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class GestureController extends AbstractController implements INotifiableController, IController { - - IEventClientManager mEventClientManager; - private long mTimestamp = 0; - - public GestureController(Context context) { - mEventClientManager = ManagerFactory.getEventClientManager(this); - } - - /** - * Sends a keyboard event - * @param button - * @return - */ - private boolean keyboardAction(String button) { - mEventClientManager.sendButton("KB", button, false, true, true, (short)0, (byte)0); - return true; - } - - - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) - return keyboardAction(ButtonCodes.KEYBOARD_ENTER); - else{ - // check when the last trackball move happened to avoid too speedy selections - long newstamp = System.currentTimeMillis(); - if (newstamp - mTimestamp > 300){ - mTimestamp = newstamp; - if (Math.abs(event.getX()) > 0.15f) { - return keyboardAction(event.getX() < 0 ? ButtonCodes.KEYBOARD_LEFT : ButtonCodes.KEYBOARD_RIGHT); - } else if (Math.abs(event.getY()) > 0.15f){ - return keyboardAction(event.getY() < 0 ? ButtonCodes.KEYBOARD_UP : ButtonCodes.KEYBOARD_DOWN); - } - } - } - return false; - } - - - public boolean onKeyDown(int keyCode, KeyEvent event) { - char key = (char)event.getUnicodeChar(); - if (key > 'A' && key < 'z') - return keyboardAction("" + key); - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_LEFT: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_RIGHT: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_ENTER, false, true, true, (short)0, (byte)0); - return true; - default: - return false; - } - } - - public void onActivityPause() { - mEventClientManager.setController(null); - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - mEventClientManager.setController(this); - } +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.content.Context; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.eventclient.ButtonCodes; + +public class GestureController extends AbstractController implements INotifiableController, IController { + + IEventClientManager mEventClientManager; + private long mTimestamp = 0; + + public GestureController(Context context) { + mEventClientManager = ManagerFactory.getEventClientManager(this); + } + + /** + * Sends a keyboard event + * + * @param button + * @return + */ + private boolean keyboardAction(String button) { + mEventClientManager.sendButton("KB", button, false, true, true, (short) 0, (byte) 0); + return true; + } + + + public boolean onTrackballEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) + return keyboardAction(ButtonCodes.KEYBOARD_ENTER); + else { + // check when the last trackball move happened to avoid too speedy selections + long newstamp = System.currentTimeMillis(); + if (newstamp - mTimestamp > 300) { + mTimestamp = newstamp; + if (Math.abs(event.getX()) > 0.15f) { + return keyboardAction(event.getX() < 0 ? ButtonCodes.KEYBOARD_LEFT : ButtonCodes.KEYBOARD_RIGHT); + } else if (Math.abs(event.getY()) > 0.15f) { + return keyboardAction(event.getY() < 0 ? ButtonCodes.KEYBOARD_UP : ButtonCodes.KEYBOARD_DOWN); + } + } + } + return false; + } + + + public boolean onKeyDown(int keyCode, KeyEvent event) { + char key = (char) event.getUnicodeChar(); + if (key > 'A' && key < 'z') + return keyboardAction("" + key); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_DOWN: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_UP: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_LEFT: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short) 0, (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_CENTER: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_ENTER, false, true, true, (short) 0, (byte) 0); + return true; + default: + return false; + } + } + + public void onActivityPause() { + mEventClientManager.setController(null); + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + mEventClientManager.setController(this); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/HomeController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/HomeController.java similarity index 85% rename from src/org/xbmc/android/remote/presentation/controller/HomeController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/HomeController.java index 7b683d03..534c185d 100644 --- a/src/org/xbmc/android/remote/presentation/controller/HomeController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/HomeController.java @@ -1,600 +1,617 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.GestureRemoteActivity; -import org.xbmc.android.remote.presentation.activity.HomeActivity; -import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.activity.MovieLibraryActivity; -import org.xbmc.android.remote.presentation.activity.MusicLibraryActivity; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.activity.RemoteActivity; -import org.xbmc.android.remote.presentation.activity.TvShowLibraryActivity; -import org.xbmc.android.remote.presentation.notification.NowPlayingNotificationManager; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.android.util.ConnectionFactory; -import org.xbmc.android.util.HostFactory; -import org.xbmc.android.util.PowerDown; -import org.xbmc.android.util.WakeOnLan; -import org.xbmc.android.util.WifiHelper; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Episode; -import org.xbmc.api.object.Host; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.object.Movie; -import org.xbmc.api.object.Season; -import org.xbmc.api.object.TvShow; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.MediaType; -import org.xbmc.httpapi.BroadcastListener; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.net.wifi.WifiManager.WifiLock; -import android.os.Bundle; -import android.os.CountDownTimer; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; -import android.widget.AdapterView.OnItemClickListener; - -public class HomeController extends AbstractController implements INotifiableController, IController, Observer, OnSharedPreferenceChangeListener { - - private static final int HOME_ACTION_REMOTE = 0; - private static final int HOME_ACTION_MUSIC = 1; - private static final int HOME_ACTION_VIDEOS = 2; - private static final int HOME_ACTION_PICTURES = 3; - private static final int HOME_ACTION_NOWPLAYING = 4; - private static final int HOME_ACTION_RECONNECT = 5; - private static final int HOME_ACTION_WOL = 6; - private static final int HOME_ACTION_TVSHOWS = 7; - private static final int HOME_ACTION_POWERDOWN = 8; - - private IInfoManager mInfoManager; - - private static final String TAG = "HomeController"; - private static final boolean DEBUG = false; - - private DataResponse mUpdateVersionHandler; - - private HomeAdapter mHomeMenu; - private HomeAdapter mOfflineMenu; - - private int mNumCoversDownloaded = 0; - - private WolCounter mWolCounter; - - private final HomeItem mHomeWol = new HomeItem(HOME_ACTION_WOL, R.drawable.icon_home_power, "Power On", "Turn your XBMC's"); - - private final GridView mMenuGrid; - - public HomeController(Activity activity, Handler handler, GridView menuGrid) { - super.onCreate(activity, handler); - mInfoManager = ManagerFactory.getInfoManager(this); - mMenuGrid = menuGrid; - setupMenuItems(menuGrid); -// BroadcastListener bcl = BroadcastListener.getInstance(ConnectionManager.getHttpClient(this)); -// bcl.addObserver(this); - } - - public View.OnClickListener getOnHostChangeListener() { - return new OnClickListener() { - public void onClick(View v) { - openHostChanger(); - } - }; - } - - /** - * Opens the host changer popup. - */ - public void openHostChanger() { - - // granted, this is butt-ugly. better ideas, be my guest. - final ArrayList hosts = HostFactory.getHosts(mActivity.getApplicationContext()); - final HashMap hostMap = new HashMap(); - final CharSequence[] names = new CharSequence[hosts.size()]; - int i = 0; - for (Host host : hosts) { - names[i] = host.name; - hostMap.put(i, host); - i++; - } - if (hosts.size() > 0) { - AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - builder.setTitle("Pick your XBMC!"); - builder.setItems(names, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - final Host host = hostMap.get(which); - if (HostFactory.host != null && HostFactory.host.id == host.id) { - Toast.makeText(mActivity.getApplicationContext(), "You've picked the same host as the current.", Toast.LENGTH_SHORT).show(); - } else { - Log.i(TAG, "Switching host to " + (host == null ? "" : host.addr) + "."); - HostFactory.saveHost(mActivity.getApplicationContext(), host); - final GridView menuGrid = (GridView)mActivity.findViewById(R.id.HomeItemGridView); - resetupOfflineMenuItems(); - setHomeAdapter(menuGrid, mOfflineMenu); - final Button versionButton = (Button)mActivity.findViewById(R.id.home_version_button); - versionButton.setText("Connecting..."); - Toast.makeText(mActivity.getApplicationContext(), "Changed host to " + host.toString() + ".", Toast.LENGTH_SHORT).show(); - ClientFactory.resetClient(host); - mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); - } - } - }); - AlertDialog dialog = builder.create(); - dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND); - dialog.show(); - } else { - Toast.makeText(mActivity.getApplicationContext(), "No XBMC hosts defined, please do that first.", Toast.LENGTH_LONG).show(); - Intent intent = new Intent(mActivity, HostSettingsActivity.class); - mActivity.startActivity(intent); - } - } - - public void setupVersionHandler(final Handler handler, final Button versionTextView, final GridView homeItemGrid) { - mUpdateVersionHandler = new DataResponse() { - public void run() { - if (!mPaused) { - handler.post(new Runnable() { - public void run() { - if (!ConnectionFactory.isNetworkAvailable(mActivity.getApplicationContext())) { - versionTextView.setText("No network"); - } - if (!value.equals("")) { - if (mWolCounter != null) { - mWolCounter.cancel(); - } - versionTextView.setText("XBMC " + value); - homeItemGrid.setAdapter(mHomeMenu); - NowPlayingNotificationManager.getInstance(mActivity.getApplicationContext()).startNotificating(); - } else { - versionTextView.setText("Check Settings and retry"); - homeItemGrid.setAdapter(mOfflineMenu); - } - } - }); - } - } - }; - } - - private void setupMenuItems(GridView menuGrid) { - final HomeItem remote = new HomeItem(HOME_ACTION_REMOTE, R.drawable.icon_home_remote, "Remote Control", "Use as"); - - final ArrayList homeItems = new ArrayList(); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext()); - if (prefs.getBoolean("setting_show_home_music", true)) - homeItems.add(new HomeItem(HOME_ACTION_MUSIC, R.drawable.icon_home_music, "Music", "Listen to")); - if (prefs.getBoolean("setting_show_home_movies", true)) - homeItems.add(new HomeItem(HOME_ACTION_VIDEOS, R.drawable.icon_home_movie, "Movies", "Watch your")); - if (prefs.getBoolean("setting_show_home_tv", true)) - homeItems.add(new HomeItem(HOME_ACTION_TVSHOWS, R.drawable.icon_home_tv, "TV Shows", "Watch your")); - if (prefs.getBoolean("setting_show_home_pictures", true)) - homeItems.add(new HomeItem(HOME_ACTION_PICTURES, R.drawable.icon_home_picture, "Pictures", "Browse your")); - - prefs.registerOnSharedPreferenceChangeListener(this); - homeItems.add(new HomeItem(HOME_ACTION_NOWPLAYING, R.drawable.icon_home_playing, "Now Playing", "See what's")); - homeItems.add(remote); - if (prefs.getBoolean("setting_show_home_powerdown", false)) - homeItems.add(new HomeItem(HOME_ACTION_POWERDOWN, R.drawable.icon_home_power, "Power Off", "Turn your XBMC off")); - - final ArrayList offlineItems = new ArrayList(); - offlineItems.add(remote); - offlineItems.add(new HomeItem(HOME_ACTION_RECONNECT, R.drawable.icon_home_reconnect, "Connect", "Try again to")); - -// final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext()); -// final String wolMac = prefs.getString("setting_wol", ""); - if (HostFactory.host != null && !"".equals(HostFactory.host.mac_addr)) - offlineItems.add(mHomeWol); - - mHomeMenu = new HomeAdapter(mActivity, homeItems); - mOfflineMenu = new HomeAdapter(mActivity, offlineItems); - - setHomeAdapter(menuGrid, mOfflineMenu); - } - - /** - * Due to host changing we need to resetup the offline items with checking of WOL prefs and WiFi activation. - * @param menuGrid - */ - private void resetupOfflineMenuItems() { - mOfflineMenu.remove(mHomeWol); - if (HostFactory.host != null && !"".equals(HostFactory.host.mac_addr)) - mOfflineMenu.add(mHomeWol); - } - - private void setHomeAdapter(GridView menuGrid, HomeAdapter adapter) { - menuGrid.setAdapter(adapter); - menuGrid.setOnItemClickListener(getHomeMenuOnClickListener()); - menuGrid.setSelected(true); - menuGrid.setSelection(0); - } - - private OnItemClickListener getHomeMenuOnClickListener() { - return new OnItemClickListener() { - - public void onItemClick(AdapterView listView, View v, int position, long ID) { - HomeItem item = (HomeItem)listView.getAdapter().getItem(position); - final Host host = HostFactory.host; - Intent intent = null; - switch (item.ID) { - case HOME_ACTION_REMOTE: - final int mode = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE).getInt(RemoteController.LAST_REMOTE_PREFNAME, -1); - if (mode == RemoteController.LAST_REMOTE_GESTURE) { - intent = new Intent(v.getContext(), GestureRemoteActivity.class); - } else { - intent = new Intent(v.getContext(), RemoteActivity.class); - } - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - break; - case HOME_ACTION_MUSIC: - intent = new Intent(v.getContext(), MusicLibraryActivity.class); - break; - case HOME_ACTION_VIDEOS: - intent = new Intent(v.getContext(), MovieLibraryActivity.class); - break; - case HOME_ACTION_TVSHOWS: - intent = new Intent(v.getContext(), TvShowLibraryActivity.class); - break; - case HOME_ACTION_PICTURES: - intent = new Intent(v.getContext(), ListActivity.class); - intent.putExtra(ListController.EXTRA_LIST_CONTROLLER, new FileListController()); - intent.putExtra(ListController.EXTRA_SHARE_TYPE, MediaType.PICTURES); - intent.putExtra(ListController.EXTRA_PATH, ""); - break; - case HOME_ACTION_NOWPLAYING: - intent = new Intent(v.getContext(), NowPlayingActivity.class); - break; - case HOME_ACTION_RECONNECT: - ((Button)mActivity.findViewById(R.id.home_version_button)).setText("Reconnecting..."); - ClientFactory.resetClient(host); - mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); - break; - case HOME_ACTION_WOL: - WakeOnLan wol = new WakeOnLan(); - if (wol.sendMagicPacket(host.mac_addr, host.wol_port)) { // If succeeded in sending the magic packet, begin the countdown - if(mWolCounter != null) mWolCounter.cancel(); - mWolCounter = new WolCounter(host.wol_wait * 1000,1000); - mWolCounter.start(); - } - break; - case HOME_ACTION_POWERDOWN: - PowerDown powerdown = new PowerDown(); - powerdown.ShowDialog(mActivity); - break; - } - if (intent != null) { - mActivity.startActivity(intent); - } - } - }; - } - - public void update(Observable observable, Object data) { - if (data instanceof BroadcastListener.Event) { - BroadcastListener.Event event = (BroadcastListener.Event)data; - switch (event.id) { - case BroadcastListener.EVENT_ON_PROGRESS_CHANGED: - Log.i("broadcast", "EVENT_ON_PROGRESS_CHANGED: " + event.getInt(0)); - break; - default: - Log.i("broadcast", "EVENT: " + event.id + ", int = " + event.getInt(0)); - break; - } - } - } - - private class HomeAdapter extends ArrayAdapter { - private Activity mActivity; - HomeAdapter(Activity activity, ArrayList items) { - super(activity, R.layout.home_item, items); - mActivity = activity; - } - public View getView(int position, View convertView, ViewGroup parent) { - View row; - if (convertView == null) { - LayoutInflater inflater = mActivity.getLayoutInflater(); - row = inflater.inflate(R.layout.home_item, null); - } else { - row = convertView; - } - HomeItem item = this.getItem(position); - TextView title = (TextView)row.findViewById(R.id.TitleTextView); - TextView subtitle = (TextView)row.findViewById(R.id.SubtitleTextView); - ImageView icon = (ImageView)row.findViewById(R.id.IconImageView); - title.setText(item.title); - subtitle.setText(item.subtitle); - icon.setImageResource(item.icon); - return row; - } - } - - private class HomeItem { - public final int ID, icon; - public final String title, subtitle; - - public HomeItem(int ID, int icon, String title, String subtitle) { - this.ID = ID; - this.icon = icon; - this.title = title; - this.subtitle = subtitle; - } - } - - public class WolCounter extends CountDownTimer { - private Button textCount; - - public WolCounter(long millisInFuture, long countDownInterval) { - super(millisInFuture, countDownInterval); - - textCount = ((Button)mActivity.findViewById(R.id.home_version_button)); - } - - @Override - public void onFinish() { - ((Button)mActivity.findViewById(R.id.home_version_button)).setText("Attempting to reconnect..."); - mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); - mWolCounter = null; - } - - @Override - public void onTick(long millisUntilFinished) { - textCount.setText("Waiting for " + millisUntilFinished/1000 + " more seconds..."); - } - } - - public class ProgressThread extends Thread { - - private Handler mHandlerOut; - private Handler mHandlerIn; - private int mTotal; - private int mPosition; - - public final static int MSG_NEXT = 0; - public final static int MSG_QUIT = 1; - - public final static String DATA_TYPE = "type"; - public final static String DATA_TOTAL = "total"; - public final static String DATA_POSITION = "pos"; - public final static String DATA_COVER = "cover"; - - private final int mType; - private final ProgressDialog mProgressDialog; - - public ProgressThread(Handler h, int type, ProgressDialog progressDialog) { - super("Cover download progress Thread"); - if (DEBUG) Log.i(TAG, "[ProgressThread] Creating."); - mHandlerOut = h; - mType = type; - mProgressDialog = progressDialog; - } - - public void cancel() { - if (DEBUG) Log.i(TAG, "[ProgressThread] Cancelling."); - Message msgStart = mHandlerIn.obtainMessage(); - Bundle b = new Bundle(); - b.putInt(DATA_TYPE, mType); - msgStart.what = MSG_QUIT; - msgStart.setData(b); - mHandlerOut.sendMessage(msgStart); - } - - public Handler getHandlerIn() { - return mHandlerIn; - } - - public ArrayList getCovers() { - switch (mType) { - case HomeActivity.MENU_COVER_DOWNLOAD_MOVIES: - final IVideoManager vm = ManagerFactory.getVideoManager(HomeController.this); - final ArrayList movies = vm.getMovies(mActivity.getApplicationContext()); - return new ArrayList(movies); - case HomeActivity.MENU_COVER_DOWNLOAD_MUSIC: - final IMusicManager mm = ManagerFactory.getMusicManager(HomeController.this); - final ArrayList albums = mm.getAlbums(mActivity.getApplicationContext()); - return new ArrayList(albums); - case HomeActivity.MENU_COVER_DOWNLOAD_ACTORS: - final IVideoManager vm2 = ManagerFactory.getVideoManager(HomeController.this); - final ArrayList actors = vm2.getActors(mActivity.getApplicationContext()); - return new ArrayList(actors); - case HomeActivity.MENU_COVER_DOWNLOAD_TVSHOWS: - final ITvShowManager tsm = ManagerFactory.getTvManager(HomeController.this); - final ArrayList shows = tsm.getTvShows(mActivity.getApplicationContext()); - return new ArrayList(shows); - case HomeActivity.MENU_COVER_DOWNLOAD_TVSEASONS: - final ITvShowManager tsm2 = ManagerFactory.getTvManager(HomeController.this); - final ArrayList seasons = tsm2.getAllSeasons(mActivity.getApplicationContext()); - return new ArrayList(seasons); - case HomeActivity.MENU_COVER_DOWNLOAD_TVEPISODES: - final ITvShowManager tsm3 = ManagerFactory.getTvManager(HomeController.this); - final ArrayList episodes = tsm3.getAllEpisodes(mActivity.getApplicationContext()); - return new ArrayList(episodes); - default: - return null; - } - } - - public void run() { - if (DEBUG) Log.i(TAG, "[ProgressThread] Starting progress thread."); - final ArrayList covers = getCovers(); - mTotal = covers.size(); - mPosition = 0; - mProgressDialog.setMax(covers.size()); - boolean started = false; - final WifiLock lock; - if(HostFactory.host != null && HostFactory.host.wifi_only) { - lock = WifiHelper.getInstance(mActivity).getNewWifiLock("BatchDownloader"); - lock.acquire(); - } else - lock = null; - final PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); - final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG); - wl.acquire(); - - Looper.prepare(); - mHandlerIn = new Handler() { - public void handleMessage(Message msgIn) { - switch (msgIn.what) { - case MSG_NEXT: - if (DEBUG) Log.i(TAG, "[ProgressThread] New message received, posting back new cover."); - Message msgOut = mHandlerOut.obtainMessage(); - Bundle b = new Bundle(); - b.putInt(DATA_TOTAL, mTotal); - b.putInt(DATA_POSITION, mPosition); - b.putInt(DATA_TYPE, mType); - if (mPosition < mTotal) { - b.putSerializable(DATA_COVER, covers.get(mPosition)); - } - msgOut.setData(b); - mHandlerOut.sendMessage(msgOut); - mPosition++; - break; - case MSG_QUIT: - if (DEBUG) Log.i(TAG, "[ProgressThread] Exiting."); - Looper.myLooper().quit(); - break; - } - } - }; - if (!started) { - mNumCoversDownloaded = 0; - started = true; - Message msgStart = mHandlerOut.obtainMessage(); - Bundle b = new Bundle(); - b.putInt(DATA_TYPE, mType); - msgStart.what = MSG_NEXT; - msgStart.setData(b); - mHandlerIn.sendMessage(msgStart); - if (DEBUG) Log.i(TAG, "[ProgressThread] Not started, kicking on...."); - } - Looper.loop(); - - if (lock != null) { - lock.release(); - } - wl.release(); - } - } - - /** - * Handles messages coming in to mHandlerOut - * @param msg - * @param progressDialog - * @param progressThread - */ - public void onHandleMessage(Message msg, ProgressDialog progressDialog, final ProgressThread progressThread) { - - int total = msg.getData().getInt(ProgressThread.DATA_TOTAL); - int position = msg.getData().getInt(ProgressThread.DATA_POSITION); - int type = msg.getData().getInt(ProgressThread.DATA_TYPE); - if (msg.what != ProgressThread.MSG_QUIT) { - if (total > 0) { - progressDialog.setProgress(position); - if (position < total) { - final ICoverArt cover = (ICoverArt)msg.getData().getSerializable(ProgressThread.DATA_COVER); - if (DEBUG) Log.i(TAG, "New download message received for position " + position + ": " + cover.getName()); - if (AbstractManager.cacheCover(cover, (INotifiableManager)mInfoManager, mActivity.getApplicationContext())) { - mNumCoversDownloaded++; - } - if (DEBUG) Log.i(TAG, "Cover Downloaded, sending new (empty) message to progress thread."); - final Handler handlerIn = progressThread.getHandlerIn(); - if (progressThread.isAlive() && handlerIn != null) { - handlerIn.sendEmptyMessage(ProgressThread.MSG_NEXT); - } else { - if (DEBUG) Log.i(TAG, "Thread dead, exiting."); - return; - } - } else { - mActivity.dismissDialog(type); - progressThread.getHandlerIn().sendEmptyMessage(ProgressThread.MSG_QUIT); - Toast toast = Toast.makeText(mActivity, mNumCoversDownloaded + " posters downloaded.", Toast.LENGTH_SHORT); - toast.show(); - } - } else { - mActivity.dismissDialog(type); - Toast toast = Toast.makeText(mActivity, "No posters downloaded, libary empty?", Toast.LENGTH_LONG); - toast.show(); - } - } else { - mActivity.dismissDialog(type); - progressThread.getHandlerIn().sendEmptyMessage(ProgressThread.MSG_QUIT); - Toast toast = Toast.makeText(mActivity, "Aborted, " + mNumCoversDownloaded + " posters downloaded.", Toast.LENGTH_SHORT); - toast.show(); - } - } - - public void onActivityPause() { - mInfoManager.setController(null); - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - mInfoManager.setController(this); - mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); - } - - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (key.equals("setting_show_home_music") || key.equals("setting_show_home_movies") || key.equals("setting_show_home_tv") || key.equals("setting_show_home_pictures") || key.equals("setting_show_home_powerdown")) { - setupMenuItems(mMenuGrid); - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.net.wifi.WifiManager.WifiLock; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.GestureRemoteActivity; +import org.xbmc.android.remote.presentation.activity.HomeActivity; +import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.activity.MovieLibraryActivity; +import org.xbmc.android.remote.presentation.activity.MusicLibraryActivity; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.activity.RemoteActivity; +import org.xbmc.android.remote.presentation.activity.TvShowLibraryActivity; +import org.xbmc.android.remote.presentation.notification.NowPlayingNotificationManager; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.android.util.ConnectionFactory; +import org.xbmc.android.util.HostFactory; +import org.xbmc.android.util.PowerDown; +import org.xbmc.android.util.WakeOnLan; +import org.xbmc.android.util.WifiHelper; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Episode; +import org.xbmc.api.object.Host; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.object.Movie; +import org.xbmc.api.object.Season; +import org.xbmc.api.object.TvShow; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.MediaType; +import org.xbmc.httpapi.BroadcastListener; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Observable; +import java.util.Observer; + +public class HomeController extends AbstractController implements INotifiableController, IController, Observer, + OnSharedPreferenceChangeListener { + + private static final int HOME_ACTION_REMOTE = 0; + private static final int HOME_ACTION_MUSIC = 1; + private static final int HOME_ACTION_VIDEOS = 2; + private static final int HOME_ACTION_PICTURES = 3; + private static final int HOME_ACTION_NOWPLAYING = 4; + private static final int HOME_ACTION_RECONNECT = 5; + private static final int HOME_ACTION_WOL = 6; + private final HomeItem mHomeWol = new HomeItem(HOME_ACTION_WOL, R.drawable.icon_home_power, "Power On", + "Turn your XBMC's"); + private static final int HOME_ACTION_TVSHOWS = 7; + private static final int HOME_ACTION_POWERDOWN = 8; + private static final String TAG = "HomeController"; + private static final boolean DEBUG = false; + private final GridView mMenuGrid; + private IInfoManager mInfoManager; + private DataResponse mUpdateVersionHandler; + private HomeAdapter mHomeMenu; + private HomeAdapter mOfflineMenu; + private int mNumCoversDownloaded = 0; + private WolCounter mWolCounter; + + public HomeController(Activity activity, Handler handler, GridView menuGrid) { + super.onCreate(activity, handler); + mInfoManager = ManagerFactory.getInfoManager(this); + mMenuGrid = menuGrid; + setupMenuItems(menuGrid); +// BroadcastListener bcl = BroadcastListener.getInstance(ConnectionManager.getHttpClient(this)); +// bcl.addObserver(this); + } + + public View.OnClickListener getOnHostChangeListener() { + return new OnClickListener() { + public void onClick(View v) { + openHostChanger(); + } + }; + } + + /** + * Opens the host changer popup. + */ + public void openHostChanger() { + + // granted, this is butt-ugly. better ideas, be my guest. + final ArrayList hosts = HostFactory.getHosts(mActivity.getApplicationContext()); + final HashMap hostMap = new HashMap(); + final CharSequence[] names = new CharSequence[hosts.size()]; + int i = 0; + for (Host host : hosts) { + names[i] = host.name; + hostMap.put(i, host); + i++; + } + if (hosts.size() > 0) { + AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + builder.setTitle("Pick your XBMC!"); + builder.setItems(names, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + final Host host = hostMap.get(which); + if (HostFactory.host != null && HostFactory.host.id == host.id) { + Toast.makeText(mActivity.getApplicationContext(), "You've picked the same host as the " + + "current" + + ".", Toast.LENGTH_SHORT).show(); + } else { + Log.i(TAG, "Switching host to " + (host == null ? "" : host.addr) + "."); + HostFactory.saveHost(mActivity.getApplicationContext(), host); + final GridView menuGrid = (GridView) mActivity.findViewById(R.id.HomeItemGridView); + resetupOfflineMenuItems(); + setHomeAdapter(menuGrid, mOfflineMenu); + final Button versionButton = (Button) mActivity.findViewById(R.id.home_version_button); + versionButton.setText("Connecting..."); + Toast.makeText(mActivity.getApplicationContext(), "Changed host to " + host.toString() + ".", + Toast.LENGTH_SHORT).show(); + ClientFactory.resetClient(host); + mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); + } + } + }); + AlertDialog dialog = builder.create(); + dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, + WindowManager.LayoutParams.FLAG_BLUR_BEHIND); + dialog.show(); + } else { + Toast.makeText(mActivity.getApplicationContext(), "No XBMC hosts defined, please do that first.", + Toast.LENGTH_LONG).show(); + Intent intent = new Intent(mActivity, HostSettingsActivity.class); + mActivity.startActivity(intent); + } + } + + public void setupVersionHandler(final Handler handler, final Button versionTextView, final GridView homeItemGrid) { + mUpdateVersionHandler = new DataResponse() { + public void run() { + if (!mPaused) { + handler.post(new Runnable() { + public void run() { + if (!ConnectionFactory.isNetworkAvailable(mActivity.getApplicationContext())) { + versionTextView.setText("No network"); + } + if (!value.equals("")) { + if (mWolCounter != null) { + mWolCounter.cancel(); + } + versionTextView.setText("XBMC " + value); + homeItemGrid.setAdapter(mHomeMenu); + NowPlayingNotificationManager.getInstance(mActivity.getApplicationContext()) + .startNotificating(); + } else { + versionTextView.setText("Check Settings and retry"); + homeItemGrid.setAdapter(mOfflineMenu); + } + } + }); + } + } + }; + } + + private void setupMenuItems(GridView menuGrid) { + final HomeItem remote = new HomeItem(HOME_ACTION_REMOTE, R.drawable.icon_home_remote, "Remote Control", + "Use as"); + + final ArrayList homeItems = new ArrayList(); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext + ()); + if (prefs.getBoolean("setting_show_home_music", true)) + homeItems.add(new HomeItem(HOME_ACTION_MUSIC, R.drawable.icon_home_music, "Music", "Listen to")); + if (prefs.getBoolean("setting_show_home_movies", true)) + homeItems.add(new HomeItem(HOME_ACTION_VIDEOS, R.drawable.icon_home_movie, "Movies", "Watch your")); + if (prefs.getBoolean("setting_show_home_tv", true)) + homeItems.add(new HomeItem(HOME_ACTION_TVSHOWS, R.drawable.icon_home_tv, "TV Shows", "Watch your")); + if (prefs.getBoolean("setting_show_home_pictures", true)) + homeItems.add(new HomeItem(HOME_ACTION_PICTURES, R.drawable.icon_home_picture, "Pictures", "Browse your")); + + prefs.registerOnSharedPreferenceChangeListener(this); + homeItems.add(new HomeItem(HOME_ACTION_NOWPLAYING, R.drawable.icon_home_playing, "Now Playing", "See what's")); + homeItems.add(remote); + if (prefs.getBoolean("setting_show_home_powerdown", false)) + homeItems.add(new HomeItem(HOME_ACTION_POWERDOWN, R.drawable.icon_home_power, "Power Off", + "Turn your XBMC off")); + + final ArrayList offlineItems = new ArrayList(); + offlineItems.add(remote); + offlineItems.add(new HomeItem(HOME_ACTION_RECONNECT, R.drawable.icon_home_reconnect, "Connect", + "Try again to")); + +// final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext +// ()); +// final String wolMac = prefs.getString("setting_wol", ""); + if (HostFactory.host != null && !"".equals(HostFactory.host.mac_addr)) + offlineItems.add(mHomeWol); + + mHomeMenu = new HomeAdapter(mActivity, homeItems); + mOfflineMenu = new HomeAdapter(mActivity, offlineItems); + + setHomeAdapter(menuGrid, mOfflineMenu); + } + + /** + * Due to host changing we need to resetup the offline items with checking of WOL prefs and WiFi activation. + * + */ + private void resetupOfflineMenuItems() { + mOfflineMenu.remove(mHomeWol); + if (HostFactory.host != null && !"".equals(HostFactory.host.mac_addr)) + mOfflineMenu.add(mHomeWol); + } + + private void setHomeAdapter(GridView menuGrid, HomeAdapter adapter) { + menuGrid.setAdapter(adapter); + menuGrid.setOnItemClickListener(getHomeMenuOnClickListener()); + menuGrid.setSelected(true); + menuGrid.setSelection(0); + } + + private OnItemClickListener getHomeMenuOnClickListener() { + return new OnItemClickListener() { + + public void onItemClick(AdapterView listView, View v, int position, long ID) { + HomeItem item = (HomeItem) listView.getAdapter().getItem(position); + final Host host = HostFactory.host; + Intent intent = null; + switch (item.ID) { + case HOME_ACTION_REMOTE: + final int mode = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE).getInt + (RemoteController.LAST_REMOTE_PREFNAME, -1); + if (mode == RemoteController.LAST_REMOTE_GESTURE) { + intent = new Intent(v.getContext(), GestureRemoteActivity.class); + } else { + intent = new Intent(v.getContext(), RemoteActivity.class); + } + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + break; + case HOME_ACTION_MUSIC: + intent = new Intent(v.getContext(), MusicLibraryActivity.class); + break; + case HOME_ACTION_VIDEOS: + intent = new Intent(v.getContext(), MovieLibraryActivity.class); + break; + case HOME_ACTION_TVSHOWS: + intent = new Intent(v.getContext(), TvShowLibraryActivity.class); + break; + case HOME_ACTION_PICTURES: + intent = new Intent(v.getContext(), ListActivity.class); + intent.putExtra(ListController.EXTRA_LIST_CONTROLLER, new FileListController()); + intent.putExtra(ListController.EXTRA_SHARE_TYPE, MediaType.PICTURES); + intent.putExtra(ListController.EXTRA_PATH, ""); + break; + case HOME_ACTION_NOWPLAYING: + intent = new Intent(v.getContext(), NowPlayingActivity.class); + break; + case HOME_ACTION_RECONNECT: + ((Button) mActivity.findViewById(R.id.home_version_button)).setText("Reconnecting..."); + ClientFactory.resetClient(host); + mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); + break; + case HOME_ACTION_WOL: + WakeOnLan wol = new WakeOnLan(); + if (wol.sendMagicPacket(host.mac_addr, host.wol_port)) { // If succeeded in sending the magic + // packet, begin the countdown + if (mWolCounter != null) mWolCounter.cancel(); + mWolCounter = new WolCounter(host.wol_wait * 1000, 1000); + mWolCounter.start(); + } + break; + case HOME_ACTION_POWERDOWN: + PowerDown powerdown = new PowerDown(); + powerdown.ShowDialog(mActivity); + break; + } + if (intent != null) { + mActivity.startActivity(intent); + } + } + }; + } + + public void update(Observable observable, Object data) { + if (data instanceof BroadcastListener.Event) { + BroadcastListener.Event event = (BroadcastListener.Event) data; + switch (event.id) { + case BroadcastListener.EVENT_ON_PROGRESS_CHANGED: + Log.i("broadcast", "EVENT_ON_PROGRESS_CHANGED: " + event.getInt(0)); + break; + default: + Log.i("broadcast", "EVENT: " + event.id + ", int = " + event.getInt(0)); + break; + } + } + } + + /** + * Handles messages coming in to mHandlerOut + * + * @param msg + * @param progressDialog + * @param progressThread + */ + public void onHandleMessage(Message msg, ProgressDialog progressDialog, final ProgressThread progressThread) { + + int total = msg.getData().getInt(ProgressThread.DATA_TOTAL); + int position = msg.getData().getInt(ProgressThread.DATA_POSITION); + int type = msg.getData().getInt(ProgressThread.DATA_TYPE); + if (msg.what != ProgressThread.MSG_QUIT) { + if (total > 0) { + progressDialog.setProgress(position); + if (position < total) { + final ICoverArt cover = (ICoverArt) msg.getData().getSerializable(ProgressThread.DATA_COVER); + if (DEBUG) + Log.i(TAG, "New download message received for position " + position + ": " + cover.getName()); + if (AbstractManager.cacheCover(cover, (INotifiableManager) mInfoManager, + mActivity.getApplicationContext())) { + mNumCoversDownloaded++; + } + if (DEBUG) Log.i(TAG, "Cover Downloaded, sending new (empty) message to progress thread."); + final Handler handlerIn = progressThread.getHandlerIn(); + if (progressThread.isAlive() && handlerIn != null) { + handlerIn.sendEmptyMessage(ProgressThread.MSG_NEXT); + } else { + if (DEBUG) Log.i(TAG, "Thread dead, exiting."); + return; + } + } else { + mActivity.dismissDialog(type); + progressThread.getHandlerIn().sendEmptyMessage(ProgressThread.MSG_QUIT); + Toast toast = Toast.makeText(mActivity, mNumCoversDownloaded + " posters downloaded.", + Toast.LENGTH_SHORT); + toast.show(); + } + } else { + mActivity.dismissDialog(type); + Toast toast = Toast.makeText(mActivity, "No posters downloaded, libary empty?", Toast.LENGTH_LONG); + toast.show(); + } + } else { + mActivity.dismissDialog(type); + progressThread.getHandlerIn().sendEmptyMessage(ProgressThread.MSG_QUIT); + Toast toast = Toast.makeText(mActivity, "Aborted, " + mNumCoversDownloaded + " posters downloaded.", + Toast.LENGTH_SHORT); + toast.show(); + } + } + + public void onActivityPause() { + mInfoManager.setController(null); + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + mInfoManager.setController(this); + mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals("setting_show_home_music") || key.equals("setting_show_home_movies") || key.equals + ("setting_show_home_tv") || key.equals("setting_show_home_pictures") || key.equals + ("setting_show_home_powerdown")) { + setupMenuItems(mMenuGrid); + } + } + + private class HomeAdapter extends ArrayAdapter { + private Activity mActivity; + + HomeAdapter(Activity activity, ArrayList items) { + super(activity, R.layout.home_item, items); + mActivity = activity; + } + + public View getView(int position, View convertView, ViewGroup parent) { + View row; + if (convertView == null) { + LayoutInflater inflater = mActivity.getLayoutInflater(); + row = inflater.inflate(R.layout.home_item, null); + } else { + row = convertView; + } + HomeItem item = this.getItem(position); + TextView title = (TextView) row.findViewById(R.id.TitleTextView); + TextView subtitle = (TextView) row.findViewById(R.id.SubtitleTextView); + ImageView icon = (ImageView) row.findViewById(R.id.IconImageView); + title.setText(item.title); + subtitle.setText(item.subtitle); + icon.setImageResource(item.icon); + return row; + } + } + + private class HomeItem { + public final int ID, icon; + public final String title, subtitle; + + public HomeItem(int ID, int icon, String title, String subtitle) { + this.ID = ID; + this.icon = icon; + this.title = title; + this.subtitle = subtitle; + } + } + + public class WolCounter extends CountDownTimer { + private Button textCount; + + public WolCounter(long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + + textCount = ((Button) mActivity.findViewById(R.id.home_version_button)); + } + + @Override + public void onFinish() { + ((Button) mActivity.findViewById(R.id.home_version_button)).setText("Attempting to reconnect..."); + mInfoManager.getSystemInfo(mUpdateVersionHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); + mWolCounter = null; + } + + @Override + public void onTick(long millisUntilFinished) { + textCount.setText("Waiting for " + millisUntilFinished / 1000 + " more seconds..."); + } + } + + public class ProgressThread extends Thread { + + public final static int MSG_NEXT = 0; + public final static int MSG_QUIT = 1; + public final static String DATA_TYPE = "type"; + public final static String DATA_TOTAL = "total"; + public final static String DATA_POSITION = "pos"; + public final static String DATA_COVER = "cover"; + private final int mType; + private final ProgressDialog mProgressDialog; + private Handler mHandlerOut; + private Handler mHandlerIn; + private int mTotal; + private int mPosition; + + public ProgressThread(Handler h, int type, ProgressDialog progressDialog) { + super("Cover download progress Thread"); + if (DEBUG) Log.i(TAG, "[ProgressThread] Creating."); + mHandlerOut = h; + mType = type; + mProgressDialog = progressDialog; + } + + public void cancel() { + if (DEBUG) Log.i(TAG, "[ProgressThread] Cancelling."); + Message msgStart = mHandlerIn.obtainMessage(); + Bundle b = new Bundle(); + b.putInt(DATA_TYPE, mType); + msgStart.what = MSG_QUIT; + msgStart.setData(b); + mHandlerOut.sendMessage(msgStart); + } + + public Handler getHandlerIn() { + return mHandlerIn; + } + + public ArrayList getCovers() { + switch (mType) { + case HomeActivity.MENU_COVER_DOWNLOAD_MOVIES: + final IVideoManager vm = ManagerFactory.getVideoManager(HomeController.this); + final ArrayList movies = vm.getMovies(mActivity.getApplicationContext()); + return new ArrayList(movies); + case HomeActivity.MENU_COVER_DOWNLOAD_MUSIC: + final IMusicManager mm = ManagerFactory.getMusicManager(HomeController.this); + final ArrayList albums = mm.getAlbums(mActivity.getApplicationContext()); + return new ArrayList(albums); + case HomeActivity.MENU_COVER_DOWNLOAD_ACTORS: + final IVideoManager vm2 = ManagerFactory.getVideoManager(HomeController.this); + final ArrayList actors = vm2.getActors(mActivity.getApplicationContext()); + return new ArrayList(actors); + case HomeActivity.MENU_COVER_DOWNLOAD_TVSHOWS: + final ITvShowManager tsm = ManagerFactory.getTvManager(HomeController.this); + final ArrayList shows = tsm.getTvShows(mActivity.getApplicationContext()); + return new ArrayList(shows); + case HomeActivity.MENU_COVER_DOWNLOAD_TVSEASONS: + final ITvShowManager tsm2 = ManagerFactory.getTvManager(HomeController.this); + final ArrayList seasons = tsm2.getAllSeasons(mActivity.getApplicationContext()); + return new ArrayList(seasons); + case HomeActivity.MENU_COVER_DOWNLOAD_TVEPISODES: + final ITvShowManager tsm3 = ManagerFactory.getTvManager(HomeController.this); + final ArrayList episodes = tsm3.getAllEpisodes(mActivity.getApplicationContext()); + return new ArrayList(episodes); + default: + return null; + } + } + + public void run() { + if (DEBUG) Log.i(TAG, "[ProgressThread] Starting progress thread."); + final ArrayList covers = getCovers(); + mTotal = covers.size(); + mPosition = 0; + mProgressDialog.setMax(covers.size()); + boolean started = false; + final WifiLock lock; + if (HostFactory.host != null && HostFactory.host.wifi_only) { + lock = WifiHelper.getInstance(mActivity).getNewWifiLock("BatchDownloader"); + lock.acquire(); + } else + lock = null; + final PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); + final PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, TAG); + wl.acquire(); + + Looper.prepare(); + mHandlerIn = new Handler() { + public void handleMessage(Message msgIn) { + switch (msgIn.what) { + case MSG_NEXT: + if (DEBUG) Log.i(TAG, "[ProgressThread] New message received, posting back new cover."); + Message msgOut = mHandlerOut.obtainMessage(); + Bundle b = new Bundle(); + b.putInt(DATA_TOTAL, mTotal); + b.putInt(DATA_POSITION, mPosition); + b.putInt(DATA_TYPE, mType); + if (mPosition < mTotal) { + b.putSerializable(DATA_COVER, covers.get(mPosition)); + } + msgOut.setData(b); + mHandlerOut.sendMessage(msgOut); + mPosition++; + break; + case MSG_QUIT: + if (DEBUG) Log.i(TAG, "[ProgressThread] Exiting."); + Looper.myLooper().quit(); + break; + } + } + }; + if (!started) { + mNumCoversDownloaded = 0; + started = true; + Message msgStart = mHandlerOut.obtainMessage(); + Bundle b = new Bundle(); + b.putInt(DATA_TYPE, mType); + msgStart.what = MSG_NEXT; + msgStart.setData(b); + mHandlerIn.sendMessage(msgStart); + if (DEBUG) Log.i(TAG, "[ProgressThread] Not started, kicking on...."); + } + Looper.loop(); + + if (lock != null) { + lock.release(); + } + wl.release(); + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/HostPreference.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/HostPreference.java similarity index 78% rename from src/org/xbmc/android/remote/presentation/controller/HostPreference.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/HostPreference.java index 534538a6..31d4d44a 100644 --- a/src/org/xbmc/android/remote/presentation/controller/HostPreference.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/HostPreference.java @@ -1,246 +1,246 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import org.xbmc.android.remote.R; -import org.xbmc.android.util.HostFactory; -import org.xbmc.android.util.MacAddressResolver; -import org.xbmc.api.object.Host; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Handler; -import android.preference.DialogPreference; -import android.preference.PreferenceActivity; -import android.preference.PreferenceManager; -import android.util.AttributeSet; -import android.view.View; -import android.view.ViewGroup; -import android.view.View.OnClickListener; -import android.view.View.OnFocusChangeListener; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.Toast; - -/** - * One of those contains name, host, port, user and pass of an XBMC instance. - * - * @author Team XBMC - */ -public class HostPreference extends DialogPreference { - - private EditText mNameView, mHostView, mPortView, mUserView, mPassView, - mEsPortView, mTimeoutView, mAccPointView, mMacAddrView, mWolWaitView, mWolPortView; - - private CheckBox mWifiOnlyView; - - private Host mHost; - private Context mContext; - - public static final String ID_PREFIX = "settings_host_"; - - public HostPreference(Context context) { - this(context, null); - } - - public HostPreference(Context context, AttributeSet attrs) { - super(context, attrs); - - mContext = context; - - setDialogLayoutResource(R.layout.preference_host); - setDialogTitle("Add new host"); - setDialogIcon(R.drawable.bubble_add); - } - - public void create(PreferenceManager preferenceManager) { - onAttachedToHierarchy(preferenceManager); - showDialog(null); - } - - public void setHost(Host host) { - mHost = host; - setTitle(host.name); - setSummary(host.getSummary()); - setDialogTitle(host.name); - setDialogIcon(null); - } - - public Host getHost() { - return mHost; - } - - @Override - protected View onCreateView(final ViewGroup parent) { - final ViewGroup view = (ViewGroup)super.onCreateView(parent); - if (mHost != null) { - ImageView btn = new ImageView(getContext()); - btn.setImageResource(R.drawable.bubble_del_up); - btn.setClickable(true); - btn.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); - builder.setMessage("Are you sure you want to delete the XBMC host \"" + mHost.name + "\"?"); - builder.setPositiveButton("Yes!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - HostFactory.deleteHost(getContext(), mHost); - ((PreferenceActivity)view.getContext()).getPreferenceScreen().removePreference(HostPreference.this); - } - }); - builder.setNegativeButton("Nah.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - builder.create().show(); - } - }); - view.addView(btn); - } - return view; - } - - @Override - protected View onCreateDialogView() { - final ViewGroup parent = (ViewGroup)super.onCreateDialogView(); - mNameView = (EditText)parent.findViewById(R.id.pref_name); - mHostView = (EditText)parent.findViewById(R.id.pref_host); - mHostView.setOnFocusChangeListener(new OnFocusChangeListener() { - Handler handler = new Handler(){ - public void handleMessage(android.os.Message message){ - if(message.getData().containsKey(MacAddressResolver.MESSAGE_MAC_ADDRESS)){ - String mac = message.getData().getString(MacAddressResolver.MESSAGE_MAC_ADDRESS); - if(!mac.equals("")){ - mMacAddrView.setText(mac); - Toast toast = Toast.makeText(getContext(), "Updated MAC for host: " + mHostView.getText().toString() + "\nto: " + mac, Toast.LENGTH_SHORT); - toast.show(); - } - - } - } - }; - public void onFocusChange(View v, boolean hasFocus) { - if(hasFocus) - return; - if(mMacAddrView.getText().toString().equals("")) - handler.post(new MacAddressResolver(mHostView.getText().toString(), handler)); - } - }); - mPortView = (EditText)parent.findViewById(R.id.pref_port); - mUserView = (EditText)parent.findViewById(R.id.pref_user); - mPassView = (EditText)parent.findViewById(R.id.pref_pass); - mEsPortView = (EditText)parent.findViewById(R.id.pref_eventserver_port); - mTimeoutView = (EditText)parent.findViewById(R.id.pref_timeout); - mMacAddrView = (EditText)parent.findViewById(R.id.pref_mac_addr); - mAccPointView = (EditText)parent.findViewById(R.id.pref_access_point); - mWifiOnlyView = (CheckBox)parent.findViewById(R.id.pref_wifi_only); - mWolPortView = (EditText)parent.findViewById(R.id.pref_wol_port); - mWolWaitView = (EditText)parent.findViewById(R.id.pref_wol_wait); - return parent; - } - - @Override - protected void onBindDialogView(View view) { - super.onBindDialogView(view); - if (mHost != null) { - mNameView.setText(mHost.name); - mHostView.setText(mHost.addr); - mPortView.setText(String.valueOf(mHost.port)); - mUserView.setText(mHost.user); - mPassView.setText(mHost.pass); - - mEsPortView.setText(String.valueOf(mHost.esPort)); - mTimeoutView.setText(String.valueOf(mHost.timeout)); - mMacAddrView.setText(mHost.mac_addr); - mAccPointView.setText(mHost.access_point); - mWifiOnlyView.setChecked(mHost.wifi_only); - mWolPortView.setText(String.valueOf(mHost.wol_port)); - mWolWaitView.setText(String.valueOf(mHost.wol_wait)); - } else { - //set defaults: - mPortView.setText("" + Host.DEFAULT_HTTP_PORT); - mEsPortView.setText("" + Host.DEFAULT_EVENTSERVER_PORT); - mTimeoutView.setText("" + Host.DEFAULT_TIMEOUT); - mWolPortView.setText("" + Host.DEFAULT_WOL_PORT); - mWolWaitView.setText("" + Host.DEFAULT_WOL_WAIT); - } - } - - @Override - protected void onDialogClosed(boolean positiveResult) { - super.onDialogClosed(positiveResult); - if (positiveResult) { - final Host host = new Host(); - host.name = mNameView.getText().toString(); - host.addr = mHostView.getText().toString().trim(); - try { - host.port = Integer.parseInt(mPortView.getText().toString()); - } catch (NumberFormatException e) { - host.port = Host.DEFAULT_HTTP_PORT; - } - host.user = mUserView.getText().toString(); - host.pass = mPassView.getText().toString(); - - try { - host.esPort = Integer.parseInt(mEsPortView.getText().toString()); - } catch (NumberFormatException e) { - host.esPort = Host.DEFAULT_EVENTSERVER_PORT; - } - try { - host.timeout = Integer.parseInt(mTimeoutView.getText().toString()); - } catch (NumberFormatException e) { - host.timeout = Host.DEFAULT_TIMEOUT; - } - host.access_point = mAccPointView.getText().toString(); - host.mac_addr = mMacAddrView.getText().toString(); - host.wifi_only = mWifiOnlyView.isChecked(); - try { - host.wol_port = Integer.parseInt(mWolPortView.getText().toString()); - }catch (NumberFormatException e) { - host.wol_port = Host.DEFAULT_WOL_PORT; - } - try { - host.wol_wait = Integer.parseInt(mWolWaitView.getText().toString()); - }catch (NumberFormatException e) { - host.wol_wait = Host.DEFAULT_WOL_WAIT; - } - - - if (mHost == null) { - HostFactory.addHost(getContext(), host); - } else { - host.id = mHost.id; - HostFactory.updateHost(getContext(), host); - } - if (callChangeListener(host)) { - notifyChanged(); - } - setHost(host); - - if (HostFactory.host == null) { - HostFactory.saveHost(mContext, host); - } - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Handler; +import android.preference.DialogPreference; +import android.preference.PreferenceActivity; +import android.preference.PreferenceManager; +import android.util.AttributeSet; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnFocusChangeListener; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; + +import org.xbmc.android.remote.R; +import org.xbmc.android.util.HostFactory; +import org.xbmc.android.util.MacAddressResolver; +import org.xbmc.api.object.Host; + +/** + * One of those contains name, host, port, user and pass of an XBMC instance. + * + * @author Team XBMC + */ +public class HostPreference extends DialogPreference { + + public static final String ID_PREFIX = "settings_host_"; + private EditText mNameView, mHostView, mPortView, mUserView, mPassView, + mEsPortView, mTimeoutView, mAccPointView, mMacAddrView, mWolWaitView, mWolPortView; + private CheckBox mWifiOnlyView; + private Host mHost; + private Context mContext; + + public HostPreference(Context context) { + this(context, null); + } + + public HostPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + mContext = context; + + setDialogLayoutResource(R.layout.preference_host); + setDialogTitle("Add new host"); + setDialogIcon(R.drawable.bubble_add); + } + + public void create(PreferenceManager preferenceManager) { + onAttachedToHierarchy(preferenceManager); + showDialog(null); + } + + public Host getHost() { + return mHost; + } + + public void setHost(Host host) { + mHost = host; + setTitle(host.name); + setSummary(host.getSummary()); + setDialogTitle(host.name); + setDialogIcon(null); + } + + @Override + protected View onCreateView(final ViewGroup parent) { + final ViewGroup view = (ViewGroup) super.onCreateView(parent); + if (mHost != null) { + ImageView btn = new ImageView(getContext()); + btn.setImageResource(R.drawable.bubble_del_up); + btn.setClickable(true); + btn.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setMessage("Are you sure you want to delete the XBMC host \"" + mHost.name + "\"?"); + builder.setPositiveButton("Yes!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + HostFactory.deleteHost(getContext(), mHost); + ((PreferenceActivity) view.getContext()).getPreferenceScreen().removePreference + (HostPreference.this); + } + }); + builder.setNegativeButton("Nah.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + builder.create().show(); + } + }); + view.addView(btn); + } + return view; + } + + @Override + protected View onCreateDialogView() { + final ViewGroup parent = (ViewGroup) super.onCreateDialogView(); + mNameView = (EditText) parent.findViewById(R.id.pref_name); + mHostView = (EditText) parent.findViewById(R.id.pref_host); + mHostView.setOnFocusChangeListener(new OnFocusChangeListener() { + Handler handler = new Handler() { + public void handleMessage(android.os.Message message) { + if (message.getData().containsKey(MacAddressResolver.MESSAGE_MAC_ADDRESS)) { + String mac = message.getData().getString(MacAddressResolver.MESSAGE_MAC_ADDRESS); + if (!mac.equals("")) { + mMacAddrView.setText(mac); + Toast toast = Toast.makeText(getContext(), "Updated MAC for host: " + mHostView.getText() + .toString() + "\nto: " + mac, Toast.LENGTH_SHORT); + toast.show(); + } + + } + } + }; + + public void onFocusChange(View v, boolean hasFocus) { + if (hasFocus) + return; + if (mMacAddrView.getText().toString().equals("")) + handler.post(new MacAddressResolver(mHostView.getText().toString(), handler)); + } + }); + mPortView = (EditText) parent.findViewById(R.id.pref_port); + mUserView = (EditText) parent.findViewById(R.id.pref_user); + mPassView = (EditText) parent.findViewById(R.id.pref_pass); + mEsPortView = (EditText) parent.findViewById(R.id.pref_eventserver_port); + mTimeoutView = (EditText) parent.findViewById(R.id.pref_timeout); + mMacAddrView = (EditText) parent.findViewById(R.id.pref_mac_addr); + mAccPointView = (EditText) parent.findViewById(R.id.pref_access_point); + mWifiOnlyView = (CheckBox) parent.findViewById(R.id.pref_wifi_only); + mWolPortView = (EditText) parent.findViewById(R.id.pref_wol_port); + mWolWaitView = (EditText) parent.findViewById(R.id.pref_wol_wait); + return parent; + } + + @Override + protected void onBindDialogView(View view) { + super.onBindDialogView(view); + if (mHost != null) { + mNameView.setText(mHost.name); + mHostView.setText(mHost.addr); + mPortView.setText(String.valueOf(mHost.port)); + mUserView.setText(mHost.user); + mPassView.setText(mHost.pass); + + mEsPortView.setText(String.valueOf(mHost.esPort)); + mTimeoutView.setText(String.valueOf(mHost.timeout)); + mMacAddrView.setText(mHost.mac_addr); + mAccPointView.setText(mHost.access_point); + mWifiOnlyView.setChecked(mHost.wifi_only); + mWolPortView.setText(String.valueOf(mHost.wol_port)); + mWolWaitView.setText(String.valueOf(mHost.wol_wait)); + } else { + //set defaults: + mPortView.setText("" + Host.DEFAULT_HTTP_PORT); + mEsPortView.setText("" + Host.DEFAULT_EVENTSERVER_PORT); + mTimeoutView.setText("" + Host.DEFAULT_TIMEOUT); + mWolPortView.setText("" + Host.DEFAULT_WOL_PORT); + mWolWaitView.setText("" + Host.DEFAULT_WOL_WAIT); + } + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + if (positiveResult) { + final Host host = new Host(); + host.name = mNameView.getText().toString(); + host.addr = mHostView.getText().toString().trim(); + try { + host.port = Integer.parseInt(mPortView.getText().toString()); + } catch (NumberFormatException e) { + host.port = Host.DEFAULT_HTTP_PORT; + } + host.user = mUserView.getText().toString(); + host.pass = mPassView.getText().toString(); + + try { + host.esPort = Integer.parseInt(mEsPortView.getText().toString()); + } catch (NumberFormatException e) { + host.esPort = Host.DEFAULT_EVENTSERVER_PORT; + } + try { + host.timeout = Integer.parseInt(mTimeoutView.getText().toString()); + } catch (NumberFormatException e) { + host.timeout = Host.DEFAULT_TIMEOUT; + } + host.access_point = mAccPointView.getText().toString(); + host.mac_addr = mMacAddrView.getText().toString(); + host.wifi_only = mWifiOnlyView.isChecked(); + try { + host.wol_port = Integer.parseInt(mWolPortView.getText().toString()); + } catch (NumberFormatException e) { + host.wol_port = Host.DEFAULT_WOL_PORT; + } + try { + host.wol_wait = Integer.parseInt(mWolWaitView.getText().toString()); + } catch (NumberFormatException e) { + host.wol_wait = Host.DEFAULT_WOL_WAIT; + } + + + if (mHost == null) { + HostFactory.addHost(getContext(), host); + } else { + host.id = mHost.id; + HostFactory.updateHost(getContext(), host); + } + if (callChangeListener(host)) { + notifyChanged(); + } + setHost(host); + + if (HostFactory.host == null) { + HostFactory.saveHost(mContext, host); + } + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/IController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/IController.java similarity index 97% rename from src/org/xbmc/android/remote/presentation/controller/IController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/IController.java index 884e7ba4..163aa9f3 100644 --- a/src/org/xbmc/android/remote/presentation/controller/IController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/IController.java @@ -1,29 +1,30 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import android.app.Activity; - -public interface IController { - public void onActivityPause(); - public void onActivityResume(Activity activity); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; + +public interface IController { + public void onActivityPause(); + + public void onActivityResume(Activity activity); } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/ListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ListController.java similarity index 88% rename from src/org/xbmc/android/remote/presentation/controller/ListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/ListController.java index 42d67cd1..8cd33262 100644 --- a/src/org/xbmc/android/remote/presentation/controller/ListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ListController.java @@ -1,252 +1,257 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import java.io.Serializable; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.widget.FastScrollView; -import org.xbmc.android.widget.IdleListDetector; -import org.xbmc.android.widget.IdleListener; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.ThumbSize; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.os.Handler; -import android.view.ContextMenu; -import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AbsListView; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListAdapter; -import android.widget.TextView; -import android.widget.Toast; - -public abstract class ListController extends AbstractController implements Serializable, INotifiableController { - - public static final String EXTRA_LIST_CONTROLLER = "ListController"; - public static final String EXTRA_MOVIE = "movie"; - public static final String EXTRA_TVSHOW = "tvshow"; - public static final String EXTRA_SEASON = "season"; - public static final String EXTRA_EPISODE = "episode"; - public static final String EXTRA_ALBUM = "album"; - public static final String EXTRA_ARTIST = "artist"; - public static final String EXTRA_ACTOR = "actor"; - public static final String EXTRA_GENRE = "genre"; - public static final String EXTRA_SHARE_TYPE = "shareType"; - public static final String EXTRA_PATH = "path"; - public static final String EXTRA_DISPLAY_PATH = "display_path"; - - private static final int MENU_SHOWHIDE_WATCHED = 51; - private static final String PREF_HIDE_WATCHED = "HideWatched"; - - protected AbsListView mList; - - private TextView mTitleView; - private ViewGroup mMessageGroup; - private TextView mMessageText; - private boolean hideWatched; - private boolean isCreated = false; - - protected static Bitmap mFallbackBitmap; - protected IdleListDetector mPostScrollLoader; - - public void onCreate(Activity activity, Handler handler, AbsListView list) { - super.onCreate(activity, handler); - mList = list; - mActivity = activity; - SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); - hideWatched = sp.getBoolean(PREF_HIDE_WATCHED, false); - isCreated = true; -// list.setOnScrollListener(new ScrollManager(ThumbSize.SMALL)); - } - - /** - * Default listener is small - * @return - */ - protected IdleListener setupIdleListener() { - return setupIdleListener(ThumbSize.SMALL); - } - - /** - * Hook up the mechanism to load images only when the list "slows" down. - */ - protected IdleListener setupIdleListener(int thumbSize) { - IdleListener idleListener = new IdleListener(mList, thumbSize); - mPostScrollLoader = new IdleListDetector(idleListener); - FastScrollView fastScroller = (FastScrollView)mList.getParent(); - fastScroller.setOnIdleListDetector(mPostScrollLoader); - return idleListener; - } - - public abstract void onContextItemSelected(MenuItem item); - public abstract void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); - - public void onCreateOptionsMenu(Menu menu) { } - - protected void createShowHideWatchedToggle(Menu menu) { - configureShowHideWatchedToggleOption(menu.add(0, MENU_SHOWHIDE_WATCHED, 0, ""), hideWatched); - } - - public void onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == MENU_SHOWHIDE_WATCHED) { - SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); - hideWatched = !(sp.getBoolean(PREF_HIDE_WATCHED, false)); - sp.edit().putBoolean(PREF_HIDE_WATCHED, hideWatched).commit(); - configureShowHideWatchedToggleOption(item, hideWatched); - refreshList(); - } - } - - private MenuItem configureShowHideWatchedToggleOption(MenuItem item, boolean hideWatched) { - if (hideWatched) { - return item.setTitle("Show Watched").setIcon(R.drawable.menu_show_watched); - } else { - return item.setTitle("Hide Watched").setIcon(R.drawable.menu_hide_watched); - } - } - - protected void refreshList() { } - - public void findTitleView(View parent) { - mTitleView = (TextView)parent.findViewById(R.id.titlebar_text); - } - - public void findMessageView(View parent) { - mMessageGroup = (ViewGroup)parent.findViewById(R.id.listmessage); - mMessageText = (TextView)parent.findViewById(R.id.listmessage_text); - mMessageGroup.setVisibility(View.GONE); - } - - protected void setTitle(final String title) { - if (mTitleView != null) { - mHandler.post(new Runnable() { - public void run() { - mTitleView.setText(title); - } - }); - } - } - - protected boolean isCreated() { - return isCreated; - } - - protected void setNoDataMessage(final String message, final int imageResource) { - if (mMessageGroup != null) { - mHandler.post(new Runnable() { - public void run() { - mMessageText.setText(message); - mMessageText.setCompoundDrawablesWithIntrinsicBounds(imageResource, 0, 0, 0); - ((AdapterView) mList).setAdapter(null); - mMessageGroup.setVisibility(View.VISIBLE); - } - }); - } - } - - protected void hideMessage() { - if (mMessageGroup != null) { - mMessageGroup.setVisibility(View.GONE); - } - } - - protected void showOnLoading() { - mHandler.post(new Runnable() { - public void run() { - ((AdapterView) mList).setAdapter(new LoadingAdapter(mActivity)); - mList.setVisibility(View.VISIBLE); - } - }); - } - - protected boolean isLoading() { - return mList.getAdapter() instanceof LoadingAdapter; - } - - @Override - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (isCreated()) { - SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); - boolean hideWatched = sp.getBoolean(PREF_HIDE_WATCHED, false); - if (hideWatched != this.hideWatched) { - this.hideWatched = hideWatched; - refreshList(); - } - } - } - - protected class QueryResponse extends DataResponse { - private final String mSuccessMessage; - private final String mErrorMessage; - private final boolean mGotoNowPlaying; - public QueryResponse(Activity activity, String successMessage, String errorMessage) { - super(); - mSuccessMessage = successMessage; - mErrorMessage = errorMessage; - mGotoNowPlaying = false; - } - public QueryResponse(Activity activity, String successMessage, String errorMessage, boolean gotoNowPlaying) { - super(); - mSuccessMessage = successMessage; - mErrorMessage = errorMessage; - mGotoNowPlaying = gotoNowPlaying; - } - public void run() { - Toast.makeText(mActivity, value ? mSuccessMessage : mErrorMessage, Toast.LENGTH_LONG).show(); - if (value && mGotoNowPlaying) { - mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); - } - } - } - - private static final long serialVersionUID = 2903701184005613570L; - - private class LoadingAdapter extends ArrayAdapter { - View row; - public LoadingAdapter(Activity act) { - super(act, R.layout.loadinglistentry); - add("dummy"); - row = LayoutInflater.from(mActivity).inflate(R.layout.loadinglistentry, null); - ((TextView)row.findViewById(R.id.loading_text)).setText("Loading..."); - } - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // TODO Auto-generated method stub - - return row; - } - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.os.Handler; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.TextView; +import android.widget.Toast; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.widget.FastScrollView; +import org.xbmc.android.widget.IdleListDetector; +import org.xbmc.android.widget.IdleListener; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.ThumbSize; + +import java.io.Serializable; + +public abstract class ListController extends AbstractController implements Serializable, INotifiableController { + + public static final String EXTRA_LIST_CONTROLLER = "ListController"; + public static final String EXTRA_MOVIE = "movie"; + public static final String EXTRA_TVSHOW = "tvshow"; + public static final String EXTRA_SEASON = "season"; + public static final String EXTRA_EPISODE = "episode"; + public static final String EXTRA_ALBUM = "album"; + public static final String EXTRA_ARTIST = "artist"; + public static final String EXTRA_ACTOR = "actor"; + public static final String EXTRA_GENRE = "genre"; + public static final String EXTRA_SHARE_TYPE = "shareType"; + public static final String EXTRA_PATH = "path"; + public static final String EXTRA_DISPLAY_PATH = "display_path"; + + private static final int MENU_SHOWHIDE_WATCHED = 51; + private static final String PREF_HIDE_WATCHED = "HideWatched"; + private static final long serialVersionUID = 2903701184005613570L; + protected static Bitmap mFallbackBitmap; + protected AbsListView mList; + protected IdleListDetector mPostScrollLoader; + private TextView mTitleView; + private ViewGroup mMessageGroup; + private TextView mMessageText; + private boolean hideWatched; + private boolean isCreated = false; + + public void onCreate(Activity activity, Handler handler, AbsListView list) { + super.onCreate(activity, handler); + mList = list; + mActivity = activity; + SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); + hideWatched = sp.getBoolean(PREF_HIDE_WATCHED, false); + isCreated = true; +// list.setOnScrollListener(new ScrollManager(ThumbSize.SMALL)); + } + + /** + * Default listener is small + * + * @return + */ + protected IdleListener setupIdleListener() { + return setupIdleListener(ThumbSize.SMALL); + } + + /** + * Hook up the mechanism to load images only when the list "slows" down. + */ + protected IdleListener setupIdleListener(int thumbSize) { + IdleListener idleListener = new IdleListener(mList, thumbSize); + mPostScrollLoader = new IdleListDetector(idleListener); + FastScrollView fastScroller = (FastScrollView) mList.getParent(); + fastScroller.setOnIdleListDetector(mPostScrollLoader); + return idleListener; + } + + public abstract void onContextItemSelected(MenuItem item); + + public abstract void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); + + public void onCreateOptionsMenu(Menu menu) { + } + + protected void createShowHideWatchedToggle(Menu menu) { + configureShowHideWatchedToggleOption(menu.add(0, MENU_SHOWHIDE_WATCHED, 0, ""), hideWatched); + } + + public void onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == MENU_SHOWHIDE_WATCHED) { + SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); + hideWatched = !(sp.getBoolean(PREF_HIDE_WATCHED, false)); + sp.edit().putBoolean(PREF_HIDE_WATCHED, hideWatched).commit(); + configureShowHideWatchedToggleOption(item, hideWatched); + refreshList(); + } + } + + private MenuItem configureShowHideWatchedToggleOption(MenuItem item, boolean hideWatched) { + if (hideWatched) { + return item.setTitle("Show Watched").setIcon(R.drawable.menu_show_watched); + } else { + return item.setTitle("Hide Watched").setIcon(R.drawable.menu_hide_watched); + } + } + + protected void refreshList() { + } + + public void findTitleView(View parent) { + mTitleView = (TextView) parent.findViewById(R.id.titlebar_text); + } + + public void findMessageView(View parent) { + mMessageGroup = (ViewGroup) parent.findViewById(R.id.listmessage); + mMessageText = (TextView) parent.findViewById(R.id.listmessage_text); + mMessageGroup.setVisibility(View.GONE); + } + + protected void setTitle(final String title) { + if (mTitleView != null) { + mHandler.post(new Runnable() { + public void run() { + mTitleView.setText(title); + } + }); + } + } + + protected boolean isCreated() { + return isCreated; + } + + protected void setNoDataMessage(final String message, final int imageResource) { + if (mMessageGroup != null) { + mHandler.post(new Runnable() { + public void run() { + mMessageText.setText(message); + mMessageText.setCompoundDrawablesWithIntrinsicBounds(imageResource, 0, 0, 0); + ((AdapterView) mList).setAdapter(null); + mMessageGroup.setVisibility(View.VISIBLE); + } + }); + } + } + + protected void hideMessage() { + if (mMessageGroup != null) { + mMessageGroup.setVisibility(View.GONE); + } + } + + protected void showOnLoading() { + mHandler.post(new Runnable() { + public void run() { + ((AdapterView) mList).setAdapter(new LoadingAdapter(mActivity)); + mList.setVisibility(View.VISIBLE); + } + }); + } + + protected boolean isLoading() { + return mList.getAdapter() instanceof LoadingAdapter; + } + + @Override + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (isCreated()) { + SharedPreferences sp = mActivity.getSharedPreferences("global", Context.MODE_PRIVATE); + boolean hideWatched = sp.getBoolean(PREF_HIDE_WATCHED, false); + if (hideWatched != this.hideWatched) { + this.hideWatched = hideWatched; + refreshList(); + } + } + } + + protected class QueryResponse extends DataResponse { + private final String mSuccessMessage; + private final String mErrorMessage; + private final boolean mGotoNowPlaying; + + public QueryResponse(Activity activity, String successMessage, String errorMessage) { + super(); + mSuccessMessage = successMessage; + mErrorMessage = errorMessage; + mGotoNowPlaying = false; + } + + public QueryResponse(Activity activity, String successMessage, String errorMessage, boolean gotoNowPlaying) { + super(); + mSuccessMessage = successMessage; + mErrorMessage = errorMessage; + mGotoNowPlaying = gotoNowPlaying; + } + + public void run() { + Toast.makeText(mActivity, value ? mSuccessMessage : mErrorMessage, Toast.LENGTH_LONG).show(); + if (value && mGotoNowPlaying) { + mActivity.startActivity(new Intent(mActivity, NowPlayingActivity.class)); + } + } + } + + private class LoadingAdapter extends ArrayAdapter { + View row; + + public LoadingAdapter(Activity act) { + super(act, R.layout.loadinglistentry); + add("dummy"); + row = LayoutInflater.from(mActivity).inflate(R.layout.loadinglistentry, null); + ((TextView) row.findViewById(R.id.loading_text)).setText("Loading..."); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + // TODO Auto-generated method stub + + return row; + } + } +} diff --git a/src/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java similarity index 67% rename from src/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java index b21ca883..4a271b79 100644 --- a/src/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/ListControllerOnKeyListener.java @@ -21,8 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import org.xbmc.api.object.INamedResource; - import android.content.Context; import android.os.Build; import android.view.KeyEvent; @@ -31,69 +29,74 @@ import android.view.inputmethod.InputMethodManager; import android.widget.AbsListView; +import org.xbmc.api.object.INamedResource; + public class ListControllerOnKeyListener implements OnKeyListener { - + public static final String[] DEVICES_HANDLE_MENU_LONGPRESS = {"HTC Magic"}; public static final int LONGPRESS_REPEATS = 10; public static boolean sHandleMenuLongPress; - - static{ + + static { //Decide if MenuKey LongPress is handled by the device itself. sHandleMenuLongPress = true; - for(int i = 0; i < DEVICES_HANDLE_MENU_LONGPRESS.length; i++){ - if(Build.MODEL.equals(DEVICES_HANDLE_MENU_LONGPRESS[i])){ + for (int i = 0; i < DEVICES_HANDLE_MENU_LONGPRESS.length; i++) { + if (Build.MODEL.equals(DEVICES_HANDLE_MENU_LONGPRESS[i])) { sHandleMenuLongPress = false; break; } } } - - + + private boolean mCreatingSoftKeyboard = false; + @SuppressWarnings("unchecked") public boolean onKey(View v, int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU){ - switch(event.getAction()){ - case KeyEvent.ACTION_DOWN: - if(!sHandleMenuLongPress) + if (keyCode == KeyEvent.KEYCODE_MENU) { + switch (event.getAction()) { + case KeyEvent.ACTION_DOWN: + if (!sHandleMenuLongPress) + return false; + return handleMenuKeyDown(v, event); + case KeyEvent.ACTION_UP: + return handleMenuKeyUp(v, event); + default: return false; - return handleMenuKeyDown(v, event); - case KeyEvent.ACTION_UP: - return handleMenuKeyUp(v, event); - default: - return false; } } if (event.getAction() == KeyEvent.ACTION_DOWN) { - if ( keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z ){ - final AbsListView view = (AbsListView)v; - int startIndex = (view).getSelectedItem() == null ? 0 : (view).getSelectedItemPosition() +1; + if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) { + final AbsListView view = (AbsListView) v; + int startIndex = (view).getSelectedItem() == null ? 0 : (view).getSelectedItemPosition() + 1; int count = (view).getCount(); - for(int i = startIndex; i < count; i++){ - if(((T)(view).getItemAtPosition(i)).getShortName().toLowerCase().charAt(0) == Character.toLowerCase(event.getDisplayLabel())){ + for (int i = startIndex; i < count; i++) { + if (((T) (view).getItemAtPosition(i)).getShortName().toLowerCase().charAt(0) == Character + .toLowerCase(event.getDisplayLabel())) { (view).setSelection(i); return true; } } //Check if we should iterate again from the top - if(startIndex > 0){ - for(int i = 0; i < startIndex -1 ; i++){ - if(((T)(view).getItemAtPosition(i)).getShortName().toLowerCase().charAt(0) == Character.toLowerCase(event.getDisplayLabel())){ + if (startIndex > 0) { + for (int i = 0; i < startIndex - 1; i++) { + if (((T) (view).getItemAtPosition(i)).getShortName().toLowerCase().charAt(0) == Character + .toLowerCase(event.getDisplayLabel())) { (view).setSelection(i); return true; } } - } + } return true; } } //event is NOT eaten return false; } - - private boolean handleMenuKeyDown(View v, KeyEvent event){ + + private boolean handleMenuKeyDown(View v, KeyEvent event) { InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if(event.getRepeatCount() >= LONGPRESS_REPEATS){ + if (event.getRepeatCount() >= LONGPRESS_REPEATS) { imm.showSoftInput(v, InputMethodManager.SHOW_FORCED); mCreatingSoftKeyboard = true; return true; @@ -101,14 +104,13 @@ private boolean handleMenuKeyDown(View v, KeyEvent event){ imm.hideSoftInputFromWindow(v.getWindowToken(), 0); return false; } - private boolean handleMenuKeyUp(View v, KeyEvent event){ - if(mCreatingSoftKeyboard){ + + private boolean handleMenuKeyUp(View v, KeyEvent event) { + if (mCreatingSoftKeyboard) { mCreatingSoftKeyboard = false; return true; } - + return false; } - - private boolean mCreatingSoftKeyboard = false; } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/MediaIntentController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MediaIntentController.java similarity index 88% rename from src/org/xbmc/android/remote/presentation/controller/MediaIntentController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/MediaIntentController.java index 467bf71c..cae0a66e 100644 --- a/src/org/xbmc/android/remote/presentation/controller/MediaIntentController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MediaIntentController.java @@ -21,19 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.net.MalformedURLException; -import java.net.URL; - -import org.xbmc.android.remote.R.drawable; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.MediaIntentActivity; -import org.xbmc.android.util.YoutubeURLParser; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.presentation.INotifiableController; - import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; @@ -47,26 +34,50 @@ import android.preference.PreferenceManager; import android.util.Log; +import org.xbmc.android.remote.R.drawable; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.MediaIntentActivity; +import org.xbmc.android.util.YoutubeURLParser; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.presentation.INotifiableController; + +import java.net.MalformedURLException; +import java.net.URL; + /** * Class that is called when XBMC locally tries to open any media content. The * user then has an additional option "Play in XBMC". - * + * * @author Team XBMC */ public class MediaIntentController extends AbstractController implements IController, INotifiableController { - + + private static final String CONFIRM_PLAY_ON_XBMC = "setting_confirm_play_on_xbmc"; private IControlManager mControlManager; private IInfoManager mInfoManager; private DataResponse mXbmcStatusHandler; - private static final String CONFIRM_PLAY_ON_XBMC = "setting_confirm_play_on_xbmc"; - + public MediaIntentController(Activity activity, Handler handler) { super.onCreate(activity, handler); mInfoManager = ManagerFactory.getInfoManager(this); mControlManager = ManagerFactory.getControlManager(this); } + private static boolean isValidURL(String path) { + if (path == null || path.equals("")) + return false; + try { + new URL(path); + } catch (MalformedURLException e) { + return false; + } + return true; + } + /* (non-Javadoc) * @see org.xbmc.android.remote.presentation.controller.IController#onActivityPause() */ @@ -83,13 +94,14 @@ public void onActivityResume(Activity activity) { super.onActivityResume(activity); mInfoManager.setController(this); mControlManager.setController(this); - mInfoManager.getSystemInfo(mXbmcStatusHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); + mInfoManager.getSystemInfo(mXbmcStatusHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); } public void playUrl(String url) { - mControlManager.playUrl(new DataResponse(), url, mActivity.getApplicationContext()); + mControlManager.playUrl(new DataResponse(), url, mActivity.getApplicationContext()); } - + public void setupStatusHandler() { mXbmcStatusHandler = new DataResponse() { public void run() { @@ -124,33 +136,22 @@ public void run() { e.printStackTrace(); } } - - } - - private static boolean isValidURL(String path){ - if(path == null || path.equals("")) - return false; - try{ - new URL(path); - } catch(MalformedURLException e) { - return false; - } - return true; + } - + /** * Checks the intent that created/resumed this activity. Used to see if we are being handed * an URL that should be passed to XBMC. */ - private void checkIntent(){ + private void checkIntent() { Intent intent = mActivity.getIntent(); final String action = intent.getAction(); - if(action != null) { + if (action != null) { Log.i("CHECKINTENT", action); - if (action.equals(MediaIntentActivity.ACTION)){ + if (action.equals(MediaIntentActivity.ACTION)) { final String path = intent.getData().toString(); - if(isValidURL(path)){ + if (isValidURL(path)) { handleURL(path); cleaupIntent(intent); } @@ -166,22 +167,24 @@ private void cleaupIntent(Intent intent) { private void handleURL(final String path) { // If it is a youtube URL, we have to parse the video id from it and send it to the youtube plugin. - // The syntax for that is plugin://plugin.video.youtube/?path=/root/search%26action=play_video%26videoid=VIDEOID + // The syntax for that is plugin://plugin.video + // .youtube/?path=/root/search%26action=play_video%26videoid=VIDEOID Uri playuri = Uri.parse(path); final String url; final String message; String youtubeVideoId = YoutubeURLParser.parseYoutubeURL(playuri); - - if(youtubeVideoId != null){ + + if (youtubeVideoId != null) { url = "plugin://plugin.video.youtube/?path=/root/search&action=play_video&videoid=" + youtubeVideoId; - message = "Do you want to play\nYoutube video " + youtubeVideoId + " on XBMC? Youtube addon required!"; - }else{ + message = "Do you want to play\nYoutube video " + youtubeVideoId + " on XBMC? Youtube addon required!"; + } else { // Not a youtube URL or unparsable YouTube URL so just pass it on to XBMC as-is url = playuri.toString(); message = "Do you want to play\n" + path + "\n on XBMC?"; - } - - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext()); + } + + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext + ()); if (prefs.getBoolean(CONFIRM_PLAY_ON_XBMC, true)) { final Builder builder = new Builder(mActivity); builder.setTitle("Play URL on XBMC?"); @@ -190,8 +193,8 @@ private void handleURL(final String path) { builder.setIcon(drawable.icon); builder.setNeutralButton("Yes", new android.content.DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { - new Thread(){ - public void run(){ + new Thread() { + public void run() { Looper.prepare(); playUrl(url); Looper.loop(); @@ -207,7 +210,7 @@ public void onClick(DialogInterface dialog, int which) { mActivity.finish(); } }); - + final AlertDialog alert = builder.create(); try { alert.show(); @@ -215,8 +218,8 @@ public void onClick(DialogInterface dialog, int which) { e.printStackTrace(); } } else { - new Thread(){ - public void run(){ + new Thread() { + public void run() { Looper.prepare(); playUrl(url); Looper.loop(); diff --git a/src/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java similarity index 90% rename from src/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java index d6880245..fe27ed57 100644 --- a/src/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieGenreListController.java @@ -21,16 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.object.Genre; - import android.app.Activity; import android.content.Intent; import android.graphics.BitmapFactory; @@ -46,31 +36,41 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.object.Genre; + +import java.util.ArrayList; + public class MovieGenreListController extends ListController implements IController { - + public static final int TYPE_MOVIE = 0; public static final int TYPE_TVSHOW = 1; - + private static final long serialVersionUID = 4360738733222799619L; private IVideoManager mVideoManager; private int mType; - + public MovieGenreListController(int type) { mType = type; } - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mVideoManager = ManagerFactory.getVideoManager(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; Intent nextActivity = new Intent(view.getContext(), ListActivity.class); - Genre genre = (Genre)mList.getAdapter().getItem(((OneLabelItemView)view).position); - if(mType == TYPE_MOVIE) + Genre genre = (Genre) mList.getAdapter().getItem(((OneLabelItemView) view).position); + if (mType == TYPE_MOVIE) nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new MovieListController()); else nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new TvShowListController()); @@ -78,9 +78,9 @@ public void onItemClick(AdapterView parent, View view, int position, long id) mActivity.startActivity(nextActivity); } }); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_genre); - + final String title = mType == TYPE_MOVIE ? "Movie " : mType == TYPE_TVSHOW ? "TV Show " : "" + "genres"; DataResponse> response = new DataResponse>() { public void run() { @@ -95,60 +95,61 @@ public void run() { }; mList.setOnKeyListener(new ListControllerOnKeyListener()); - + showOnLoading(); - setTitle(title + "..."); - switch(mType) { - case TYPE_MOVIE: - mVideoManager.getMovieGenres(response, mActivity.getApplicationContext()); - break; - case TYPE_TVSHOW: - mVideoManager.getTvShowGenres(response, mActivity.getApplicationContext()); - break; - } - } - } - - private class GenreAdapter extends ArrayAdapter { - GenreAdapter(Activity activity, ArrayList items) { - super(activity, 0, items); - } - public View getView(int position, View convertView, ViewGroup parent) { - final OneLabelItemView view; - if (convertView == null) { - view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); - } else { - view = (OneLabelItemView)convertView; + setTitle(title + "..."); + switch (mType) { + case TYPE_MOVIE: + mVideoManager.getMovieGenres(response, mActivity.getApplicationContext()); + break; + case TYPE_TVSHOW: + mVideoManager.getTvShowGenres(response, mActivity.getApplicationContext()); + break; } - final Genre genre = this.getItem(position); - view.reset(); - view.position = position; - view.title = genre.name; - return view; } } - private static final long serialVersionUID = 4360738733222799619L; - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // no context menu here } + @Override public void onContextItemSelected(MenuItem item) { // no context menu here } - + public void onActivityPause() { if (mVideoManager != null) { mVideoManager.setController(null); } super.onActivityPause(); } - + public void onActivityResume(Activity activity) { super.onActivityResume(activity); if (mVideoManager != null) { mVideoManager.setController(this); } } + + private class GenreAdapter extends ArrayAdapter { + GenreAdapter(Activity activity, ArrayList items) { + super(activity, 0, items); + } + + public View getView(int position, View convertView, ViewGroup parent) { + final OneLabelItemView view; + if (convertView == null) { + view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); + } else { + view = (OneLabelItemView) convertView; + } + final Genre genre = this.getItem(position); + view.reset(); + view.position = position; + view.title = genre.name; + return view; + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/MovieListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieListController.java similarity index 65% rename from src/org/xbmc/android/remote/presentation/controller/MovieListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieListController.java index 7bdfbf7b..e76ec31f 100644 --- a/src/org/xbmc/android/remote/presentation/controller/MovieListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MovieListController.java @@ -21,25 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.MovieDetailsActivity; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Movie; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -66,13 +47,30 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.MovieDetailsActivity; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Movie; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class MovieListController extends ListController implements IController { - private static final int mThumbSize = ThumbSize.SMALL; public static final int ITEM_CONTEXT_PLAY = 1; public static final int ITEM_CONTEXT_INFO = 2; public static final int ITEM_CONTEXT_IMDB = 3; - public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_TITLE_ASC = 21; @@ -83,29 +81,26 @@ public class MovieListController extends ListController implements IController { public static final int MENU_SORT_BY_RATING_DESC = 26; public static final int MENU_SORT_BY_DATE_ADDED_ASC = 27; public static final int MENU_SORT_BY_DATE_ADDED_DESC = 28; - - + private static final int mThumbSize = ThumbSize.SMALL; + private static final long serialVersionUID = 1088971882661811256L; + private static Bitmap mWatchedBitmap; private Actor mActor; private Genre mGenre; - private IVideoManager mVideoManager; private IControlManager mControlManager; - private boolean mLoadCovers = false; - private static Bitmap mWatchedBitmap; - public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mVideoManager = ManagerFactory.getVideoManager(this); mControlManager = ManagerFactory.getControlManager(this); - - ((ISortableManager)mVideoManager).setSortKey(AbstractManager.PREF_SORT_KEY_MOVIE); - ((ISortableManager)mVideoManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); - + + ((ISortableManager) mVideoManager).setSortKey(AbstractManager.PREF_SORT_KEY_MOVIE); + ((ISortableManager) mVideoManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; - + if (!isCreated()) { super.onCreate(activity, handler, list); @@ -113,19 +108,19 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mActor = (Actor)mActivity.getIntent().getSerializableExtra(ListController.EXTRA_ACTOR); - mGenre = (Genre)mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); + + mActor = (Actor) mActivity.getIntent().getSerializableExtra(ListController.EXTRA_ACTOR); + mGenre = (Genre) mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_poster); mWatchedBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.check_mark); setupIdleListener(); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; - final Movie movie = (Movie)mList.getAdapter().getItem(((FiveLabelsItemView)view).position); + if (isLoading()) return; + final Movie movie = (Movie) mList.getAdapter().getItem(((FiveLabelsItemView) view).position); Intent nextActivity = new Intent(view.getContext(), MovieDetailsActivity.class); nextActivity.putExtra(ListController.EXTRA_MOVIE, movie); mActivity.startActivity(nextActivity); @@ -135,9 +130,10 @@ public void onItemClick(AdapterView parent, View view, int position, long id) fetch(); } } - + private void fetch() { - final String title = mActor != null ? mActor.name + " - " : mGenre != null ? mGenre.name + " - " : "" + "Movies"; + final String title = mActor != null ? mActor.name + " - " : mGenre != null ? mGenre.name + " - " : "" + + "Movies"; DataResponse> response = new DataResponse>() { public void run() { if (value.size() > 0) { @@ -149,61 +145,63 @@ public void run() { } } }; - + showOnLoading(); setTitle(title + "..."); - if (mActor != null) { // movies with a certain actor + if (mActor != null) { // movies with a certain actor mVideoManager.getMovies(response, mActor, mActivity.getApplicationContext()); - } else if (mGenre != null) { // movies of a genre + } else if (mGenre != null) { // movies of a genre mVideoManager.getMovies(response, mGenre, mActivity.getApplicationContext()); - } else { // all movies + } else { // all movies mVideoManager.getMovies(response, mActivity.getApplicationContext()); } } - + /** * Shows a dialog and refreshes the movie library if user confirmed. + * * @param activity */ public void refreshMovieLibrary(final Activity activity) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage("Are you sure you want XBMC to rescan your movie library?") - .setCancelable(false) - .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mControlManager.updateLibrary(new DataResponse() { - public void run() { - final String message; - if (value) { - message = "Movie library updated has been launched."; - } else { - message = "Error launching movie library update."; + .setCancelable(false) + .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mControlManager.updateLibrary(new DataResponse() { + public void run() { + final String message; + if (value) { + message = "Movie library updated has been launched."; + } else { + message = "Error launching movie library update."; + } + Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); + toast.show(); } - Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); - toast.show(); - } - }, "video", mActivity.getApplicationContext()); - } - }) - .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + }, "video", mActivity.getApplicationContext()); + } + }) + .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); builder.create().show(); } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; + final FiveLabelsItemView view = (FiveLabelsItemView) ((AdapterContextMenuInfo) menuInfo).targetView; menu.setHeaderTitle(view.title); menu.add(0, ITEM_CONTEXT_PLAY, 1, "Play Movie"); menu.add(0, ITEM_CONTEXT_INFO, 2, "View Details"); menu.add(0, ITEM_CONTEXT_IMDB, 3, "Open IMDb"); } - + public void onContextItemSelected(MenuItem item) { - final Movie movie = (Movie)mList.getAdapter().getItem(((FiveLabelsItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final Movie movie = (Movie) mList.getAdapter().getItem(((FiveLabelsItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_PLAY: mControlManager.playFile(new DataResponse() { @@ -221,23 +219,20 @@ public void run() { break; case ITEM_CONTEXT_IMDB: Intent intentIMDb = null; - if (movie.getIMDbId().equals("")) - { + if (movie.getIMDbId().equals("")) { intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///find?s=tt&q=" + movie.getName())); - } - else - { + } else { intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///title/" + movie.getIMDbId())); } - if (mActivity.getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) - { - if (movie.getIMDbId().equals("")) - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/search/title?title=" + movie.getShortName() + "&title_type=feature,tv_movie&release_date=" + movie.year)); - } - else - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/title/" + movie.getIMDbId())); + if (mActivity.getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == + null) { + if (movie.getIMDbId().equals("")) { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb" + + ".com/search/title?title=" + movie.getShortName() + "&title_type=feature," + + "tv_movie&release_date=" + movie.year)); + } else { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/title/" + movie + .getIMDbId())); } } mActivity.startActivity(intentIMDb); @@ -246,7 +241,7 @@ public void run() { return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { if (mActor != null || mGenre != null) { @@ -264,93 +259,126 @@ public void onCreateOptionsMenu(Menu menu) { // menu.add(0, MENU_SWITCH_VIEW, 0, "Switch view").setIcon(R.drawable.menu_view); createShowHideWatchedToggle(menu); } - + @Override public void onOptionsItemSelected(MenuItem item) { final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - break; - case MENU_SORT_BY_TITLE_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_DATE_ADDED_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.DATE_ADDED); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_DATE_ADDED_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.DATE_ADDED); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - default: - super.onOptionsItemSelected(item); + case MENU_PLAY_ALL: + break; + case MENU_SORT_BY_TITLE_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, SortType.RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_DATE_ADDED_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.DATE_ADDED); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_DATE_ADDED_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.DATE_ADDED); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_MOVIE, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + default: + super.onOptionsItemSelected(item); } } - + @Override protected void refreshList() { hideMessage(); fetch(); } - + + public void onActivityPause() { + if (mVideoManager != null) { + mVideoManager.setController(null); + mVideoManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mVideoManager != null) { + mVideoManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + private class MovieAdapter extends ArrayAdapter { MovieAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final FiveLabelsItemView view; if (convertView == null) { - view = new FiveLabelsItemView(mActivity, mVideoManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), false); + view = new FiveLabelsItemView(mActivity, mVideoManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), false); } else { - view = (FiveLabelsItemView)convertView; + view = (FiveLabelsItemView) convertView; } - + final Movie movie = getItem(position); view.reset(); view.position = position; @@ -360,11 +388,11 @@ public View getView(int position, View convertView, ViewGroup parent) { view.subtitleRight = movie.year > 0 ? String.valueOf(movie.year) : ""; view.bottomtitle = movie.runtime; view.bottomright = String.valueOf(movie.rating); - + if (mLoadCovers) { - if(mVideoManager.coverLoaded(movie, mThumbSize)){ + if (mVideoManager.coverLoaded(movie, mThumbSize)) { view.setCover(mVideoManager.getCoverSync(movie, mThumbSize)); - }else{ + } else { view.setCover(null); view.getResponse().load(movie, !mPostScrollLoader.isListIdle()); } @@ -372,28 +400,5 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - private static final long serialVersionUID = 1088971882661811256L; - - public void onActivityPause() { - if (mVideoManager != null) { - mVideoManager.setController(null); - mVideoManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mVideoManager != null) { - mVideoManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java similarity index 88% rename from src/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java index bee9f321..f060be34 100644 --- a/src/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicGenreListController.java @@ -21,16 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.MusicGenreActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.object.Genre; - import android.app.Activity; import android.content.Intent; import android.graphics.BitmapFactory; @@ -47,35 +37,45 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.MusicGenreActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.object.Genre; + +import java.util.ArrayList; + public class MusicGenreListController extends ListController implements IController { - + public static final int ITEM_CONTEXT_QUEUE = 1; public static final int ITEM_CONTEXT_PLAY = 2; - + private static final long serialVersionUID = 4360738733222799619L; private IMusicManager mMusicManager; - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mMusicManager = ManagerFactory.getMusicManager(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); - + mActivity.registerForContextMenu(mList); mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; + if (isLoading()) return; Intent nextActivity; - Genre genre = (Genre)mList.getAdapter().getItem(((OneLabelItemView)view).position); + Genre genre = (Genre) mList.getAdapter().getItem(((OneLabelItemView) view).position); nextActivity = new Intent(view.getContext(), MusicGenreActivity.class); nextActivity.putExtra(ListController.EXTRA_GENRE, genre); nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new SongListController()); mActivity.startActivity(nextActivity); } }); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_genre); - + final String title = "Genres"; DataResponse> response = new DataResponse>() { public void run() { @@ -88,56 +88,74 @@ public void run() { } } }; - + mList.setOnKeyListener(new ListControllerOnKeyListener()); setTitle("..."); showOnLoading(); - mMusicManager.getGenres(response, mActivity.getApplicationContext()); + mMusicManager.getGenres(response, mActivity.getApplicationContext()); } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! - final Genre genre = (Genre)mList.getAdapter().getItem(((OneLabelItemView)(((AdapterContextMenuInfo)menuInfo).targetView)).position); + final Genre genre = (Genre) mList.getAdapter().getItem(((OneLabelItemView) (((AdapterContextMenuInfo) + menuInfo).targetView)).position); menu.setHeaderTitle(genre.name); menu.add(0, ITEM_CONTEXT_QUEUE, 1, "Queue " + genre.name + " songs"); menu.add(0, ITEM_CONTEXT_PLAY, 2, "Play " + genre.name + " songs"); } - + public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final Genre genre = (Genre)mList.getAdapter().getItem(((OneLabelItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final Genre genre = (Genre) mList.getAdapter().getItem(((OneLabelItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_QUEUE: mMusicManager.addToPlaylist(new QueryResponse( - mActivity, - "Adding all songs of genre " + genre.name + " to playlist...", + mActivity, + "Adding all songs of genre " + genre.name + " to playlist...", "Error adding songs!" - ), genre, mActivity.getApplicationContext()); + ), genre, mActivity.getApplicationContext()); break; case ITEM_CONTEXT_PLAY: mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs of genre " + genre.name + "...", + mActivity, + "Playing all songs of genre " + genre.name + "...", "Error playing songs!", true - ), genre, mActivity.getApplicationContext()); + ), genre, mActivity.getApplicationContext()); break; } } - + + public void onActivityPause() { + if (mMusicManager != null) { + mMusicManager.setController(null); + mMusicManager.postActivity(); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mMusicManager != null) { + mMusicManager.setController(this); + } + } + private class GenreAdapter extends ArrayAdapter { GenreAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final OneLabelItemView view; if (convertView == null) { view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); } else { - view = (OneLabelItemView)convertView; + view = (OneLabelItemView) convertView; } final Genre genre = this.getItem(position); view.reset(); @@ -146,20 +164,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - private static final long serialVersionUID = 4360738733222799619L; - - public void onActivityPause() { - if (mMusicManager != null) { - mMusicManager.setController(null); - mMusicManager.postActivity(); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mMusicManager != null) { - mMusicManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java similarity index 80% rename from src/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java index db411743..42943039 100644 --- a/src/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/MusicPlaylistController.java @@ -21,26 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; -import java.util.HashMap; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.business.NowPlayingPollerThread; -import org.xbmc.android.remote.presentation.activity.PlaylistActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.android.util.ConnectionFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; -import org.xbmc.api.info.PlayStatus; -import org.xbmc.api.object.INamedResource; -import org.xbmc.api.object.Song; -import org.xbmc.eventclient.ButtonCodes; -import org.xbmc.httpapi.client.MusicClient; - import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -62,62 +42,80 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.business.NowPlayingPollerThread; +import org.xbmc.android.remote.presentation.activity.PlaylistActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.android.util.ConnectionFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.info.PlayStatus; +import org.xbmc.api.object.INamedResource; +import org.xbmc.api.object.Song; +import org.xbmc.eventclient.ButtonCodes; +import org.xbmc.httpapi.client.MusicClient; + +import java.util.ArrayList; +import java.util.HashMap; + public class MusicPlaylistController extends ListController implements IController, Callback { - + public static final String TAG = "MusicPlaylistLogic"; - + public static final int ITEM_CONTEXT_PLAY = 1; public static final int ITEM_CONTEXT_REMOVE = 2; - + public static final int MESSAGE_PLAYLIST_SIZE = 701; public static final String BUNDLE_PLAYLIST_SIZE = "playlist_size"; - + private static final long serialVersionUID = 755529227668553163L; + private static Bitmap sPlayingBitmap; private PlaylistActivity mPlaylistActivity; private Handler mNowPlayingHandler; private SongAdapter mSongAdapter; - private IControlManager mControlManager; private IMusicManager mMusicManager; private IEventClientManager mEventClient; - private int mPlayStatus = PlayStatus.UNKNOWN; private int mPlayListId = -1; private int mCurrentPosition = -1; private int mLastPosition = -1; - - private static Bitmap sPlayingBitmap; - + public void onCreate(final PlaylistActivity activity, Handler handler, final AbsListView list) { - + mPlaylistActivity = activity; mMusicManager = ManagerFactory.getMusicManager(this); mControlManager = ManagerFactory.getControlManager(this); mEventClient = ManagerFactory.getEventClientManager(this); mNowPlayingHandler = new Handler(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); - + activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_song_light); sPlayingBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_play); - + mMusicManager.getPlaylistPosition(new DataResponse() { public void run() { mCurrentPosition = value; } }, mActivity.getApplicationContext()); - + mMusicManager.getPlaylist(new DataResponse>() { - public void run() { - if (value.size() > 0) { - final ArrayList items = new ArrayList(); - int i = 0; - for (String path : value) { - items.add(new PlaylistItem(path, i++)); + public void run() { + if (value.size() > 0) { + final ArrayList items = new ArrayList(); + int i = 0; + for (String path : value) { + items.add(new PlaylistItem(path, i++)); } - setTitle("Music playlist (" + (value.size() > MusicClient.PLAYLIST_LIMIT ? MusicClient.PLAYLIST_LIMIT + "+" : value.size()) + ")" ); + setTitle("Music playlist (" + (value.size() > MusicClient.PLAYLIST_LIMIT ? MusicClient + .PLAYLIST_LIMIT + "+" : value.size()) + ")"); mSongAdapter = new SongAdapter(activity, items); ((AdapterView) mList).setAdapter(mSongAdapter); if (mCurrentPosition >= 0) { @@ -128,13 +126,15 @@ public void run() { setNoDataMessage("No tracks in playlist.", R.drawable.icon_playlist_dark); } - } - }, mActivity.getApplicationContext()); + } + }, mActivity.getApplicationContext()); mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - final PlaylistItem item = (PlaylistItem)mList.getAdapter().getItem(((OneLabelItemView)view).position); + final PlaylistItem item = (PlaylistItem) mList.getAdapter().getItem(((OneLabelItemView) view) + .position); final DataResponse doNothing = new DataResponse(); - mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mActivity.getApplicationContext()); + mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + mActivity.getApplicationContext()); mMusicManager.setPlaylistSong(doNothing, item.position, mActivity.getApplicationContext()); } }); @@ -146,47 +146,47 @@ public void onItemClick(AdapterView parent, View view, int position, long id) /** * This is called from the thread with a message containing updated info of * what's currently playing. - * - * @param msg - * Message object containing currently playing info + * + * @param msg Message object containing currently playing info */ public synchronized boolean handleMessage(Message msg) { final Bundle data = msg.getData(); - final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying) data.getSerializable(NowPlayingPollerThread.BUNDLE_CURRENTLY_PLAYING); + final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying) data.getSerializable(NowPlayingPollerThread + .BUNDLE_CURRENTLY_PLAYING); switch (msg.what) { - case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: - mPlayStatus = currentlyPlaying.getPlayStatus(); - if (currentlyPlaying.isPlaying()) { - mPlaylistActivity.setTime(Song.getDuration(currentlyPlaying.getTime() + 1)); - } else { - mPlaylistActivity.clear(); - } - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: - mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); - onTrackChanged(currentlyPlaying); - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: - mPlayListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); - return true; - - case MESSAGE_PLAYLIST_SIZE: - final int size = msg.getData().getInt(BUNDLE_PLAYLIST_SIZE); - mPlaylistActivity.setNumItems(size == 0 ? "empty" : size + " tracks"); - return true; - - case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: - case NowPlayingPollerThread.MESSAGE_RECONFIGURE: - mPlayStatus = PlayStatus.UNKNOWN; - return true; - - default: - return false; + case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: + mPlayStatus = currentlyPlaying.getPlayStatus(); + if (currentlyPlaying.isPlaying()) { + mPlaylistActivity.setTime(Song.getDuration(currentlyPlaying.getTime() + 1)); + } else { + mPlaylistActivity.clear(); + } + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: + mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); + onTrackChanged(currentlyPlaying); + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: + mPlayListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); + return true; + + case MESSAGE_PLAYLIST_SIZE: + final int size = msg.getData().getInt(BUNDLE_PLAYLIST_SIZE); + mPlaylistActivity.setNumItems(size == 0 ? "empty" : size + " tracks"); + return true; + + case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: + case NowPlayingPollerThread.MESSAGE_RECONFIGURE: + mPlayStatus = PlayStatus.UNKNOWN; + return true; + + default: + return false; } } - + public void setupButtons(View prev, View stop, View playpause, View next) { // setup buttons @@ -197,44 +197,30 @@ public void setupButtons(View prev, View stop, View playpause, View next) { public void onClick(View v) { switch (mPlayStatus) { case PlayStatus.PLAYING: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short)0, (byte)0); + mEventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short) 0, + (byte) 0); break; case PlayStatus.PAUSED: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short)0, (byte)0); + mEventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short) 0, (byte) 0); break; case PlayStatus.STOPPED: final DataResponse doNothing = new DataResponse(); - //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mActivity.getApplicationContext()); - mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); + //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + // mActivity.getApplicationContext()); + mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); break; } } }); } - - /** - * Handles the push- release button code. Switches image of the pressed - * button, vibrates and executes command. - */ - private class OnRemoteAction implements OnClickListener { - private final String mAction; - - public OnRemoteAction(String action) { - mAction = action; - } - - public void onClick(View v) { - mEventClient.sendButton("R1", mAction, false, true, true, (short) 0, (byte) 0); - } - } - public void onTrackChanged(ICurrentlyPlaying newSong) { final SongAdapter adapter = mSongAdapter; if (adapter != null) { final int currentPos = mCurrentPosition; final int newPos = newSong.getPlaylistPosition(); - + // clear previous song's icon OneLabelItemView view = adapter.getViewAtPosition(currentPos); if (currentPos >= 0 && view != null) { @@ -243,7 +229,7 @@ public void onTrackChanged(ICurrentlyPlaying newSong) { } else { Log.i(TAG, "NOT resetting previous icon at position " + currentPos); } - + // set new song's play icon view = adapter.getViewAtPosition(newPos); mCurrentPosition = newPos; @@ -254,50 +240,118 @@ public void onTrackChanged(ICurrentlyPlaying newSong) { } } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! -/* final OneHolderholder = (OneHolder)((AdapterContextMenuInfo)menuInfo).targetView.getTag(); +/* final OneHolderholder = (OneHolder)((AdapterContextMenuInfo)menuInfo).targetView +.getTag(); menu.setHeaderTitle(holder.holderItem.filename); menu.add(0, ITEM_CONTEXT_PLAY, 1, "Play"); menu.add(0, ITEM_CONTEXT_REMOVE, 2, "Remove");*/ } - + public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final PlaylistItem playlistItem = (PlaylistItem)mList.getAdapter().getItem(((OneLabelItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final PlaylistItem playlistItem = (PlaylistItem) mList.getAdapter().getItem(((OneLabelItemView) ( + (AdapterContextMenuInfo) item.getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_PLAY: - mMusicManager.setPlaylistSong(new DataResponse(), playlistItem.position, mActivity.getApplicationContext()); + mMusicManager.setPlaylistSong(new DataResponse(), playlistItem.position, + mActivity.getApplicationContext()); break; case ITEM_CONTEXT_REMOVE: - mMusicManager.removeFromPlaylist(new DataResponse(), playlistItem.path, mActivity.getApplicationContext()); + mMusicManager.removeFromPlaylist(new DataResponse(), playlistItem.path, + mActivity.getApplicationContext()); break; default: return; } } - + + public void onActivityPause() { + ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, + true); + if (mMusicManager != null) { + mMusicManager.setController(null); + mMusicManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + if (mEventClient != null) { + mEventClient.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + ConnectionFactory.subscribeNowPlayingPollerThread(activity.getApplicationContext(), mNowPlayingHandler); + if (mEventClient != null) { + mEventClient.setController(this); + } + if (mMusicManager != null) { + mMusicManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + + private static class PlaylistItem implements INamedResource { + public final String path; + public final String filename; + public final int position; + + public PlaylistItem(String path, int position) { + this.path = path; + this.filename = path.substring(path.replaceAll("\\\\", "/").lastIndexOf('/') + 1); + this.position = position; + } + + public String getShortName() { + return filename; + } + } + + /** + * Handles the push- release button code. Switches image of the pressed + * button, vibrates and executes command. + */ + private class OnRemoteAction implements OnClickListener { + private final String mAction; + + public OnRemoteAction(String action) { + mAction = action; + } + + public void onClick(View v) { + mEventClient.sendButton("R1", mAction, false, true, true, (short) 0, (byte) 0); + } + } + private class SongAdapter extends ArrayAdapter { private final HashMap mItemPositions = new HashMap(); + SongAdapter(Activity activity, ArrayList items) { super(activity, 0, items); Handler handler = mNowPlayingHandler; if (handler != null) { Message msg = Message.obtain(); - Bundle bundle = msg.getData(); - bundle.putInt(BUNDLE_PLAYLIST_SIZE, items.size()); - msg.what = MESSAGE_PLAYLIST_SIZE; - handler.sendMessage(msg); + Bundle bundle = msg.getData(); + bundle.putInt(BUNDLE_PLAYLIST_SIZE, items.size()); + msg.what = MESSAGE_PLAYLIST_SIZE; + handler.sendMessage(msg); } } + public View getView(int position, View convertView, ViewGroup parent) { final OneLabelItemView view; if (convertView == null) { view = new OneLabelItemView(mActivity, parent.getWidth(), mFallbackBitmap, mList.getSelector(), true); } else { - view = (OneLabelItemView)convertView; + view = (OneLabelItemView) convertView; mItemPositions.remove(view.position); } final PlaylistItem item = this.getItem(position); @@ -312,6 +366,7 @@ public View getView(int position, View convertView, ViewGroup parent) { mItemPositions.put(view.position, view); return view; } + public OneLabelItemView getViewAtPosition(int position) { if (mItemPositions.containsKey(position)) { return mItemPositions.get(position); @@ -319,49 +374,4 @@ public OneLabelItemView getViewAtPosition(int position) { return null; } } - - private static class PlaylistItem implements INamedResource{ - public final String path; - public final String filename; - public final int position; - public PlaylistItem(String path, int position) { - this.path = path; - this.filename = path.substring(path.replaceAll("\\\\", "/").lastIndexOf('/') + 1); - this.position = position; - } - public String getShortName() { - return filename; - } - } - - public void onActivityPause() { - ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, true); - if (mMusicManager != null) { - mMusicManager.setController(null); - mMusicManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - if (mEventClient != null) { - mEventClient.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - ConnectionFactory.subscribeNowPlayingPollerThread(activity.getApplicationContext(), mNowPlayingHandler); - if (mEventClient != null) { - mEventClient.setController(this); - } - if (mMusicManager != null) { - mMusicManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } - - private static final long serialVersionUID = 755529227668553163L; } diff --git a/src/org/xbmc/android/remote/presentation/controller/NowPlayingController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/NowPlayingController.java similarity index 84% rename from src/org/xbmc/android/remote/presentation/controller/NowPlayingController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/NowPlayingController.java index 55677825..e454d757 100644 --- a/src/org/xbmc/android/remote/presentation/controller/NowPlayingController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/NowPlayingController.java @@ -1,222 +1,237 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.business.NowPlayingPollerThread; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.activity.PlaylistActivity; -import org.xbmc.android.util.ConnectionFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; -import org.xbmc.api.info.PlayStatus; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.api.type.MediaType; -import org.xbmc.api.type.SeekType; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Handler.Callback; -import android.os.Message; -import android.util.Log; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.SeekBar; -import android.widget.SeekBar.OnSeekBarChangeListener; - -public class NowPlayingController extends AbstractController implements INotifiableController, IController, Callback { - - private static final String TAG = "NowPlayingController"; - - private IControlManager mControlManager; - private NowPlayingActivity mNowPlayingActivity; - private Handler mNowPlayingHandler; - private IEventClientManager mEventClientManager; - private int mPlayStatus = PlayStatus.UNKNOWN; - private int mPlayListId = -1; - private int mLastPosition = -1; - - public NowPlayingController(NowPlayingActivity activity, Handler handler) { - super.onCreate(activity, handler); - mNowPlayingActivity = activity; - mControlManager = ManagerFactory.getControlManager(this); - mEventClientManager = ManagerFactory.getEventClientManager(this); - mNowPlayingHandler = new Handler(this); - } - - /** - * This is called from the thread with a message containing updated - * info of what's currently playing. - * @param msg Message object containing currently playing info - */ - public synchronized boolean handleMessage(Message msg) { - - final Bundle data = msg.getData(); - final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying)data.getSerializable(NowPlayingPollerThread.BUNDLE_CURRENTLY_PLAYING); - - switch (msg.what) { - case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: - mPlayStatus = currentlyPlaying.getPlayStatus(); - mNowPlayingActivity.setProgressPosition(Math.round(currentlyPlaying.getPercentage())); - if (mPlayStatus == PlayStatus.PAUSED || mPlayStatus == PlayStatus.PLAYING) { - mNowPlayingActivity.updateProgress(currentlyPlaying.getDuration(), currentlyPlaying.getTime(), (mPlayStatus == PlayStatus.PAUSED)); - } else { - mNowPlayingActivity.clear(); - } - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: - mNowPlayingActivity.updateInfo(currentlyPlaying.getTitle(), currentlyPlaying.getArtist(), currentlyPlaying.getAlbum()); - mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: - mPlayListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); - return true; - - case NowPlayingPollerThread.MESSAGE_COVER_CHANGED: - // TODO: FIX!! - mNowPlayingActivity.updateCover(ConnectionFactory.getNowPlayingPoller(mActivity).getNowPlayingCover(), (currentlyPlaying != null) ? currentlyPlaying.getMediaType() : MediaType.UNKNOWN); - return true; - - case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: - mPlayStatus = PlayStatus.UNKNOWN; - Log.w(TAG,"Received connection error from poller!"); - return true; - - case NowPlayingPollerThread.MESSAGE_RECONFIGURE: - mPlayStatus = PlayStatus.UNKNOWN; - new Thread(){ - public void run(){ - try{ - Thread.sleep(1000); - } catch (InterruptedException e) { - Log.e(TAG, Log.getStackTraceString(e)); - } - ConnectionFactory.subscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler); - } - }.start(); - return true; - default: - return false; - } - } - - public void enableSeekbar(SeekBar seekbar) { - seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { - public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - if (fromUser && !seekBar.isInTouchMode()) - seek(progress); - } - - public void onStartTrackingTouch(SeekBar seekBar) { - - } - - public void onStopTrackingTouch(SeekBar seekBar) { - seek(seekBar.getProgress()); - } - }); - } - - public void disableSeekbar(SeekBar seekbar) { - seekbar.setOnSeekBarChangeListener(null); - } - - public void setupButtons(SeekBar seekbar, View prev, View stop, View playpause, View next, View playlist) { - - enableSeekbar(seekbar); - - // setup buttons - prev.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_SKIP_MINUS)); - stop.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_STOP)); - next.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_SKIP_PLUS)); - playpause.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - switch (mPlayStatus) { - case PlayStatus.PLAYING: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short)0, (byte)0); - break; - case PlayStatus.PAUSED: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short)0, (byte)0); - break; - case PlayStatus.STOPPED: - final DataResponse doNothing = new DataResponse(); - //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mActivity.getApplicationContext()); - mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); - break; - } - } - }); - - // playlist button - playlist.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mActivity.startActivity(new Intent(mActivity, PlaylistActivity.class)); - } - }); - } - public void seek(int progress) { - mControlManager.seek(new DataResponse(), SeekType.absolute, progress, mActivity.getApplicationContext()); - } - - - /** - * Handles the push- release button code. Switches image of the pressed - * button, vibrates and executes command. - */ - private class OnRemoteAction implements OnClickListener { - private final String mAction; - public OnRemoteAction(String action) { - mAction = action; - } - public void onClick(View v) { - mEventClientManager.sendButton("R1", mAction, false, true, true, (short)0, (byte)0); - } - } - - public void onActivityPause() { - ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, true); - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(final Activity activity) { - super.onActivityResume(activity); - new Thread("nowplaying-spawning") { - @Override - public void run() { - ConnectionFactory.subscribeNowPlayingPollerThread(activity.getApplicationContext(), mNowPlayingHandler); - } - }.start(); - if (mControlManager != null) { - mControlManager.setController(this); - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Handler.Callback; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.business.NowPlayingPollerThread; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.activity.PlaylistActivity; +import org.xbmc.android.util.ConnectionFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.info.PlayStatus; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.api.type.MediaType; +import org.xbmc.api.type.SeekType; +import org.xbmc.eventclient.ButtonCodes; + +public class NowPlayingController extends AbstractController implements INotifiableController, IController, Callback { + + private static final String TAG = "NowPlayingController"; + + private IControlManager mControlManager; + private NowPlayingActivity mNowPlayingActivity; + private Handler mNowPlayingHandler; + private IEventClientManager mEventClientManager; + private int mPlayStatus = PlayStatus.UNKNOWN; + private int mPlayListId = -1; + private int mLastPosition = -1; + + public NowPlayingController(NowPlayingActivity activity, Handler handler) { + super.onCreate(activity, handler); + mNowPlayingActivity = activity; + mControlManager = ManagerFactory.getControlManager(this); + mEventClientManager = ManagerFactory.getEventClientManager(this); + mNowPlayingHandler = new Handler(this); + } + + /** + * This is called from the thread with a message containing updated + * info of what's currently playing. + * + * @param msg Message object containing currently playing info + */ + public synchronized boolean handleMessage(Message msg) { + + final Bundle data = msg.getData(); + final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying) data.getSerializable(NowPlayingPollerThread + .BUNDLE_CURRENTLY_PLAYING); + + switch (msg.what) { + case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: + mPlayStatus = currentlyPlaying.getPlayStatus(); + mNowPlayingActivity.setProgressPosition(Math.round(currentlyPlaying.getPercentage())); + if (mPlayStatus == PlayStatus.PAUSED || mPlayStatus == PlayStatus.PLAYING) { + mNowPlayingActivity.updateProgress(currentlyPlaying.getDuration(), currentlyPlaying.getTime(), + (mPlayStatus == PlayStatus.PAUSED)); + } else { + mNowPlayingActivity.clear(); + } + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: + mNowPlayingActivity.updateInfo(currentlyPlaying.getTitle(), currentlyPlaying.getArtist(), + currentlyPlaying.getAlbum()); + mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: + mPlayListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); + return true; + + case NowPlayingPollerThread.MESSAGE_COVER_CHANGED: + // TODO: FIX!! + mNowPlayingActivity.updateCover(ConnectionFactory.getNowPlayingPoller(mActivity).getNowPlayingCover(), + (currentlyPlaying != null) ? currentlyPlaying.getMediaType() : MediaType.UNKNOWN); + return true; + + case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: + mPlayStatus = PlayStatus.UNKNOWN; + Log.w(TAG, "Received connection error from poller!"); + return true; + + case NowPlayingPollerThread.MESSAGE_RECONFIGURE: + mPlayStatus = PlayStatus.UNKNOWN; + new Thread() { + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + ConnectionFactory.subscribeNowPlayingPollerThread(mActivity.getApplicationContext(), + mNowPlayingHandler); + } + }.start(); + return true; + default: + return false; + } + } + + public void enableSeekbar(SeekBar seekbar) { + seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { + if (fromUser && !seekBar.isInTouchMode()) + seek(progress); + } + + public void onStartTrackingTouch(SeekBar seekBar) { + + } + + public void onStopTrackingTouch(SeekBar seekBar) { + seek(seekBar.getProgress()); + } + }); + } + + public void disableSeekbar(SeekBar seekbar) { + seekbar.setOnSeekBarChangeListener(null); + } + + public void setupButtons(SeekBar seekbar, View prev, View stop, View playpause, View next, View playlist) { + + enableSeekbar(seekbar); + + // setup buttons + prev.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_SKIP_MINUS)); + stop.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_STOP)); + next.setOnClickListener(new OnRemoteAction(ButtonCodes.REMOTE_SKIP_PLUS)); + playpause.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + switch (mPlayStatus) { + case PlayStatus.PLAYING: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short) 0, + (byte) 0); + break; + case PlayStatus.PAUSED: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short) 0, + (byte) 0); + break; + case PlayStatus.STOPPED: + final DataResponse doNothing = new DataResponse(); + //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + // mActivity.getApplicationContext()); + mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); + break; + } + } + }); + + // playlist button + playlist.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mActivity.startActivity(new Intent(mActivity, PlaylistActivity.class)); + } + }); + } + + public void seek(int progress) { + mControlManager.seek(new DataResponse(), SeekType.absolute, progress, + mActivity.getApplicationContext()); + } + + public void onActivityPause() { + ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, + true); + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(final Activity activity) { + super.onActivityResume(activity); + new Thread("nowplaying-spawning") { + @Override + public void run() { + ConnectionFactory.subscribeNowPlayingPollerThread(activity.getApplicationContext(), + mNowPlayingHandler); + } + }.start(); + if (mControlManager != null) { + mControlManager.setController(this); + } + } + + /** + * Handles the push- release button code. Switches image of the pressed + * button, vibrates and executes command. + */ + private class OnRemoteAction implements OnClickListener { + private final String mAction; + + public OnRemoteAction(String action) { + mAction = action; + } + + public void onClick(View v) { + mEventClientManager.sendButton("R1", mAction, false, true, true, (short) 0, (byte) 0); + } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/PlaylistController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/PlaylistController.java similarity index 64% rename from src/org/xbmc/android/remote/presentation/controller/PlaylistController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/PlaylistController.java index f6ec90d9..6158502f 100644 --- a/src/org/xbmc/android/remote/presentation/controller/PlaylistController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/PlaylistController.java @@ -21,28 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; -import java.util.HashMap; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.business.NowPlayingPollerThread; -import org.xbmc.android.remote.presentation.activity.PlaylistActivity; -import org.xbmc.android.remote.presentation.widget.OneLabelItemView; -import org.xbmc.android.util.ConnectionFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; -import org.xbmc.api.info.PlayStatus; -import org.xbmc.api.object.INamedResource; -import org.xbmc.api.object.Song; -import org.xbmc.eventclient.ButtonCodes; -import org.xbmc.httpapi.client.MusicClient; -import org.xbmc.httpapi.client.VideoClient; - import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -64,73 +42,95 @@ import android.widget.ArrayAdapter; import android.widget.ListAdapter; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.business.NowPlayingPollerThread; +import org.xbmc.android.remote.presentation.activity.PlaylistActivity; +import org.xbmc.android.remote.presentation.widget.OneLabelItemView; +import org.xbmc.android.util.ConnectionFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.info.PlayStatus; +import org.xbmc.api.object.INamedResource; +import org.xbmc.api.object.Song; +import org.xbmc.eventclient.ButtonCodes; +import org.xbmc.httpapi.client.MusicClient; +import org.xbmc.httpapi.client.VideoClient; + +import java.util.ArrayList; +import java.util.HashMap; + public class PlaylistController extends ListController implements IController, Callback { - + public static final String TAG = "PlaylistLogic"; public static final int MUSIC_PLAYLIST_ID = 0; public static final int VIDEO_PLAYLIST_ID = 1; - + public static final int ITEM_CONTEXT_PLAY = 1; public static final int ITEM_CONTEXT_REMOVE = 2; - + public static final int MESSAGE_PLAYLIST_SIZE = 701; public static final String BUNDLE_PLAYLIST_SIZE = "playlist_size"; - + private static final long serialVersionUID = 755529227668553163L; + private static Bitmap sPlayingBitmap; + private static Bitmap mFallbackBitmapVideo; private PlaylistActivity mPlaylistActivity; private Handler mNowPlayingHandler; private ItemAdapter mItemAdapter; - private IControlManager mControlManager; private IMusicManager mMusicManager; private IVideoManager mVideoManager; private IEventClientManager mEventClient; - private int mPlayStatus = PlayStatus.UNKNOWN; private int mPlayListId = -1; private int mCurrentPosition = -1; private int mLastPosition = -1; - - private static Bitmap sPlayingBitmap; - private static Bitmap mFallbackBitmapVideo; - + public void onCreate(final PlaylistActivity activity, Handler handler, final AbsListView list) { - + mPlaylistActivity = activity; mMusicManager = ManagerFactory.getMusicManager(this); mVideoManager = ManagerFactory.getVideoManager(this); mControlManager = ManagerFactory.getControlManager(this); mEventClient = ManagerFactory.getEventClientManager(this); mNowPlayingHandler = new Handler(this); - + if (!isCreated()) { super.onCreate(activity, handler, list); - + activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_song_light); mFallbackBitmapVideo = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_video_light); sPlayingBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon_play); - + mControlManager.getPlaylistId(new DataResponse() { public void run() { mPlayListId = value; - + updatePlaylist(); } - }, mActivity.getApplicationContext()); - + }, mActivity.getApplicationContext()); + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - final PlaylistItem item = (PlaylistItem)mList.getAdapter().getItem(((OneLabelItemView)view).position); + final PlaylistItem item = (PlaylistItem) mList.getAdapter().getItem(((OneLabelItemView) view) + .position); final DataResponse doNothing = new DataResponse(); - //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mActivity.getApplicationContext()); + //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + // mActivity.getApplicationContext()); switch (mPlayListId) { - case MUSIC_PLAYLIST_ID: - mMusicManager.setPlaylistSong(doNothing, item.position, mActivity.getApplicationContext()); - break; - case VIDEO_PLAYLIST_ID: - mVideoManager.setPlaylistVideo(doNothing, item.position, mActivity.getApplicationContext()); - break; + case MUSIC_PLAYLIST_ID: + mMusicManager.setPlaylistSong(doNothing, item.position, mActivity.getApplicationContext()); + break; + case VIDEO_PLAYLIST_ID: + mVideoManager.setPlaylistVideo(doNothing, item.position, mActivity.getApplicationContext + ()); + break; } } }); @@ -138,124 +138,127 @@ public void onItemClick(AdapterView parent, View view, int position, long id) setTitle("Playlist..."); } } - + private void updatePlaylist() { switch (mPlayListId) { - case MUSIC_PLAYLIST_ID: - mMusicManager.getPlaylistPosition(new DataResponse() { - public void run() { - mCurrentPosition = value; - } - }, mActivity.getApplicationContext()); - - mMusicManager.getPlaylist(new DataResponse>() { - public void run() { - if (value.size() > 0) { - final ArrayList items = new ArrayList(); - int i = 0; - for (String path : value) { - items.add(new PlaylistItem(path, i++)); - } - setTitle("Music playlist (" + (value.size() > MusicClient.PLAYLIST_LIMIT ? MusicClient.PLAYLIST_LIMIT + "+" : value.size()) + ")" ); - mItemAdapter = new ItemAdapter(mPlaylistActivity, items); - ((AdapterView) mList).setAdapter(mItemAdapter); - if (mCurrentPosition >= 0) { - mList.setSelection(mCurrentPosition); - } - } else { - setTitle("Music playlist"); - setNoDataMessage("No tracks in playlist.", R.drawable.icon_playlist_dark); + case MUSIC_PLAYLIST_ID: + mMusicManager.getPlaylistPosition(new DataResponse() { + public void run() { + mCurrentPosition = value; } + }, mActivity.getApplicationContext()); - } - }, mActivity.getApplicationContext()); - break; - case VIDEO_PLAYLIST_ID: - mVideoManager.getPlaylistPosition(new DataResponse() { - public void run() { - mCurrentPosition = value; - } - }, mActivity.getApplicationContext()); - - mVideoManager.getPlaylist(new DataResponse>() { - public void run() { - if (value.size() > 0) { - final ArrayList items = new ArrayList(); - int i = 0; - for (String path : value) { - items.add(new PlaylistItem(path, i++)); + mMusicManager.getPlaylist(new DataResponse>() { + public void run() { + if (value.size() > 0) { + final ArrayList items = new ArrayList(); + int i = 0; + for (String path : value) { + items.add(new PlaylistItem(path, i++)); + } + setTitle("Music playlist (" + (value.size() > MusicClient.PLAYLIST_LIMIT ? MusicClient + .PLAYLIST_LIMIT + "+" : value.size()) + ")"); + mItemAdapter = new ItemAdapter(mPlaylistActivity, items); + ((AdapterView) mList).setAdapter(mItemAdapter); + if (mCurrentPosition >= 0) { + mList.setSelection(mCurrentPosition); + } + } else { + setTitle("Music playlist"); + setNoDataMessage("No tracks in playlist.", R.drawable.icon_playlist_dark); } - setTitle("Video playlist (" + (value.size() > VideoClient.PLAYLIST_LIMIT ? VideoClient.PLAYLIST_LIMIT + "+" : value.size()) + ")" ); - mItemAdapter = new ItemAdapter(mPlaylistActivity, items); - ((AdapterView) mList).setAdapter(mItemAdapter); - if (mCurrentPosition >= 0) { - mList.setSelection(mCurrentPosition); - } - } else { - setTitle("Video playlist"); - setNoDataMessage("No videos in playlist.", R.drawable.icon_playlist_dark); + } + }, mActivity.getApplicationContext()); + break; + case VIDEO_PLAYLIST_ID: + mVideoManager.getPlaylistPosition(new DataResponse() { + public void run() { + mCurrentPosition = value; + } + }, mActivity.getApplicationContext()); + + mVideoManager.getPlaylist(new DataResponse>() { + public void run() { + if (value.size() > 0) { + final ArrayList items = new ArrayList(); + int i = 0; + for (String path : value) { + items.add(new PlaylistItem(path, i++)); + } + setTitle("Video playlist (" + (value.size() > VideoClient.PLAYLIST_LIMIT ? VideoClient + .PLAYLIST_LIMIT + "+" : value.size()) + ")"); + mItemAdapter = new ItemAdapter(mPlaylistActivity, items); + ((AdapterView) mList).setAdapter(mItemAdapter); + if (mCurrentPosition >= 0) { + mList.setSelection(mCurrentPosition); + } + } else { + setTitle("Video playlist"); + setNoDataMessage("No videos in playlist.", R.drawable.icon_playlist_dark); + } - } - }, mActivity.getApplicationContext()); - break; - default: - setTitle("Music playlist"); - setNoDataMessage("No tracks in playlist.", R.drawable.icon_playlist_dark); - break; + } + }, mActivity.getApplicationContext()); + break; + default: + setTitle("Music playlist"); + setNoDataMessage("No tracks in playlist.", R.drawable.icon_playlist_dark); + break; } } /** * This is called from the thread with a message containing updated info of * what's currently playing. - * - * @param msg - * Message object containing currently playing info + * + * @param msg Message object containing currently playing info */ public synchronized boolean handleMessage(Message msg) { final Bundle data = msg.getData(); - final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying) data.getSerializable(NowPlayingPollerThread.BUNDLE_CURRENTLY_PLAYING); + final ICurrentlyPlaying currentlyPlaying = (ICurrentlyPlaying) data.getSerializable(NowPlayingPollerThread + .BUNDLE_CURRENTLY_PLAYING); switch (msg.what) { - case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: - mPlayStatus = currentlyPlaying.getPlayStatus(); - if (currentlyPlaying.isPlaying()) { - mPlaylistActivity.setTime(Song.getDuration(currentlyPlaying.getTime() + 1)); - } else { - mPlaylistActivity.clear(); - } - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: - mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); - onItemChanged(currentlyPlaying); - return true; - - case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: - final int playListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); - if (playListId != mPlayListId) { - // music <-> video playlist changed - mPlayListId = playListId; - - updatePlaylist(); - } - return true; - - case MESSAGE_PLAYLIST_SIZE: - final int size = msg.getData().getInt(BUNDLE_PLAYLIST_SIZE); - mPlaylistActivity.setNumItems(size == 0 ? "empty" : size + (mPlayListId == VIDEO_PLAYLIST_ID ? " videos" : " tracks")); - return true; - - case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: - case NowPlayingPollerThread.MESSAGE_RECONFIGURE: - mPlayStatus = PlayStatus.UNKNOWN; - return true; - - default: - return false; + case NowPlayingPollerThread.MESSAGE_PROGRESS_CHANGED: + mPlayStatus = currentlyPlaying.getPlayStatus(); + if (currentlyPlaying.isPlaying()) { + mPlaylistActivity.setTime(Song.getDuration(currentlyPlaying.getTime() + 1)); + } else { + mPlaylistActivity.clear(); + } + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: + mLastPosition = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYPOSITION); + onItemChanged(currentlyPlaying); + return true; + + case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: + final int playListId = data.getInt(NowPlayingPollerThread.BUNDLE_LAST_PLAYLIST); + if (playListId != mPlayListId) { + // music <-> video playlist changed + mPlayListId = playListId; + + updatePlaylist(); + } + return true; + + case MESSAGE_PLAYLIST_SIZE: + final int size = msg.getData().getInt(BUNDLE_PLAYLIST_SIZE); + mPlaylistActivity.setNumItems(size == 0 ? "empty" : size + (mPlayListId == VIDEO_PLAYLIST_ID ? " " + + "videos" : " tracks")); + return true; + + case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: + case NowPlayingPollerThread.MESSAGE_RECONFIGURE: + mPlayStatus = PlayStatus.UNKNOWN; + return true; + + default: + return false; } } - + public void setupButtons(View prev, View stop, View playpause, View next) { // setup buttons @@ -266,56 +269,47 @@ public void setupButtons(View prev, View stop, View playpause, View next) { public void onClick(View v) { switch (mPlayStatus) { case PlayStatus.PLAYING: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short)0, (byte)0); + mEventClient.sendButton("R1", ButtonCodes.REMOTE_PAUSE, false, true, true, (short) 0, + (byte) 0); break; case PlayStatus.PAUSED: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short)0, (byte)0); + mEventClient.sendButton("R1", ButtonCodes.REMOTE_PLAY, false, true, true, (short) 0, (byte) 0); break; case PlayStatus.STOPPED: final DataResponse doNothing = new DataResponse(); - //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mActivity.getApplicationContext()); - mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); + //mControlManager.setPlaylistId(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + // mActivity.getApplicationContext()); + mControlManager.setPlaylistPos(doNothing, mPlayListId < 0 ? 0 : mPlayListId, + mLastPosition < 0 ? 0 : mLastPosition, mActivity.getApplicationContext()); break; } } }); } - - - /** - * Handles the push- release button code. Switches image of the pressed - * button, vibrates and executes command. - */ - private class OnRemoteAction implements OnClickListener { - private final String mAction; - - public OnRemoteAction(String action) { - mAction = action; - } - public void onClick(View v) { - mEventClient.sendButton("R1", mAction, false, true, true, (short) 0, (byte) 0); - } - } - public void onItemChanged(ICurrentlyPlaying newItem) { final ItemAdapter adapter = mItemAdapter; if (adapter != null) { final int currentPos = mCurrentPosition; final int newPos = newItem.getPlaylistPosition(); - + // clear previous item's icon OneLabelItemView view = adapter.getViewAtPosition(currentPos); if (currentPos >= 0 && view != null) { switch (mPlayListId) { - case MUSIC_PLAYLIST_ID: view.setCover(BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.icon_song_light)); break; - case VIDEO_PLAYLIST_ID: view.setCover(BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.icon_video)); break; - } + case MUSIC_PLAYLIST_ID: + view.setCover(BitmapFactory.decodeResource(mActivity.getResources(), + R.drawable.icon_song_light)); + break; + case VIDEO_PLAYLIST_ID: + view.setCover(BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.icon_video)); + break; + } Log.i(TAG, "Resetting previous icon at position " + currentPos + " (" + view.title + ")"); } else { Log.i(TAG, "NOT resetting previous icon at position " + currentPos); } - + // set new item's play icon view = adapter.getViewAtPosition(newPos); mCurrentPosition = newPos; @@ -326,107 +320,54 @@ public void onItemChanged(ICurrentlyPlaying newItem) { } } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! -/* final OneHolderholder = (OneHolder)((AdapterContextMenuInfo)menuInfo).targetView.getTag(); +/* final OneHolderholder = (OneHolder)((AdapterContextMenuInfo)menuInfo).targetView +.getTag(); menu.setHeaderTitle(holder.holderItem.filename); menu.add(0, ITEM_CONTEXT_PLAY, 1, "Play"); menu.add(0, ITEM_CONTEXT_REMOVE, 2, "Remove");*/ } - + public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final PlaylistItem playlistItem = (PlaylistItem)mList.getAdapter().getItem(((OneLabelItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final PlaylistItem playlistItem = (PlaylistItem) mList.getAdapter().getItem(((OneLabelItemView) ( + (AdapterContextMenuInfo) item.getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_PLAY: switch (mPlayListId) { - case MUSIC_PLAYLIST_ID: - mMusicManager.setPlaylistSong(new DataResponse(), playlistItem.position, mActivity.getApplicationContext()); - break; - case VIDEO_PLAYLIST_ID: - mVideoManager.setPlaylistVideo(new DataResponse(), playlistItem.position, mActivity.getApplicationContext()); - break; + case MUSIC_PLAYLIST_ID: + mMusicManager.setPlaylistSong(new DataResponse(), playlistItem.position, + mActivity.getApplicationContext()); + break; + case VIDEO_PLAYLIST_ID: + mVideoManager.setPlaylistVideo(new DataResponse(), playlistItem.position, + mActivity.getApplicationContext()); + break; } break; case ITEM_CONTEXT_REMOVE: switch (mPlayListId) { - case MUSIC_PLAYLIST_ID: - mMusicManager.removeFromPlaylist(new DataResponse(), playlistItem.path, mActivity.getApplicationContext()); - break; - case VIDEO_PLAYLIST_ID: - mVideoManager.removeFromPlaylist(new DataResponse(), playlistItem.path, mActivity.getApplicationContext()); - break; - } + case MUSIC_PLAYLIST_ID: + mMusicManager.removeFromPlaylist(new DataResponse(), playlistItem.path, + mActivity.getApplicationContext()); + break; + case VIDEO_PLAYLIST_ID: + mVideoManager.removeFromPlaylist(new DataResponse(), playlistItem.path, + mActivity.getApplicationContext()); + break; + } break; default: return; } } - - private class ItemAdapter extends ArrayAdapter { - private final HashMap mItemPositions = new HashMap(); - ItemAdapter(Activity activity, ArrayList items) { - super(activity, 0, items); - Handler handler = mNowPlayingHandler; - if (handler != null) { - Message msg = Message.obtain(); - Bundle bundle = msg.getData(); - bundle.putInt(BUNDLE_PLAYLIST_SIZE, items.size()); - msg.what = MESSAGE_PLAYLIST_SIZE; - handler.sendMessage(msg); - } - } - public View getView(int position, View convertView, ViewGroup parent) { - final OneLabelItemView view; - if (convertView == null) { - view = new OneLabelItemView(mActivity, parent.getWidth(), getFallbackBitmap(), mList.getSelector(), true); - } else { - view = (OneLabelItemView)convertView; - mItemPositions.remove(view.position); - } - final PlaylistItem item = this.getItem(position); - view.reset(); - view.position = position; - view.title = item.filename; - if (position == mCurrentPosition) { - view.setCover(sPlayingBitmap); - } else { - view.setCover(getFallbackBitmap()); - } - mItemPositions.put(view.position, view); - return view; - } - - public OneLabelItemView getViewAtPosition(int position) { - if (mItemPositions.containsKey(position)) { - return mItemPositions.get(position); - } - return null; - } - - private Bitmap getFallbackBitmap() { - return (mPlayListId == VIDEO_PLAYLIST_ID) ? mFallbackBitmapVideo : mFallbackBitmap; - } - } - - private static class PlaylistItem implements INamedResource{ - public final String path; - public final String filename; - public final int position; - public PlaylistItem(String path, int position) { - this.path = path; - this.filename = path.substring(path.replaceAll("\\\\", "/").lastIndexOf('/') + 1); - this.position = position; - } - public String getShortName() { - return filename; - } - } - + public void onActivityPause() { - ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, true); + ConnectionFactory.unSubscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler, + true); if (mMusicManager != null) { mMusicManager.setController(null); mMusicManager.postActivity(); @@ -449,10 +390,11 @@ public void onActivityResume(final Activity activity) { new Thread("playlist-spawning") { @Override public void run() { - ConnectionFactory.subscribeNowPlayingPollerThread(mActivity.getApplicationContext(), mNowPlayingHandler); + ConnectionFactory.subscribeNowPlayingPollerThread(mActivity.getApplicationContext(), + mNowPlayingHandler); } }.start(); - + if (mEventClient != null) { mEventClient.setController(this); } @@ -466,6 +408,85 @@ public void run() { mControlManager.setController(this); } } - - private static final long serialVersionUID = 755529227668553163L; + + private static class PlaylistItem implements INamedResource { + public final String path; + public final String filename; + public final int position; + + public PlaylistItem(String path, int position) { + this.path = path; + this.filename = path.substring(path.replaceAll("\\\\", "/").lastIndexOf('/') + 1); + this.position = position; + } + + public String getShortName() { + return filename; + } + } + + /** + * Handles the push- release button code. Switches image of the pressed + * button, vibrates and executes command. + */ + private class OnRemoteAction implements OnClickListener { + private final String mAction; + + public OnRemoteAction(String action) { + mAction = action; + } + + public void onClick(View v) { + mEventClient.sendButton("R1", mAction, false, true, true, (short) 0, (byte) 0); + } + } + + private class ItemAdapter extends ArrayAdapter { + private final HashMap mItemPositions = new HashMap(); + + ItemAdapter(Activity activity, ArrayList items) { + super(activity, 0, items); + Handler handler = mNowPlayingHandler; + if (handler != null) { + Message msg = Message.obtain(); + Bundle bundle = msg.getData(); + bundle.putInt(BUNDLE_PLAYLIST_SIZE, items.size()); + msg.what = MESSAGE_PLAYLIST_SIZE; + handler.sendMessage(msg); + } + } + + public View getView(int position, View convertView, ViewGroup parent) { + final OneLabelItemView view; + if (convertView == null) { + view = new OneLabelItemView(mActivity, parent.getWidth(), getFallbackBitmap(), mList.getSelector(), + true); + } else { + view = (OneLabelItemView) convertView; + mItemPositions.remove(view.position); + } + final PlaylistItem item = this.getItem(position); + view.reset(); + view.position = position; + view.title = item.filename; + if (position == mCurrentPosition) { + view.setCover(sPlayingBitmap); + } else { + view.setCover(getFallbackBitmap()); + } + mItemPositions.put(view.position, view); + return view; + } + + public OneLabelItemView getViewAtPosition(int position) { + if (mItemPositions.containsKey(position)) { + return mItemPositions.get(position); + } + return null; + } + + private Bitmap getFallbackBitmap() { + return (mPlayListId == VIDEO_PLAYLIST_ID) ? mFallbackBitmapVideo : mFallbackBitmap; + } + } } diff --git a/src/org/xbmc/android/remote/presentation/controller/RemoteController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/RemoteController.java similarity index 73% rename from src/org/xbmc/android/remote/presentation/controller/RemoteController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/RemoteController.java index 7130d594..e8042118 100644 --- a/src/org/xbmc/android/remote/presentation/controller/RemoteController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/RemoteController.java @@ -1,537 +1,569 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import java.util.Timer; -import java.util.TimerTask; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.GestureRemoteActivity; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.widget.gestureremote.IGestureListener; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.info.GuiSettings; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.eventclient.ButtonCodes; - -import android.app.Activity; -import android.app.Dialog; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.media.AudioManager; -import android.os.Handler; -import android.os.Vibrator; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnTouchListener; -import android.widget.Button; -import android.widget.EditText; - -public class RemoteController extends AbstractController implements INotifiableController, IController { - - public static final int LAST_REMOTE_BUTTON = 0; - public static final int LAST_REMOTE_GESTURE = 1; - public static final String LAST_REMOTE_PREFNAME = "last_remote_type"; - - private static final int MENU_NOW_PLAYING = 401; - private static final int MENU_XBMC_EXIT = 402; - private static final int MENU_XBMC_S = 403; -// private static final int MENU_SWITCH_MOUSE = 404; - private static final int MENU_SWITCH_GESTURE = 405; - private static final int MENU_ENTER_TEXT = 406; - - public static final int DIALOG_SENDTEXT = 500; - - private static final int DPAD_DOWN_MIN_DELTA_TIME = 100; - private static final int MOTION_EVENT_MIN_DELTA_TIME = 250; - private static final float MOTION_EVENT_MIN_DELTA_POSITION = 0.15f; - - private static final long VIBRATION_LENGTH = 45; - - IEventClientManager mEventClientManager; - IInfoManager mInfoManager; - IControlManager mControl; - GestureThread mGestureThread; - - /** - * timestamp since last trackball use. - */ - private long mTimestamp = 0; - private final Vibrator mVibrator; - private final boolean mDoVibrate; - - private int mEventServerInitialDelay = 750; - - private static Timer tmrKeyPress = new Timer(); - private static String currKeyAction = ""; - private static KeyPressTask currKeyTask = null; - - - final SharedPreferences prefs; - - public RemoteController(Context context) { - prefs = PreferenceManager.getDefaultSharedPreferences(context); - - mControl = ManagerFactory.getControlManager(this); - mInfoManager = ManagerFactory.getInfoManager(this); - mEventClientManager = ManagerFactory.getEventClientManager(this); - mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - mDoVibrate = prefs.getBoolean("setting_vibrate_on_touch", true); - mInfoManager.getGuiSettingInt(new DataResponse() { -// @Override -// public void run() { -// mHandler.post(new Runnable() { -// public void run() { -// mEventServerInitialDelay = value; -// Log.i("RemoteController", "Saving previous value " + GuiSettings.getName(GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY) + " = " + value); -// } -// }); -// } - }, GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, context); - - if(currKeyTask != null){ - currKeyTask.cancel(); - currKeyTask = null; - } - if(currKeyAction != null){ - mEventClientManager.sendButton("R1", currKeyAction, false, false, true, (short)0, (byte)0); - currKeyAction = ""; - } - } - - public IGestureListener startGestureThread(final Context context) { - mGestureThread = new GestureThread(mEventClientManager); - IGestureListener listener = new IGestureListener() { - private boolean mScrolling = false; - public double[] getZones() { - double[] ret = { 0.13, 0.25, 0.5, 0.75 }; - return ret; - } - public void onHorizontalMove(int value) { - Log.d(TAG, "onHorizontalMove(" + value + ")"); - if (value == 0) { - if (mGestureThread != null) { - mGestureThread.quit(); - mGestureThread = null; - } - } else { - if (mGestureThread == null) { - mGestureThread = new GestureThread(mEventClientManager); - } - mGestureThread.setLevel(value, value > 0 ? GestureThread.ACTION_RIGHT : GestureThread.ACTION_LEFT); - } - } - public void onVerticalMove(int value) { - Log.d(TAG, "onVerticalMove(" + value + ")"); - if (value == 0) { - if (mGestureThread != null) { - mGestureThread.quit(); - mGestureThread = null; - } - } else { - if (mGestureThread == null) { - mGestureThread = new GestureThread(mEventClientManager); - } - mGestureThread.setLevel(value, value > 0 ? GestureThread.ACTION_DOWN : GestureThread.ACTION_UP); - } - } - private void scroll(String button, double amount) { - if (amount != 0) { - if (!mScrolling) { - Log.i(TAG, "Setting " + GuiSettings.getName(GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY) + " = " + 25); - mInfoManager.setGuiSettingInt(new DataResponse(), GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, 25, context); - } - mEventClientManager.sendButton("XG", button, true, true, false, (short)(amount * 65535), (byte)0); - mScrolling = true; - } else { - mEventClientManager.sendButton("XG", button, false, false, false, (short)0, (byte)0); - Log.i(TAG, "Restoring " + GuiSettings.getName(GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY) + " = " + mEventServerInitialDelay); - mInfoManager.setGuiSettingInt(new DataResponse(), GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, mEventServerInitialDelay, context); - mScrolling = false; - } - } - - public void onScrollDown(double amount) { - Log.d(TAG, "onScrollDown(" + amount + ")"); - scroll(ButtonCodes.GAMEPAD_RIGHT_ANALOG_TRIGGER, amount); - } - public void onScrollUp(double amount) { - Log.d(TAG, "onScrollUp(" + amount + ")"); - scroll(ButtonCodes.GAMEPAD_LEFT_ANALOG_TRIGGER, amount); - } - public void onSelect() { - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_SELECT, false, true, false, (short)0, (byte)0); - } - public void onScrollDown() { - Log.d(TAG, "onScrollDown()"); - mEventClientManager.sendButton("KB", ButtonCodes.KEYBOARD_PAGEDOWN, false, true, true, (short)0, (byte)0); - } - public void onScrollUp() { - Log.d(TAG, "onScrollUp()"); - mEventClientManager.sendButton("KB", ButtonCodes.KEYBOARD_PAGEUP, false, true, true, (short)0, (byte)0); - } - public void onBack() { - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_BACK, false, true, true, (short)0, (byte)0); - } - public void onInfo() { - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_INFO, false, true, true, (short)0, (byte)0); - } - public void onMenu() { - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_MENU, false, true, true, (short)0, (byte)0); - } - public void onTitle() { - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_TITLE, false, true, true, (short)0, (byte)0); - } - }; - return listener; - } - - private static class GestureThread extends Thread { - public static final int ACTION_UP = 1; - public static final int ACTION_RIGHT = 2; - public static final int ACTION_DOWN = 3; - public static final int ACTION_LEFT = 4; - private final IEventClientManager mEventClient; - private boolean mQuit = false; - private int mLevel = 0; - private int[] mSpeed = { 0, 800, 400, 200, 100, 50, 0 }; - private int mAction = 0; - public GestureThread(IEventClientManager eventClient) { - super("RemoteController.GestureThread"); - mEventClient = eventClient; - } - @Override - public void run() { - Log.i("GestureThread", "STARTING..."); - while (!mQuit) { - try { - switch (mAction) { - case ACTION_UP: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short)0, (byte)0); - break; - case ACTION_RIGHT: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short)0, (byte)0); - break; - case ACTION_DOWN: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short)0, (byte)0); - break; - case ACTION_LEFT: - mEventClient.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short)0, (byte)0); - break; - } -// Log.i("GestureThread", "action: " + mAction); - Thread.sleep(mSpeed[Math.abs(mLevel)]); - } catch (InterruptedException e) { - mQuit = true; - } - - } - } - public synchronized void setLevel(int level, int action) { - mLevel = level; - mAction = action; - if (!isAlive()) { - start(); - } - } - public synchronized void quit() { - Log.i("GestureThread", "QUITTING."); - mQuit = true; - } - } - - public void showVolume() { - } - - public boolean onKeyDown(int keyCode, KeyEvent event) { - char key = (char)event.getUnicodeChar(); - if (key > 'A' && key < 'z') { - return keyboardAction("" + key); - } - switch (keyCode) { - case KeyEvent.KEYCODE_VOLUME_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_VOLUME_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_DOWN: - return onDirectionalPadDown(keyCode); - case KeyEvent.KEYCODE_DPAD_UP: - return onDirectionalPadDown(keyCode); - case KeyEvent.KEYCODE_DPAD_LEFT: - return onDirectionalPadDown(keyCode); - case KeyEvent.KEYCODE_DPAD_RIGHT: - return onDirectionalPadDown(keyCode); - case KeyEvent.KEYCODE_DPAD_CENTER: - return onDirectionalPadDown(keyCode); - default: - return false; - } - } - - private boolean onDirectionalPadDown(int keyCode){ - long newstamp = System.currentTimeMillis(); - if (newstamp - mTimestamp > DPAD_DOWN_MIN_DELTA_TIME){ - mTimestamp = newstamp; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_DOWN: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_UP: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_LEFT: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_RIGHT: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short)0, (byte)0); - return true; - case KeyEvent.KEYCODE_DPAD_CENTER: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_ENTER, false, true, true, (short)0, (byte)0); - return true; - default: - return false; - } - } - return true; - } - - public boolean onTrackballEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) - return keyboardAction(ButtonCodes.KEYBOARD_ENTER); - else{ - // check when the last trackball move happened to avoid too speedy selections - long newstamp = System.currentTimeMillis(); - if (newstamp - mTimestamp > MOTION_EVENT_MIN_DELTA_TIME){ - mTimestamp = newstamp; - if (Math.abs(event.getX()) > MOTION_EVENT_MIN_DELTA_POSITION) { - return keyboardAction(event.getX() < 0 ? ButtonCodes.KEYBOARD_LEFT : ButtonCodes.KEYBOARD_RIGHT); - } else if (Math.abs(event.getY()) > MOTION_EVENT_MIN_DELTA_POSITION){ - return keyboardAction(event.getY() < 0 ? ButtonCodes.KEYBOARD_UP : ButtonCodes.KEYBOARD_DOWN); - } - } - } - return true; - } - - public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); - menu.add(0, MENU_SWITCH_GESTURE, 0, "Gesture mode").setIcon(R.drawable.menu_gesture_mode); - menu.add(0, MENU_ENTER_TEXT, 0, "Text Entry").setIcon(R.drawable.menu_text_entry); - menu.add(0, MENU_XBMC_EXIT, 0, "Exit XBMC").setIcon(R.drawable.menu_xbmc_exit); - menu.add(0, MENU_XBMC_S, 0, "Press \"S\"").setIcon(R.drawable.menu_xbmc_s); - return true; - } - - // Need Context passed in because this can be called at times when mActivity is null. - public Dialog onCreateDialog(int id, final Context context) { - Dialog dialog; - switch(id) { - case DIALOG_SENDTEXT: - dialog = new Dialog(context); - dialog.setContentView(R.layout.sendtext); - dialog.setTitle("Text Entry"); - Button sendbutton = (Button) dialog.findViewById(R.id.sendtext_button_send); - sendbutton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - EditText text = (EditText) v.getRootView().findViewById(R.id.sendtext_text); - mControl.sendText(new DataResponse(), text.getText().toString(), context); - text.setText(""); - } - }); - Button donebutton = (Button) dialog.findViewById(R.id.sendtext_button_done); - donebutton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - EditText text = (EditText) v.getRootView().findViewById(R.id.sendtext_text); - mControl.sendText(new DataResponse(), text.getText().toString()+"\n", context); - dismissDialog(DIALOG_SENDTEXT); - } - }); - Button cancelbutton = (Button) dialog.findViewById(R.id.sendtext_button_cancel); - cancelbutton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - dismissDialog(DIALOG_SENDTEXT); - } - }); - break; - default: - dialog = null; - } - return dialog; - } - - public void onPrepareDialog (int id, Dialog dialog) { - EditText text = (EditText) dialog.findViewById(R.id.sendtext_text); - text.setText(""); - } - - public boolean onOptionsItemSelected(MenuItem item) { - Intent intent = null; - switch (item.getItemId()) { - case MENU_NOW_PLAYING: - intent = new Intent(mActivity, NowPlayingActivity.class); - break; - case MENU_SWITCH_GESTURE: - intent = new Intent(mActivity, GestureRemoteActivity.class); - intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); - break; - case MENU_XBMC_EXIT: - mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_POWER, false, true, true, (short)0, (byte)0); - break; - case MENU_XBMC_S: - mEventClientManager.sendButton("KB", "S", false, true, true, (short)0, (byte)0); - break; - case MENU_ENTER_TEXT: - showDialog(DIALOG_SENDTEXT); - break; - } - if (intent != null) { - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mActivity.startActivity(intent); - return true; - } - return true; - } - - /** - * Sends a keyboard event - * @param button - * @return - */ - private boolean keyboardAction(String button) { - mEventClientManager.sendButton("KB", button, false, true, true, (short)0, (byte)0); - return true; - } - - /** - * Shortcut for adding the listener class to the button - * @param resourceButton Resource ID of the button - * @param action Action string - * @param resourceButtonUp Resource ID of the button up image - * @param resourceButtonDown Resource ID of the button down image - */ - public void setupButton(View btn, String action) { - if (btn != null) { - btn.setOnTouchListener(new OnRemoteAction(action)); - ((Button)btn).setSoundEffectsEnabled(true); - ((Button)btn).setClickable(true); - } - } - - /** - * Handles the push- release button code. Switches image of the pressed - * button, vibrates and executes command. - */ - private class OnRemoteAction implements OnTouchListener { - private final String mAction; - public OnRemoteAction(String action) { - mAction = action; - } - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - Log.d(TAG, "onTouch - ACTION_DOWN"); - if (mDoVibrate) { - mVibrator.vibrate(VIBRATION_LENGTH); - } - - if(currKeyTask != null){ - currKeyTask.cancel(); - } - if(currKeyAction != ""){ - mEventClientManager.sendButton("R1", mAction, false, false, true, (short)0, (byte)0); - } - mEventClientManager.sendButton("R1", mAction, !prefs.getBoolean("setting_send_repeats", false), true, true, (short)0, (byte)0); - currKeyAction = mAction; - - if (prefs.getBoolean("setting_send_repeats", false) && !prefs.getBoolean("setting_send_single_click", false)) { - int RepeatDelay = Integer.parseInt(prefs.getString("setting_repeat_rate", "250")); - - currKeyTask = new KeyPressTask(mAction); - tmrKeyPress.schedule(currKeyTask, RepeatDelay, RepeatDelay); - } - - - } else if (event.getAction() == MotionEvent.ACTION_UP) { - Log.d(TAG, "onTouch - ACTION_UP"); - v.playSoundEffect(AudioManager.FX_KEY_CLICK); - - if(currKeyTask != null){ - currKeyTask.cancel(); - currKeyTask = null; - } - - mEventClientManager.sendButton("R1", mAction, false, false, true, (short)0, (byte)0); - currKeyAction = ""; - } - return false; - } - } - - private class KeyPressTask extends TimerTask { - - private String mKeyPressAction = ""; - - public KeyPressTask(String mAction) { - mKeyPressAction = mAction; - } - - public void run() { - if (mKeyPressAction.length() > 0){ - mEventClientManager.sendButton("R1", mKeyPressAction, false, true, true, (short)0, (byte)0); - - } - } - } - - public void onActivityPause() { - mEventClientManager.setController(null); - mInfoManager.setController(null); - if (mGestureThread != null) { - mGestureThread.quit(); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - mHandler = new Handler(); - mEventClientManager.setController(this); - mInfoManager.setController(this); - } - - public void sendButton(String buttonCode){ - mEventClientManager.sendButton("R1", buttonCode, false, true, false, (short)0, (byte)0); - } - +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.app.Dialog; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.os.Handler; +import android.os.Vibrator; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnTouchListener; +import android.widget.Button; +import android.widget.EditText; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.GestureRemoteActivity; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.widget.gestureremote.IGestureListener; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.info.GuiSettings; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.eventclient.ButtonCodes; + +import java.util.Timer; +import java.util.TimerTask; + +public class RemoteController extends AbstractController implements INotifiableController, IController { + + public static final int LAST_REMOTE_BUTTON = 0; + public static final int LAST_REMOTE_GESTURE = 1; + public static final String LAST_REMOTE_PREFNAME = "last_remote_type"; + public static final int DIALOG_SENDTEXT = 500; + private static final int MENU_NOW_PLAYING = 401; + private static final int MENU_XBMC_EXIT = 402; + private static final int MENU_XBMC_S = 403; + // private static final int MENU_SWITCH_MOUSE = 404; + private static final int MENU_SWITCH_GESTURE = 405; + private static final int MENU_ENTER_TEXT = 406; + private static final int DPAD_DOWN_MIN_DELTA_TIME = 100; + private static final int MOTION_EVENT_MIN_DELTA_TIME = 250; + private static final float MOTION_EVENT_MIN_DELTA_POSITION = 0.15f; + + private static final long VIBRATION_LENGTH = 45; + private static Timer tmrKeyPress = new Timer(); + private static String currKeyAction = ""; + private static KeyPressTask currKeyTask = null; + final SharedPreferences prefs; + private final Vibrator mVibrator; + private final boolean mDoVibrate; + IEventClientManager mEventClientManager; + IInfoManager mInfoManager; + IControlManager mControl; + GestureThread mGestureThread; + /** + * timestamp since last trackball use. + */ + private long mTimestamp = 0; + private int mEventServerInitialDelay = 750; + + public RemoteController(Context context) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + + mControl = ManagerFactory.getControlManager(this); + mInfoManager = ManagerFactory.getInfoManager(this); + mEventClientManager = ManagerFactory.getEventClientManager(this); + mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); + mDoVibrate = prefs.getBoolean("setting_vibrate_on_touch", true); + mInfoManager.getGuiSettingInt(new DataResponse() { +// @Override +// public void run() { +// mHandler.post(new Runnable() { +// public void run() { +// mEventServerInitialDelay = value; +// Log.i("RemoteController", "Saving previous value " + GuiSettings.getName(GuiSettings.Services +// .EVENT_SERVER_INITIAL_DELAY) + " = " + value); +// } +// }); +// } + }, GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, context); + + if (currKeyTask != null) { + currKeyTask.cancel(); + currKeyTask = null; + } + if (currKeyAction != null) { + mEventClientManager.sendButton("R1", currKeyAction, false, false, true, (short) 0, (byte) 0); + currKeyAction = ""; + } + } + + public IGestureListener startGestureThread(final Context context) { + mGestureThread = new GestureThread(mEventClientManager); + IGestureListener listener = new IGestureListener() { + private boolean mScrolling = false; + + public double[] getZones() { + double[] ret = {0.13, 0.25, 0.5, 0.75}; + return ret; + } + + public void onHorizontalMove(int value) { + Log.d(TAG, "onHorizontalMove(" + value + ")"); + if (value == 0) { + if (mGestureThread != null) { + mGestureThread.quit(); + mGestureThread = null; + } + } else { + if (mGestureThread == null) { + mGestureThread = new GestureThread(mEventClientManager); + } + mGestureThread.setLevel(value, value > 0 ? GestureThread.ACTION_RIGHT : GestureThread.ACTION_LEFT); + } + } + + public void onVerticalMove(int value) { + Log.d(TAG, "onVerticalMove(" + value + ")"); + if (value == 0) { + if (mGestureThread != null) { + mGestureThread.quit(); + mGestureThread = null; + } + } else { + if (mGestureThread == null) { + mGestureThread = new GestureThread(mEventClientManager); + } + mGestureThread.setLevel(value, value > 0 ? GestureThread.ACTION_DOWN : GestureThread.ACTION_UP); + } + } + + private void scroll(String button, double amount) { + if (amount != 0) { + if (!mScrolling) { + Log.i(TAG, "Setting " + GuiSettings.getName(GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY) + + " = " + 25); + mInfoManager.setGuiSettingInt(new DataResponse(), + GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, 25, context); + } + mEventClientManager.sendButton("XG", button, true, true, false, (short) (amount * 65535), + (byte) 0); + mScrolling = true; + } else { + mEventClientManager.sendButton("XG", button, false, false, false, (short) 0, (byte) 0); + Log.i(TAG, "Restoring " + GuiSettings.getName(GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY) + + "" + + " = " + mEventServerInitialDelay); + mInfoManager.setGuiSettingInt(new DataResponse(), + GuiSettings.Services.EVENT_SERVER_INITIAL_DELAY, mEventServerInitialDelay, context); + mScrolling = false; + } + } + + public void onScrollDown(double amount) { + Log.d(TAG, "onScrollDown(" + amount + ")"); + scroll(ButtonCodes.GAMEPAD_RIGHT_ANALOG_TRIGGER, amount); + } + + public void onScrollUp(double amount) { + Log.d(TAG, "onScrollUp(" + amount + ")"); + scroll(ButtonCodes.GAMEPAD_LEFT_ANALOG_TRIGGER, amount); + } + + public void onSelect() { + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_SELECT, false, true, false, (short) 0, + (byte) 0); + } + + public void onScrollDown() { + Log.d(TAG, "onScrollDown()"); + mEventClientManager.sendButton("KB", ButtonCodes.KEYBOARD_PAGEDOWN, false, true, true, (short) 0, + (byte) 0); + } + + public void onScrollUp() { + Log.d(TAG, "onScrollUp()"); + mEventClientManager.sendButton("KB", ButtonCodes.KEYBOARD_PAGEUP, false, true, true, (short) 0, + (byte) 0); + } + + public void onBack() { + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_BACK, false, true, true, (short) 0, (byte) 0); + } + + public void onInfo() { + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_INFO, false, true, true, (short) 0, (byte) 0); + } + + public void onMenu() { + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_MENU, false, true, true, (short) 0, (byte) 0); + } + + public void onTitle() { + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_TITLE, false, true, true, (short) 0, (byte) 0); + } + }; + return listener; + } + + public void showVolume() { + } + + public boolean onKeyDown(int keyCode, KeyEvent event) { + char key = (char) event.getUnicodeChar(); + if (key > 'A' && key < 'z') { + return keyboardAction("" + key); + } + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_PLUS, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_VOLUME_MINUS, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_DOWN: + return onDirectionalPadDown(keyCode); + case KeyEvent.KEYCODE_DPAD_UP: + return onDirectionalPadDown(keyCode); + case KeyEvent.KEYCODE_DPAD_LEFT: + return onDirectionalPadDown(keyCode); + case KeyEvent.KEYCODE_DPAD_RIGHT: + return onDirectionalPadDown(keyCode); + case KeyEvent.KEYCODE_DPAD_CENTER: + return onDirectionalPadDown(keyCode); + default: + return false; + } + } + + private boolean onDirectionalPadDown(int keyCode) { + long newstamp = System.currentTimeMillis(); + if (newstamp - mTimestamp > DPAD_DOWN_MIN_DELTA_TIME) { + mTimestamp = newstamp; + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_DOWN: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_UP: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_LEFT: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short) 0, + (byte) 0); + return true; + case KeyEvent.KEYCODE_DPAD_CENTER: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_ENTER, false, true, true, (short) 0, + (byte) 0); + return true; + default: + return false; + } + } + return true; + } + + public boolean onTrackballEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) + return keyboardAction(ButtonCodes.KEYBOARD_ENTER); + else { + // check when the last trackball move happened to avoid too speedy selections + long newstamp = System.currentTimeMillis(); + if (newstamp - mTimestamp > MOTION_EVENT_MIN_DELTA_TIME) { + mTimestamp = newstamp; + if (Math.abs(event.getX()) > MOTION_EVENT_MIN_DELTA_POSITION) { + return keyboardAction(event.getX() < 0 ? ButtonCodes.KEYBOARD_LEFT : ButtonCodes.KEYBOARD_RIGHT); + } else if (Math.abs(event.getY()) > MOTION_EVENT_MIN_DELTA_POSITION) { + return keyboardAction(event.getY() < 0 ? ButtonCodes.KEYBOARD_UP : ButtonCodes.KEYBOARD_DOWN); + } + } + } + return true; + } + + public boolean onCreateOptionsMenu(Menu menu) { + menu.add(0, MENU_NOW_PLAYING, 0, "Now playing").setIcon(R.drawable.menu_nowplaying); + menu.add(0, MENU_SWITCH_GESTURE, 0, "Gesture mode").setIcon(R.drawable.menu_gesture_mode); + menu.add(0, MENU_ENTER_TEXT, 0, "Text Entry").setIcon(R.drawable.menu_text_entry); + menu.add(0, MENU_XBMC_EXIT, 0, "Exit XBMC").setIcon(R.drawable.menu_xbmc_exit); + menu.add(0, MENU_XBMC_S, 0, "Press \"S\"").setIcon(R.drawable.menu_xbmc_s); + return true; + } + + // Need Context passed in because this can be called at times when mActivity is null. + public Dialog onCreateDialog(int id, final Context context) { + Dialog dialog; + switch (id) { + case DIALOG_SENDTEXT: + dialog = new Dialog(context); + dialog.setContentView(R.layout.sendtext); + dialog.setTitle("Text Entry"); + Button sendbutton = (Button) dialog.findViewById(R.id.sendtext_button_send); + sendbutton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + EditText text = (EditText) v.getRootView().findViewById(R.id.sendtext_text); + mControl.sendText(new DataResponse(), text.getText().toString(), context); + text.setText(""); + } + }); + Button donebutton = (Button) dialog.findViewById(R.id.sendtext_button_done); + donebutton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + EditText text = (EditText) v.getRootView().findViewById(R.id.sendtext_text); + mControl.sendText(new DataResponse(), text.getText().toString() + "\n", context); + dismissDialog(DIALOG_SENDTEXT); + } + }); + Button cancelbutton = (Button) dialog.findViewById(R.id.sendtext_button_cancel); + cancelbutton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + dismissDialog(DIALOG_SENDTEXT); + } + }); + break; + default: + dialog = null; + } + return dialog; + } + + public void onPrepareDialog(int id, Dialog dialog) { + EditText text = (EditText) dialog.findViewById(R.id.sendtext_text); + text.setText(""); + } + + public boolean onOptionsItemSelected(MenuItem item) { + Intent intent = null; + switch (item.getItemId()) { + case MENU_NOW_PLAYING: + intent = new Intent(mActivity, NowPlayingActivity.class); + break; + case MENU_SWITCH_GESTURE: + intent = new Intent(mActivity, GestureRemoteActivity.class); + intent.addFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY); + break; + case MENU_XBMC_EXIT: + mEventClientManager.sendButton("R1", ButtonCodes.REMOTE_POWER, false, true, true, (short) 0, (byte) 0); + break; + case MENU_XBMC_S: + mEventClientManager.sendButton("KB", "S", false, true, true, (short) 0, (byte) 0); + break; + case MENU_ENTER_TEXT: + showDialog(DIALOG_SENDTEXT); + break; + } + if (intent != null) { + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mActivity.startActivity(intent); + return true; + } + return true; + } + + /** + * Sends a keyboard event + * + * @param button + * @return + */ + private boolean keyboardAction(String button) { + mEventClientManager.sendButton("KB", button, false, true, true, (short) 0, (byte) 0); + return true; + } + + /** + * Shortcut for adding the listener class to the button + * + * @param btn Resource ID of the button + * @param action Action string + */ + public void setupButton(View btn, String action) { + if (btn != null) { + btn.setOnTouchListener(new OnRemoteAction(action)); + ((Button) btn).setSoundEffectsEnabled(true); + ((Button) btn).setClickable(true); + } + } + + public void onActivityPause() { + mEventClientManager.setController(null); + mInfoManager.setController(null); + if (mGestureThread != null) { + mGestureThread.quit(); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + mHandler = new Handler(); + mEventClientManager.setController(this); + mInfoManager.setController(this); + } + + public void sendButton(String buttonCode) { + mEventClientManager.sendButton("R1", buttonCode, false, true, false, (short) 0, (byte) 0); + } + + private static class GestureThread extends Thread { + public static final int ACTION_UP = 1; + public static final int ACTION_RIGHT = 2; + public static final int ACTION_DOWN = 3; + public static final int ACTION_LEFT = 4; + private final IEventClientManager mEventClient; + private boolean mQuit = false; + private int mLevel = 0; + private int[] mSpeed = {0, 800, 400, 200, 100, 50, 0}; + private int mAction = 0; + + public GestureThread(IEventClientManager eventClient) { + super("RemoteController.GestureThread"); + mEventClient = eventClient; + } + + @Override + public void run() { + Log.i("GestureThread", "STARTING..."); + while (!mQuit) { + try { + switch (mAction) { + case ACTION_UP: + mEventClient.sendButton("R1", ButtonCodes.REMOTE_UP, false, true, true, (short) 0, + (byte) 0); + break; + case ACTION_RIGHT: + mEventClient.sendButton("R1", ButtonCodes.REMOTE_RIGHT, false, true, true, (short) 0, + (byte) 0); + break; + case ACTION_DOWN: + mEventClient.sendButton("R1", ButtonCodes.REMOTE_DOWN, false, true, true, (short) 0, + (byte) 0); + break; + case ACTION_LEFT: + mEventClient.sendButton("R1", ButtonCodes.REMOTE_LEFT, false, true, true, (short) 0, + (byte) 0); + break; + } +// Log.i("GestureThread", "action: " + mAction); + Thread.sleep(mSpeed[Math.abs(mLevel)]); + } catch (InterruptedException e) { + mQuit = true; + } + + } + } + + public synchronized void setLevel(int level, int action) { + mLevel = level; + mAction = action; + if (!isAlive()) { + start(); + } + } + + public synchronized void quit() { + Log.i("GestureThread", "QUITTING."); + mQuit = true; + } + } + + /** + * Handles the push- release button code. Switches image of the pressed + * button, vibrates and executes command. + */ + private class OnRemoteAction implements OnTouchListener { + private final String mAction; + + public OnRemoteAction(String action) { + mAction = action; + } + + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + Log.d(TAG, "onTouch - ACTION_DOWN"); + if (mDoVibrate) { + mVibrator.vibrate(VIBRATION_LENGTH); + } + + if (currKeyTask != null) { + currKeyTask.cancel(); + } + if (currKeyAction != "") { + mEventClientManager.sendButton("R1", mAction, false, false, true, (short) 0, (byte) 0); + } + mEventClientManager.sendButton("R1", mAction, !prefs.getBoolean("setting_send_repeats", false), true, + true, (short) 0, (byte) 0); + currKeyAction = mAction; + + if (prefs.getBoolean("setting_send_repeats", false) && !prefs.getBoolean("setting_send_single_click", + false)) { + int RepeatDelay = Integer.parseInt(prefs.getString("setting_repeat_rate", "250")); + + currKeyTask = new KeyPressTask(mAction); + tmrKeyPress.schedule(currKeyTask, RepeatDelay, RepeatDelay); + } + + + } else if (event.getAction() == MotionEvent.ACTION_UP) { + Log.d(TAG, "onTouch - ACTION_UP"); + v.playSoundEffect(AudioManager.FX_KEY_CLICK); + + if (currKeyTask != null) { + currKeyTask.cancel(); + currKeyTask = null; + } + + mEventClientManager.sendButton("R1", mAction, false, false, true, (short) 0, (byte) 0); + currKeyAction = ""; + } + return false; + } + } + + private class KeyPressTask extends TimerTask { + + private String mKeyPressAction = ""; + + public KeyPressTask(String mAction) { + mKeyPressAction = mAction; + } + + public void run() { + if (mKeyPressAction.length() > 0) { + mEventClientManager.sendButton("R1", mKeyPressAction, false, true, true, (short) 0, (byte) 0); + + } + } + } + } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/SeasonListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SeasonListController.java similarity index 90% rename from src/org/xbmc/android/remote/presentation/controller/SeasonListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/SeasonListController.java index 1b4eb16a..9c714967 100644 --- a/src/org/xbmc/android/remote/presentation/controller/SeasonListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SeasonListController.java @@ -21,21 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.widget.GridPosterItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.object.Movie; -import org.xbmc.api.object.Season; -import org.xbmc.api.object.TvShow; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -57,12 +42,24 @@ import android.widget.ListAdapter; import android.widget.Toast; -public class SeasonListController extends ListController implements IController { +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.widget.GridPosterItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.object.Movie; +import org.xbmc.api.object.Season; +import org.xbmc.api.object.TvShow; +import org.xbmc.api.type.ThumbSize; - private static final int mThumbSize = ThumbSize.MEDIUM; +import java.util.ArrayList; - public static final int ITEM_CONTEXT_BROWSE = 1; +public class SeasonListController extends ListController implements IController { + public static final int ITEM_CONTEXT_BROWSE = 1; public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_TITLE_ASC = 21; @@ -71,12 +68,11 @@ public class SeasonListController extends ListController implements IController public static final int MENU_SORT_BY_YEAR_DESC = 24; public static final int MENU_SORT_BY_RATING_ASC = 25; public static final int MENU_SORT_BY_RATING_DESC = 26; - + private static final int mThumbSize = ThumbSize.MEDIUM; + private static final long serialVersionUID = 1088971882661811256L; private TvShow mShow; - private ITvShowManager mTvManager; private IControlManager mControlManager; - private boolean mLoadCovers = false; public void onCreate(Activity activity, Handler handler, AbsListView list) { @@ -95,12 +91,12 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { toast.show(); } - mShow = (TvShow)activity.getIntent().getSerializableExtra(ListController.EXTRA_TVSHOW); + mShow = (TvShow) activity.getIntent().getSerializableExtra(ListController.EXTRA_TVSHOW); activity.registerForContextMenu(mList); mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_season); - + setupIdleListener(mThumbSize); mList.setOnItemClickListener(new OnItemClickListener() { @@ -123,7 +119,7 @@ private void fetch() { DataResponse> response = new DataResponse>() { public void run() { if (value.size() > 0) { - setTitle(title +" (" + value.size() + ")"); + setTitle(title + " (" + value.size() + ")"); ((AdapterView) mList).setAdapter(new SeasonAdapter(mActivity, value)); } else { setTitle(title); @@ -131,7 +127,7 @@ public void run() { } } }; - + showOnLoading(); setTitle(title + "..."); if (mShow != null) { @@ -141,7 +137,7 @@ public void run() { /** * Shows a dialog and refreshes the movie library if user confirmed. - * + * * @param activity */ public void refreshMovieLibrary(final Activity activity) { @@ -152,7 +148,7 @@ public void refreshMovieLibrary(final Activity activity) { .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, - int which) { + int which) { mControlManager.updateLibrary( new DataResponse() { public void run() { @@ -168,22 +164,25 @@ public void run() { toast.show(); } }, "video", mActivity - .getApplicationContext()); + .getApplicationContext() + ); } - }) + } + ) .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, - int which) { + int which) { dialog.cancel(); } - }); + } + ); builder.create().show(); } @Override public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + ContextMenuInfo menuInfo) { final GridPosterItemView view = (GridPosterItemView) ((AdapterContextMenuInfo) menuInfo).targetView; menu.setHeaderTitle(view.title); menu.add(0, ITEM_CONTEXT_BROWSE, 1, "Browse Season"); @@ -194,17 +193,18 @@ public void onContextItemSelected(MenuItem item) { // (Season)mList.getAdapter().getItem(((GridPosterItemView)view).position); final Season season = (Season) mList.getAdapter().getItem( ((GridPosterItemView) ((AdapterContextMenuInfo) item - .getMenuInfo()).targetView).position); + .getMenuInfo()).targetView).position + ); switch (item.getItemId()) { - case ITEM_CONTEXT_BROWSE: - Intent nextActivity = new Intent(mActivity, ListActivity.class); - nextActivity.putExtra(ListController.EXTRA_SEASON, season); - nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, - new EpisodeListController()); - mActivity.startActivity(nextActivity); - break; - default: - return; + case ITEM_CONTEXT_BROWSE: + Intent nextActivity = new Intent(mActivity, ListActivity.class); + nextActivity.putExtra(ListController.EXTRA_SEASON, season); + nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, + new EpisodeListController()); + mActivity.startActivity(nextActivity); + break; + default: + return; } } @@ -230,17 +230,17 @@ public void onCreateOptionsMenu(Menu menu) { public void onOptionsItemSelected(MenuItem item) { // final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - break; - case MENU_SORT_BY_TITLE_ASC: - case MENU_SORT_BY_TITLE_DESC: - case MENU_SORT_BY_YEAR_ASC: - case MENU_SORT_BY_YEAR_DESC: - case MENU_SORT_BY_RATING_ASC: - case MENU_SORT_BY_RATING_DESC: - break; - default: - super.onOptionsItemSelected(item); + case MENU_PLAY_ALL: + break; + case MENU_SORT_BY_TITLE_ASC: + case MENU_SORT_BY_TITLE_DESC: + case MENU_SORT_BY_YEAR_ASC: + case MENU_SORT_BY_YEAR_DESC: + case MENU_SORT_BY_RATING_ASC: + case MENU_SORT_BY_RATING_DESC: + break; + default: + super.onOptionsItemSelected(item); } } @@ -250,6 +250,27 @@ protected void refreshList() { fetch(); } + public void onActivityPause() { + if (mTvManager != null) { + mTvManager.setController(null); + mTvManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mTvManager != null) { + mTvManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + private class SeasonAdapter extends ArrayAdapter { SeasonAdapter(Activity activity, ArrayList items) { super(activity, 0, items); @@ -282,27 +303,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - private static final long serialVersionUID = 1088971882661811256L; - - public void onActivityPause() { - if (mTvManager != null) { - mTvManager.setController(null); - mTvManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mTvManager != null) { - mTvManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/SettingsController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SettingsController.java similarity index 91% rename from src/org/xbmc/android/remote/presentation/controller/SettingsController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/SettingsController.java index d37a53e3..6bfa2ece 100644 --- a/src/org/xbmc/android/remote/presentation/controller/SettingsController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SettingsController.java @@ -21,16 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; -import java.util.Hashtable; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; -import org.xbmc.android.remote.presentation.activity.SettingsActivity; -import org.xbmc.android.util.HostFactory; -import org.xbmc.api.object.Host; -import org.xbmc.api.presentation.INotifiableController; - import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -47,27 +37,36 @@ import android.view.MenuItem; import android.widget.Toast; -public class SettingsController extends AbstractController implements INotifiableController, IController, OnSharedPreferenceChangeListener { - private static final String TAG = "SettingsController"; - +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.activity.HostSettingsActivity; +import org.xbmc.android.remote.presentation.activity.SettingsActivity; +import org.xbmc.android.util.HostFactory; +import org.xbmc.api.object.Host; +import org.xbmc.api.presentation.INotifiableController; + +import java.util.ArrayList; +import java.util.Hashtable; + +public class SettingsController extends AbstractController implements INotifiableController, IController, + OnSharedPreferenceChangeListener { public static final int MENU_ADD_HOST = 1; public static final int MENU_ADD_HOST_WIZARD = 3; public static final int MENU_ADD_FROM_BARCODE = 4; public static final int MENU_GENERATE_BARCODE = 5; - public static final int REQUEST_SCAN_BARCODE = 1; - - private PreferenceActivity mPreferenceActivity; + private static final String TAG = "SettingsController"; private final Hashtable mSummaries = new Hashtable(); - + private PreferenceActivity mPreferenceActivity; + public SettingsController(PreferenceActivity activity, Handler handler) { mPreferenceActivity = activity; super.onCreate(activity, handler); } - + /** - * Used in SettingsActivity in order to update the %value% placeholder in + * Used in SettingsActivity in order to update the %value% placeholder in * the summaries. + * * @param activity Reference to activity */ public void registerOnSharedPreferenceChangeListener(PreferenceActivity activity) { @@ -83,12 +82,13 @@ public void registerOnSharedPreferenceChangeListener(PreferenceActivity activity } updateSummaries(); } - + /** * Creates the preference screen that contains all the listed hosts. - * @param root Root node + * + * @param root Root node * @param activity Reference to activity - * @return + * @return */ public PreferenceScreen createHostsPreferences(PreferenceScreen root, Activity activity) { final ArrayList hosts = HostFactory.getHosts(activity.getApplicationContext()); @@ -113,7 +113,7 @@ public void onClick(DialogInterface dialog, int which) { } return root; } - + /** * Updates summaries of all known keys with the updated value. */ @@ -124,12 +124,13 @@ public void updateSummaries() { if (pref != null && pref.getSummary() != null) { String summary = pref.getSummary().toString(); if (summary.contains(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER)) { - pref.setSummary(summary.replaceAll(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER, ps.getSharedPreferences().getString(key, ""))); + pref.setSummary(summary.replaceAll(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER, + ps.getSharedPreferences().getString(key, ""))); } } } } - + /** * Used in order to replace the %value% placeholders with real values. */ @@ -138,17 +139,20 @@ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, Strin Preference pref = mPreferenceActivity.getPreferenceScreen().findPreference(key); String origSummary = mSummaries.get(key); if (origSummary != null && origSummary.contains(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER)) { - pref.setSummary(origSummary.replaceAll(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER, sharedPreferences.getString(key, ""))); + pref.setSummary(origSummary.replaceAll(SettingsActivity.SUMMARY_VALUE_PLACEHOLDER, + sharedPreferences.getString(key, ""))); } } public void onCreateOptionsMenu(Menu menu) { menu.addSubMenu(0, MENU_ADD_HOST, 0, "Add Host").setIcon(R.drawable.menu_add_host); menu.addSubMenu(0, MENU_ADD_HOST_WIZARD, 0, "Host Wizard").setIcon(R.drawable.menu_add_host); - menu.addSubMenu(0, MENU_ADD_FROM_BARCODE, 0, mPreferenceActivity.getString(R.string.add_from_barcode)).setIcon(R.drawable.menu_qr_code); - menu.addSubMenu(0, MENU_GENERATE_BARCODE, 0, mPreferenceActivity.getString(R.string.generate_barcode)).setIcon(R.drawable.menu_qr_code); + menu.addSubMenu(0, MENU_ADD_FROM_BARCODE, 0, mPreferenceActivity.getString(R.string.add_from_barcode)).setIcon + (R.drawable.menu_qr_code); + menu.addSubMenu(0, MENU_GENERATE_BARCODE, 0, mPreferenceActivity.getString(R.string.generate_barcode)).setIcon + (R.drawable.menu_qr_code); } - + public void onMenuItemSelected(int featureId, MenuItem item) { switch (item.getItemId()) { case MENU_ADD_HOST: @@ -160,33 +164,35 @@ public void onMenuItemSelected(int featureId, MenuItem item) { case MENU_ADD_FROM_BARCODE: final Intent scanIntent = new Intent("com.google.zxing.client.android.SCAN"); scanIntent.putExtra("SCAN_MODE", "QR_CODE_MODE"); - + if (mPreferenceActivity.getPackageManager().queryIntentActivities(scanIntent, 0).size() == 0) { showBarcodeUnsupportedDialog(); break; } - + mPreferenceActivity.startActivityForResult(scanIntent, REQUEST_SCAN_BARCODE); break; case MENU_GENERATE_BARCODE: final Intent intent = new Intent("com.google.zxing.client.android.ENCODE"); intent.putExtra("ENCODE_TYPE", "TEXT_TYPE"); - + if (mPreferenceActivity.getPackageManager().queryIntentActivities(intent, 0).size() == 0) { showBarcodeUnsupportedDialog(); break; } - + final ArrayList hosts = HostFactory.getHosts(mPreferenceActivity); - + if (hosts.size() == 0) { AlertDialog.Builder builder = new AlertDialog.Builder(mPreferenceActivity); builder.setMessage(mPreferenceActivity.getString(R.string.hosts_required)); - builder.setPositiveButton(mPreferenceActivity.getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); + builder.setPositiveButton(mPreferenceActivity.getString(R.string.ok), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + } + ); builder.create().show(); break; } else if (hosts.size() == 1) { @@ -218,7 +224,7 @@ public void onCancel(DialogInterface dialog) { break; } } - + public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_SCAN_BARCODE) { if (resultCode == Activity.RESULT_OK) { @@ -227,24 +233,28 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { if (host == null) { AlertDialog.Builder builder = new AlertDialog.Builder(mPreferenceActivity); builder.setMessage(mPreferenceActivity.getString(R.string.host_scan_error)); - builder.setPositiveButton(mPreferenceActivity.getString(R.string.ok), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - }); + builder.setPositiveButton(mPreferenceActivity.getString(R.string.ok), + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + } + ); builder.create().show(); } else { HostFactory.addHost(mPreferenceActivity, host); - Toast.makeText(mPreferenceActivity, mPreferenceActivity.getString(R.string.added_host, host.name), Toast.LENGTH_SHORT).show(); - + Toast.makeText(mPreferenceActivity, mPreferenceActivity.getString(R.string.added_host, host.name), + Toast.LENGTH_SHORT).show(); + // Is there a better way to refresh the preferences screen? - mPreferenceActivity.startActivity(new Intent(mPreferenceActivity.getBaseContext(), HostSettingsActivity.class)); + mPreferenceActivity.startActivity(new Intent(mPreferenceActivity.getBaseContext(), + HostSettingsActivity.class)); mPreferenceActivity.finish(); } } } } - + private void showBarcodeUnsupportedDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(mPreferenceActivity); builder.setMessage(mPreferenceActivity.getString(R.string.barcode_scanner_required)); @@ -262,14 +272,14 @@ public void onClick(DialogInterface dialog, int which) { }); builder.create().show(); } - + public void onActivityPause() { super.onActivityPause(); } - + public void onActivityResume(Activity activity) { super.onActivityResume(activity); - final ArrayList hosts = HostFactory.getHosts(activity.getApplicationContext()); + final ArrayList hosts = HostFactory.getHosts(activity.getApplicationContext()); if (hosts.size() == 1) { final Host host = hosts.get(0); Log.i(TAG, "Setting host to " + (host == null ? "" : host.addr) + "."); @@ -279,5 +289,5 @@ public void onActivityResume(Activity activity) { Log.i(TAG, "Resetting host to ."); HostFactory.saveHost(activity.getApplicationContext(), null); } - } + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/controller/SongListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SongListController.java similarity index 58% rename from src/org/xbmc/android/remote/presentation/controller/SongListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/SongListController.java index 9d5b4d5e..45da6267 100644 --- a/src/org/xbmc/android/remote/presentation/controller/SongListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/SongListController.java @@ -21,23 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.widget.ThreeLabelsItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IMusicManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Song; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; @@ -59,13 +42,28 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.widget.ThreeLabelsItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IMusicManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Song; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class SongListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; + public static final int ITEM_CONTEXT_QUEUE = 1; public static final int ITEM_CONTEXT_PLAY = 2; public static final int ITEM_CONTEXT_INFO = 3; - public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_ALBUM_ASC = 31; @@ -76,79 +74,81 @@ public class SongListController extends ListController implements IController { public static final int MENU_SORT_BY_TITLE_DESC = 36; public static final int MENU_SORT_BY_FILENAME_ASC = 37; public static final int MENU_SORT_BY_FILENAME_DESC = 38; - + private static final int mThumbSize = ThumbSize.SMALL; private static final String PREF_DEFAULT_SELECTION_ACTION = "setting_default_selection_action"; - private static final String DEFAULT_ACTION_PLAY = "0"; - + private static final String DEFAULT_ACTION_PLAY = "0"; + private static final int INT_DEFAULT_ACTION_PLAY = 0; - private static final int INT_DEFAULT_ACTION_QUEUE = 1; - + private static final int INT_DEFAULT_ACTION_QUEUE = 1; + private static final long serialVersionUID = 755529227668553163L; private Album mAlbum; private Artist mArtist; private Genre mGenre; - private IMusicManager mMusicManager; - private boolean mLoadCovers = false; - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mMusicManager = ManagerFactory.getMusicManager(this); - - ((ISortableManager)mMusicManager).setSortKey(AbstractManager.PREF_SORT_KEY_SONG); - ((ISortableManager)mMusicManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); - + + ((ISortableManager) mMusicManager).setSortKey(AbstractManager.PREF_SORT_KEY_SONG); + ((ISortableManager) mMusicManager).setPreferences(activity.getPreferences(Context.MODE_PRIVATE)); + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; - + if (!isCreated()) { super.onCreate(activity, handler, list); - + if (!mLoadCovers) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mAlbum = (Album)mActivity.getIntent().getSerializableExtra(EXTRA_ALBUM); - mArtist = (Artist)mActivity.getIntent().getSerializableExtra(EXTRA_ARTIST); - mGenre = (Genre)mActivity.getIntent().getSerializableExtra(EXTRA_GENRE); + + mAlbum = (Album) mActivity.getIntent().getSerializableExtra(EXTRA_ALBUM); + mArtist = (Artist) mActivity.getIntent().getSerializableExtra(EXTRA_ARTIST); + mGenre = (Genre) mActivity.getIntent().getSerializableExtra(EXTRA_GENRE); mActivity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(mActivity.getResources(), R.drawable.icon_song); setupIdleListener(); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; - final Song song = (Song)mList.getAdapter().getItem(((ThreeLabelsItemView)view).position); - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext()); - final int SelectionType = Integer.parseInt(prefs.getString(PREF_DEFAULT_SELECTION_ACTION, DEFAULT_ACTION_PLAY)); + if (isLoading()) return; + final Song song = (Song) mList.getAdapter().getItem(((ThreeLabelsItemView) view).position); + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity + .getApplicationContext()); + final int SelectionType = Integer.parseInt(prefs.getString(PREF_DEFAULT_SELECTION_ACTION, + DEFAULT_ACTION_PLAY)); switch (SelectionType) { case INT_DEFAULT_ACTION_PLAY: if (mAlbum == null) { mMusicManager.play(new QueryResponse( - mActivity, - "Playing \"" + song.title + "\" by " + song.artist + "...", - "Error playing song!", - true + mActivity, + "Playing \"" + song.title + "\" by " + song.artist + "...", + "Error playing song!", + true ), song, mActivity.getApplicationContext()); } else { mMusicManager.play(new QueryResponse( - mActivity, - "Playing album \"" + song.album + "\" starting with song \"" + song.title + "\" by " + song.artist + "...", - "Error playing song!", - true + mActivity, + "Playing album \"" + song.album + "\" starting with song \"" + song.title + + "\" by " + song.artist + "...", + "Error playing song!", + true ), mAlbum, song, mActivity.getApplicationContext()); } break; - case INT_DEFAULT_ACTION_QUEUE: - if (mAlbum == null) - { - mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Song added to playlist.", "Error adding song!"), song, mActivity.getApplicationContext()); - } - else - { - mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Playlist empty, added whole album.", "Song added to playlist."), mAlbum, song, mActivity.getApplicationContext()); + case INT_DEFAULT_ACTION_QUEUE: + if (mAlbum == null) { + mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Song added to playlist.", + "Error adding song!"), song, mActivity.getApplicationContext()); + } else { + mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Playlist empty, " + + "added whole album.", "Song added to playlist."), mAlbum, song, + mActivity.getApplicationContext() + ); } break; default: @@ -156,14 +156,15 @@ public void onItemClick(AdapterView parent, View view, int position, long id) } } }); - + mList.setOnKeyListener(new ListControllerOnKeyListener()); fetch(); } } - + private void fetch() { - final String title = mAlbum != null ? mAlbum.name + " - " : mArtist != null ? mArtist.name + " - " : mGenre != null ? mGenre.name + " - " : "" + "Songs"; + final String title = mAlbum != null ? mAlbum.name + " - " : mArtist != null ? mArtist.name + " - " : mGenre != + null ? mGenre.name + " - " : "" + "Songs"; DataResponse> response = new DataResponse>() { public void run() { if (value.size() > 0) { @@ -175,7 +176,7 @@ public void run() { } } }; - + showOnLoading(); setTitle(title + "..."); if (mAlbum != null) { @@ -186,41 +187,45 @@ public void run() { mMusicManager.getSongs(response, mGenre, mActivity.getApplicationContext()); } } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { // be aware that this must be explicitly called by your activity! - final ThreeLabelsItemView view = (ThreeLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; - menu.setHeaderTitle(((Song)mList.getItemAtPosition(view.getPosition())).title); + final ThreeLabelsItemView view = (ThreeLabelsItemView) ((AdapterContextMenuInfo) menuInfo).targetView; + menu.setHeaderTitle(((Song) mList.getItemAtPosition(view.getPosition())).title); menu.add(0, ITEM_CONTEXT_QUEUE, 1, "Queue Song"); menu.add(0, ITEM_CONTEXT_PLAY, 2, "Play Song"); } - + public void onContextItemSelected(MenuItem item) { // be aware that this must be explicitly called by your activity! - final Song song = (Song)mList.getAdapter().getItem(((ThreeLabelsItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final Song song = (Song) mList.getAdapter().getItem(((ThreeLabelsItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_QUEUE: if (mAlbum == null) { - mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Song added to playlist.", "Error adding song!"), song, mActivity.getApplicationContext()); + mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Song added to playlist.", + "Error adding song!"), song, mActivity.getApplicationContext()); } else { - mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Playlist empty, added whole album.", "Song added to playlist."), mAlbum, song, mActivity.getApplicationContext()); + mMusicManager.addToPlaylist(new QueryResponse(mActivity, "Playlist empty, added whole album.", + "Song added to playlist."), mAlbum, song, mActivity.getApplicationContext()); } break; case ITEM_CONTEXT_PLAY: if (mAlbum == null) { mMusicManager.play(new QueryResponse( - mActivity, - "Playing \"" + song.title + "\" by " + song.artist + "...", - "Error playing song!", - true + mActivity, + "Playing \"" + song.title + "\" by " + song.artist + "...", + "Error playing song!", + true ), song, mActivity.getApplicationContext()); } else { mMusicManager.play(new QueryResponse( - mActivity, - "Playing album \"" + song.album + "\" starting with song \"" + song.title + "\" by " + song.artist + "...", - "Error playing song!", - true + mActivity, + "Playing album \"" + song.album + "\" starting with song \"" + song.title + "\" by " + + song.artist + "...", + "Error playing song!", + true ), mAlbum, song, mActivity.getApplicationContext()); } break; @@ -228,7 +233,7 @@ public void onContextItemSelected(MenuItem item) { return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { menu.add(0, MENU_PLAY_ALL, 0, "Play all").setIcon(R.drawable.menu_song); @@ -242,109 +247,134 @@ public void onCreateOptionsMenu(Menu menu) { sortMenu.add(2, MENU_SORT_BY_FILENAME_ASC, 0, "by Filename ascending"); sortMenu.add(2, MENU_SORT_BY_FILENAME_DESC, 0, "by Filename descending"); } - + @Override public void onOptionsItemSelected(MenuItem item) { final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - final Album album = mAlbum; - final Genre genre = mGenre; - final Artist artist = mArtist; - if (album != null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs of album " + album.name + " by " + album.artist + "...", - "Error playing songs!", - true - ), album, mActivity.getApplicationContext()); - } else if (artist != null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs from " + artist.name + "...", - "Error playing songs!", - true + case MENU_PLAY_ALL: + final Album album = mAlbum; + final Genre genre = mGenre; + final Artist artist = mArtist; + if (album != null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all songs of album " + album.name + " by " + album.artist + "...", + "Error playing songs!", + true + ), album, mActivity.getApplicationContext()); + } else if (artist != null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all songs from " + artist.name + "...", + "Error playing songs!", + true ), artist, mActivity.getApplicationContext()); - } else if (genre != null) { - mMusicManager.play(new QueryResponse( - mActivity, - "Playing all songs of genre " + genre.name + "...", - "Error playing songs!", - true + } else if (genre != null) { + mMusicManager.play(new QueryResponse( + mActivity, + "Playing all songs of genre " + genre.name + "...", + "Error playing songs!", + true ), genre, mActivity.getApplicationContext()); - } - break; - case MENU_SORT_BY_ALBUM_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ALBUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ALBUM_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ALBUM); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ARTIST_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ARTIST); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_ARTIST_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ARTIST); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_FILENAME_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.FILENAME); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_FILENAME_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.FILENAME); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; + } + break; + case MENU_SORT_BY_ALBUM_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ALBUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ALBUM_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ALBUM); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ARTIST_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ARTIST); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_ARTIST_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.ARTIST); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_FILENAME_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.FILENAME); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_FILENAME_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, SortType.FILENAME); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SONG, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; } } - + + public void onActivityPause() { + if (mMusicManager != null) { + mMusicManager.setController(null); + mMusicManager.postActivity(); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mMusicManager != null) { + mMusicManager.setController(this); + } + } + private class SongAdapter extends ArrayAdapter { SongAdapter(Activity activity, ArrayList items) { super(activity, 0, items); } + public View getView(int position, View convertView, ViewGroup parent) { final ThreeLabelsItemView view; if (convertView == null) { - view = new ThreeLabelsItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, mList.getSelector(), false); + view = new ThreeLabelsItemView(mActivity, mMusicManager, parent.getWidth(), mFallbackBitmap, + mList.getSelector(), false); } else { - view = (ThreeLabelsItemView)convertView; + view = (ThreeLabelsItemView) convertView; } - + final Song song = getItem(position); view.reset(); view.position = position; @@ -357,11 +387,11 @@ public View getView(int position, View convertView, ViewGroup parent) { view.subtitle = song.artist; } view.subsubtitle = song.getDuration(); - + if (mLoadCovers) { - if(mMusicManager.coverLoaded(song, mThumbSize)){ + if (mMusicManager.coverLoaded(song, mThumbSize)) { view.setCover(mMusicManager.getCoverSync(song, mThumbSize)); - }else{ + } else { view.setCover(null); view.getResponse().load(song, !mPostScrollLoader.isListIdle()); } @@ -369,21 +399,4 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - public void onActivityPause() { - if (mMusicManager != null) { - mMusicManager.setController(null); - mMusicManager.postActivity(); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mMusicManager != null) { - mMusicManager.setController(this); - } - } - - private static final long serialVersionUID = 755529227668553163L; } diff --git a/src/org/xbmc/android/remote/presentation/controller/TvShowListController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/TvShowListController.java similarity index 68% rename from src/org/xbmc/android/remote/presentation/controller/TvShowListController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/TvShowListController.java index 22d2757c..ba606e8d 100644 --- a/src/org/xbmc/android/remote/presentation/controller/TvShowListController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/TvShowListController.java @@ -21,27 +21,6 @@ package org.xbmc.android.remote.presentation.controller; -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.AbstractManager; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.GridActivity; -import org.xbmc.android.remote.presentation.activity.ListActivity; -import org.xbmc.android.remote.presentation.activity.TvShowDetailsActivity; -import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; -import org.xbmc.android.remote.presentation.widget.FlexibleItemView; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.ISortableManager; -import org.xbmc.api.business.ITvShowManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.TvShow; -import org.xbmc.api.type.SortType; -import org.xbmc.api.type.ThumbSize; - import android.app.Activity; import android.app.AlertDialog; import android.content.Context; @@ -68,13 +47,32 @@ import android.widget.ListAdapter; import android.widget.Toast; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.AbstractManager; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.GridActivity; +import org.xbmc.android.remote.presentation.activity.ListActivity; +import org.xbmc.android.remote.presentation.activity.TvShowDetailsActivity; +import org.xbmc.android.remote.presentation.widget.FiveLabelsItemView; +import org.xbmc.android.remote.presentation.widget.FlexibleItemView; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.ISortableManager; +import org.xbmc.api.business.ITvShowManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.TvShow; +import org.xbmc.api.type.SortType; +import org.xbmc.api.type.ThumbSize; + +import java.util.ArrayList; + public class TvShowListController extends ListController implements IController { - - private static final int mThumbSize = ThumbSize.SMALL; + public static final int ITEM_CONTEXT_BROWSE = 1; public static final int ITEM_CONTEXT_INFO = 2; public static final int ITEM_CONTEXT_IMDB = 3; - public static final int MENU_PLAY_ALL = 1; public static final int MENU_SORT = 2; public static final int MENU_SORT_BY_TITLE_ASC = 21; @@ -84,25 +82,23 @@ public class TvShowListController extends ListController implements IController public static final int MENU_SORT_BY_RATING_ASC = 25; public static final int MENU_SORT_BY_RATING_DESC = 26; public static final int MENU_RECENT_EPISODES = 27; - + private static final int mThumbSize = ThumbSize.SMALL; + private static final long serialVersionUID = 1088971882661811256L; + private static Bitmap mWatchedBitmap; private Actor mActor; private Genre mGenre; - private ITvShowManager mTvManager; private IControlManager mControlManager; - private boolean mLoadCovers = false; - - private static Bitmap mWatchedBitmap; - + public void onCreate(Activity activity, Handler handler, AbsListView list) { - + mTvManager = ManagerFactory.getTvManager(this); mControlManager = ManagerFactory.getControlManager(this); - + final String sdError = ImportUtilities.assertSdCard(); mLoadCovers = sdError == null; - + if (!isCreated()) { super.onCreate(activity, handler, list); @@ -110,19 +106,19 @@ public void onCreate(Activity activity, Handler handler, AbsListView list) { Toast toast = Toast.makeText(activity, sdError + " Displaying place holders only.", Toast.LENGTH_LONG); toast.show(); } - - mActor = (Actor)mActivity.getIntent().getSerializableExtra(ListController.EXTRA_ACTOR); - mGenre = (Genre)mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); + + mActor = (Actor) mActivity.getIntent().getSerializableExtra(ListController.EXTRA_ACTOR); + mGenre = (Genre) mActivity.getIntent().getSerializableExtra(ListController.EXTRA_GENRE); activity.registerForContextMenu(mList); - + mFallbackBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.default_tvshow); mWatchedBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.check_mark); setupIdleListener(); - + mList.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView parent, View view, int position, long id) { - if(isLoading()) return; - final TvShow show = (TvShow)mList.getAdapter().getItem(((FiveLabelsItemView)view).position); + if (isLoading()) return; + final TvShow show = (TvShow) mList.getAdapter().getItem(((FiveLabelsItemView) view).position); Intent nextActivity = new Intent(view.getContext(), GridActivity.class); nextActivity.putExtra(ListController.EXTRA_TVSHOW, show); nextActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new SeasonListController()); @@ -133,13 +129,14 @@ public void onItemClick(AdapterView parent, View view, int position, long id) fetch(); } } - + private void fetch() { // tv show and episode both are using the same manager so set the sort key here - ((ISortableManager)mTvManager).setSortKey(AbstractManager.PREF_SORT_KEY_SHOW); - ((ISortableManager)mTvManager).setPreferences(mActivity.getPreferences(Context.MODE_PRIVATE)); + ((ISortableManager) mTvManager).setSortKey(AbstractManager.PREF_SORT_KEY_SHOW); + ((ISortableManager) mTvManager).setPreferences(mActivity.getPreferences(Context.MODE_PRIVATE)); - final String title = mActor != null ? mActor.name + " - " : mGenre != null ? mGenre.name + " - " : "" + "TV Shows"; + final String title = mActor != null ? mActor.name + " - " : mGenre != null ? mGenre.name + " - " : "" + "TV " + + "Shows"; DataResponse> response = new DataResponse>() { public void run() { if (value.size() > 0) { @@ -151,61 +148,63 @@ public void run() { } } }; - + showOnLoading(); - setTitle(title + "..."); - if (mActor != null) { // TV Shows with a certain actor + setTitle(title + "..."); + if (mActor != null) { // TV Shows with a certain actor mTvManager.getTvShows(response, mActor, mActivity.getApplicationContext()); - } else if (mGenre != null) { // TV Shows of a genre + } else if (mGenre != null) { // TV Shows of a genre mTvManager.getTvShows(response, mGenre, mActivity.getApplicationContext()); - } else { // all TV Shows + } else { // all TV Shows mTvManager.getTvShows(response, mActivity.getApplicationContext()); } } - + /** * Shows a dialog and refreshes the movie library if user confirmed. + * * @param activity */ public void refreshMovieLibrary(final Activity activity) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setMessage("Are you sure you want XBMC to rescan your movie library?") - .setCancelable(false) - .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mControlManager.updateLibrary(new DataResponse() { - public void run() { - final String message; - if (value) { - message = "Movie library updated has been launched."; - } else { - message = "Error launching movie library update."; + .setCancelable(false) + .setPositiveButton("Yes!", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mControlManager.updateLibrary(new DataResponse() { + public void run() { + final String message; + if (value) { + message = "Movie library updated has been launched."; + } else { + message = "Error launching movie library update."; + } + Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); + toast.show(); } - Toast toast = Toast.makeText(activity, message, Toast.LENGTH_SHORT); - toast.show(); - } - }, "video", mActivity.getApplicationContext()); - } - }) - .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); + }, "video", mActivity.getApplicationContext()); + } + }) + .setNegativeButton("Uh, no.", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); builder.create().show(); } - + @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { - final FiveLabelsItemView view = (FiveLabelsItemView)((AdapterContextMenuInfo)menuInfo).targetView; + final FiveLabelsItemView view = (FiveLabelsItemView) ((AdapterContextMenuInfo) menuInfo).targetView; menu.setHeaderTitle(view.title); menu.add(0, ITEM_CONTEXT_BROWSE, 1, "Browse TV Show"); menu.add(0, ITEM_CONTEXT_INFO, 2, "View Details"); menu.add(0, ITEM_CONTEXT_IMDB, 3, "Open IMDb"); } - + public void onContextItemSelected(MenuItem item) { - final TvShow show = (TvShow)mList.getAdapter().getItem(((FiveLabelsItemView)((AdapterContextMenuInfo)item.getMenuInfo()).targetView).position); + final TvShow show = (TvShow) mList.getAdapter().getItem(((FiveLabelsItemView) ((AdapterContextMenuInfo) item + .getMenuInfo()).targetView).position); switch (item.getItemId()) { case ITEM_CONTEXT_BROWSE: Intent browseActivity = new Intent(mActivity, GridActivity.class); @@ -220,9 +219,10 @@ public void onContextItemSelected(MenuItem item) { break; case ITEM_CONTEXT_IMDB: Intent intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("imdb:///find?s=tt&q=" + show.getName())); - if (mActivity.getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == null) - { - intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/search/title?title=" + show.getShortName() + "&title_type=tv_series&release_date=" + show.firstAired)); + if (mActivity.getPackageManager().resolveActivity(intentIMDb, PackageManager.MATCH_DEFAULT_ONLY) == + null) { + intentIMDb = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.imdb.com/search/title?title=" + + show.getShortName() + "&title_type=tv_series&release_date=" + show.firstAired)); } mActivity.startActivity(intentIMDb); break; @@ -230,7 +230,7 @@ public void onContextItemSelected(MenuItem item) { return; } } - + @Override public void onCreateOptionsMenu(Menu menu) { if (mActor != null || mGenre != null) { @@ -247,71 +247,98 @@ public void onCreateOptionsMenu(Menu menu) { // menu.add(0, MENU_SWITCH_VIEW, 0, "Switch view").setIcon(R.drawable.menu_view); createShowHideWatchedToggle(menu); } - + @Override public void onOptionsItemSelected(MenuItem item) { final SharedPreferences.Editor ed; switch (item.getItemId()) { - case MENU_PLAY_ALL: - break; - case MENU_SORT_BY_TITLE_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_TITLE_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.TITLE); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_YEAR_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.YEAR); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_ASC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_ASC); - ed.commit(); - fetch(); - break; - case MENU_SORT_BY_RATING_DESC: - ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); - ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.RATING); - ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.ORDER_DESC); - ed.commit(); - fetch(); - break; - case MENU_RECENT_EPISODES: - Intent recentEpisodesActivity = new Intent(mActivity, ListActivity.class); - recentEpisodesActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new EpisodeListController()); - mActivity.startActivity(recentEpisodesActivity); - break; - default: - super.onOptionsItemSelected(item); + case MENU_PLAY_ALL: + break; + case MENU_SORT_BY_TITLE_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_TITLE_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.TITLE); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_YEAR_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.YEAR); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_ASC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_ASC); + ed.commit(); + fetch(); + break; + case MENU_SORT_BY_RATING_DESC: + ed = mActivity.getPreferences(Context.MODE_PRIVATE).edit(); + ed.putInt(AbstractManager.PREF_SORT_BY_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, SortType.RATING); + ed.putString(AbstractManager.PREF_SORT_ORDER_PREFIX + AbstractManager.PREF_SORT_KEY_SHOW, + SortType.ORDER_DESC); + ed.commit(); + fetch(); + break; + case MENU_RECENT_EPISODES: + Intent recentEpisodesActivity = new Intent(mActivity, ListActivity.class); + recentEpisodesActivity.putExtra(ListController.EXTRA_LIST_CONTROLLER, new EpisodeListController()); + mActivity.startActivity(recentEpisodesActivity); + break; + default: + super.onOptionsItemSelected(item); } } - + @Override protected void refreshList() { hideMessage(); fetch(); } - + + public void onActivityPause() { + if (mTvManager != null) { + mTvManager.setController(null); + mTvManager.postActivity(); + } + if (mControlManager != null) { + mControlManager.setController(null); + } + super.onActivityPause(); + } + + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + if (mTvManager != null) { + mTvManager.setController(this); + } + if (mControlManager != null) { + mControlManager.setController(this); + } + } + private class TvShowAdapter extends ArrayAdapter { TvShowAdapter(Activity activity, ArrayList items) { super(activity, 0, items); @@ -348,28 +375,5 @@ public View getView(int position, View convertView, ViewGroup parent) { return view; } } - - private static final long serialVersionUID = 1088971882661811256L; - - public void onActivityPause() { - if (mTvManager != null) { - mTvManager.setController(null); - mTvManager.postActivity(); - } - if (mControlManager != null) { - mControlManager.setController(null); - } - super.onActivityPause(); - } - - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - if (mTvManager != null) { - mTvManager.setController(this); - } - if (mControlManager != null) { - mControlManager.setController(this); - } - } } diff --git a/src/org/xbmc/android/remote/presentation/controller/UrlIntentController.java b/app/src/main/java/org/xbmc/android/remote/presentation/controller/UrlIntentController.java similarity index 88% rename from src/org/xbmc/android/remote/presentation/controller/UrlIntentController.java rename to app/src/main/java/org/xbmc/android/remote/presentation/controller/UrlIntentController.java index 11c23177..15e6fc98 100644 --- a/src/org/xbmc/android/remote/presentation/controller/UrlIntentController.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/controller/UrlIntentController.java @@ -1,344 +1,349 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.remote.presentation.controller; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.xbmc.android.remote.R.drawable; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; -import org.xbmc.android.remote.presentation.activity.UrlIntentActivity; -import org.xbmc.android.util.YoutubeURLParser; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.IVideoManager; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.object.Movie; -import org.xbmc.api.presentation.INotifiableController; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.app.AlertDialog.Builder; -import android.content.DialogInterface; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.Handler; -import android.os.Looper; -import android.preference.PreferenceManager; -import android.util.Log; -import android.widget.Toast; - -/** - * Class that is called when XBMC locally tries to open any media content. The - * user then has an additional option "Play in XBMC". - * - * @author Team XBMC - */ -public class UrlIntentController extends AbstractController implements IController, INotifiableController { - - private static final String IMDb_SHARE_PREFIX = "IMDb:"; - private static final String CONFIRM_PLAY_ON_XBMC = "setting_confirm_play_on_xbmc"; - - private final IControlManager mControlManager; - private final IInfoManager mInfoManager; - private final IVideoManager mVideoManager; - - private DataResponse mXbmcStatusHandler; - - public UrlIntentController(Activity activity, Handler handler) { - super.onCreate(activity, handler); - mInfoManager = ManagerFactory.getInfoManager(this); - mControlManager = ManagerFactory.getControlManager(this); - mVideoManager = ManagerFactory.getVideoManager(this); - } - - /* (non-Javadoc) - * @see org.xbmc.android.remote.presentation.controller.IController#onActivityPause() - */ - public void onActivityPause() { - mInfoManager.setController(null); - mControlManager.setController(null); - mVideoManager.setController(null); - super.onActivityPause(); - } - - /* (non-Javadoc) - * @see org.xbmc.android.remote.presentation.controller.IController#onActivityResume(android.app.Activity) - */ - public void onActivityResume(Activity activity) { - super.onActivityResume(activity); - mInfoManager.setController(this); - mControlManager.setController(this); - mVideoManager.setController(this); - mInfoManager.getSystemInfo(mXbmcStatusHandler, SystemInfo.SYSTEM_BUILD_VERSION, mActivity.getApplicationContext()); - } - - public void playUrl(String url) { - mControlManager.playUrl(new DataResponse(), url, mActivity.getApplicationContext()); - } - - public void setupStatusHandler() { - mXbmcStatusHandler = new DataResponse() { - public void run() { - if (!value.equals("")) { - checkIntent(); - } - } - }; - } - - @Override - public void onError(Exception exception) { - final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); - try { - throw exception; - } catch (Exception e) { - builder.setTitle("Unable to send URL to XBMC!"); - builder.setMessage(e.getMessage()); - builder.setNeutralButton("Ok", new OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - mActivity.finish(); - } - }); - final AlertDialog alert = builder.create(); - try { - alert.show(); - } catch (Exception ee) { - e.printStackTrace(); - } - } - - } - - private static boolean isValidURL(String path){ - if(path == null || path.equals("")) - return false; - try{ - new URL(path); - } catch(MalformedURLException e) { - return false; - } - return true; - } - - private static String hasURL(String path){ - String[] words = path.split(" "); - for (String word : words) { - if (word.startsWith("http://") || word.startsWith("https://")) { - return word; - } - } - return null; - } - - /** - * Checks the intent that created/resumed this activity. Used to see if we are being handed - * an URL that should be passed to XBMC. - */ - private void checkIntent(){ - Intent intent = mActivity.getIntent(); - final String action = intent.getAction(); - - if(action != null) { - Log.i("CHECKINTENT", action); - if ( action.equals(UrlIntentActivity.ACTION) ){ - //final String path = intent.getData().toString(); - final String path = hasURL(intent.getStringExtra(Intent.EXTRA_TEXT)); - final String subjectTxt = intent.getStringExtra(Intent.EXTRA_SUBJECT); - - if(isIMDB(subjectTxt)){ - handleIMDb(path); - cleaupIntent(intent); - } - else if(isValidURL(path)){ - handleURL(path); - cleaupIntent(intent); - } - - } - } - } - - private void handleIMDb(String path) { - final Pattern pattern = Pattern.compile("^http://imdb\\.com/title/(tt\\d{7})$", Pattern.MULTILINE); - final Matcher matcher = pattern.matcher(path); - if(matcher.find()){ - final String imdbIdRequested = matcher.group(1); - final ProgressDialog dialog = ProgressDialog.show(mActivity, "Loading Movies", null, true); - mVideoManager.getMovies(new DataResponse>(){ - public void run() { - dialog.dismiss(); - processImdbResults(imdbIdRequested, value); - }; - }, mActivity.getApplicationContext()); - }else{ - Toast.makeText(mActivity, "Error parsing IMDb link", Toast.LENGTH_LONG).show(); //TODO: Externalize string - mActivity.finish(); - } - } - - private void processImdbResults(String imdbIdRequested, ArrayList movies) { - Movie movieFound = null; - for(Movie movie : movies){ - if(movie.getIMDbId().equals(imdbIdRequested)){ - movieFound = movie; - break; - } - } - if(movieFound == null){ - Toast.makeText(mActivity, "Movie not found in XBMC library", Toast.LENGTH_LONG).show(); //TODO: Externalize string - mActivity.finish(); - }else{ - maybePlayMovie(movieFound); - } - } - - private void maybePlayMovie(final Movie movie) { -// Toast.makeText(mActivity, movie.getName(), Toast.LENGTH_LONG).show(); - final String message = "Do you want to play\n" + movie.getName() + "\non XBMC?"; - boolean confirmPlayOnXBMC = getConfirmPlayOnXBMC(); - if (confirmPlayOnXBMC) { - final Builder builder = new Builder(mActivity); - builder.setTitle("Play Movie on XBMC?"); - builder.setMessage(message); - builder.setCancelable(true); - builder.setIcon(drawable.icon); - builder.setNeutralButton("Yes", new android.content.DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - playMovieThreaded(movie); - mActivity.finish(); - } - }); - builder.setCancelable(true); - builder.setNegativeButton("No", new android.content.DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - mActivity.finish(); - } - }); - - final AlertDialog alert = builder.create(); - try { - alert.show(); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - playMovieThreaded(movie); - mActivity.finish(); - } - } - - private void playMovieThreaded(Movie movie) { - mControlManager.playFile(new DataResponse() { - public void run() { - if (value) { - mActivity.startActivity(new Intent(mActivity.getApplicationContext(), NowPlayingActivity.class)); - } - } - }, movie.getPath(), 1, mActivity.getApplicationContext()); - } - - private boolean isIMDB(String subjectTxt) { - return subjectTxt.startsWith(IMDb_SHARE_PREFIX); - } - - private void cleaupIntent(Intent intent) { - //cleanup so we won't trigger again. - intent.setAction(null); - intent.setData(null); - } - - private void handleURL(final String path) { - // If it is a youtube URL, we have to parse the video id from it and send it to the youtube plugin. - // The syntax for that is plugin://plugin.video.youtube/?path=/root/search%26action=play_video%26videoid=VIDEOID - Uri playuri = Uri.parse(path); - final String url; - final String message; - String youtubeVideoId = YoutubeURLParser.parseYoutubeURL(playuri); - - if(youtubeVideoId != null){ - url = "plugin://plugin.video.youtube/?path=/root/search&action=play_video&videoid=" + youtubeVideoId; - message = "Do you want to play\nYoutube video " + youtubeVideoId + " on XBMC? Youtube addon required!"; - }else{ - // Not a youtube URL or unparsable YouTube URL so just pass it on to XBMC as-is - url = playuri.toString(); - message = "Do you want to play\n" + path + "\n on XBMC?"; - } - - boolean confirmPlayOnXBMC = getConfirmPlayOnXBMC(); - if (confirmPlayOnXBMC) { - final Builder builder = new Builder(mActivity); - builder.setTitle("Play URL on XBMC?"); - builder.setMessage(message); - builder.setCancelable(true); - builder.setIcon(drawable.icon); - builder.setNeutralButton("Yes", new android.content.DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - playUrlThreaded(url); - mActivity.finish(); - } - }); - builder.setCancelable(true); - builder.setNegativeButton("No", new android.content.DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - mActivity.finish(); - } - }); - - final AlertDialog alert = builder.create(); - try { - alert.show(); - } catch (Exception e) { - e.printStackTrace(); - } - } else { - playUrlThreaded(url); - mActivity.finish(); - } - } - - private void playUrlThreaded(final String url) { - new Thread(){ - public void run(){ - Looper.prepare(); - playUrl(url); - Looper.loop(); - } - }.start(); - } - - private boolean getConfirmPlayOnXBMC() { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext()); - boolean confirmPlayOnXBMC = prefs.getBoolean(CONFIRM_PLAY_ON_XBMC, true); - return confirmPlayOnXBMC; - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.remote.presentation.controller; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.AlertDialog.Builder; +import android.app.ProgressDialog; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.preference.PreferenceManager; +import android.util.Log; +import android.widget.Toast; + +import org.xbmc.android.remote.R.drawable; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; +import org.xbmc.android.remote.presentation.activity.UrlIntentActivity; +import org.xbmc.android.util.YoutubeURLParser; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.IVideoManager; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.object.Movie; +import org.xbmc.api.presentation.INotifiableController; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class that is called when XBMC locally tries to open any media content. The + * user then has an additional option "Play in XBMC". + * + * @author Team XBMC + */ +public class UrlIntentController extends AbstractController implements IController, INotifiableController { + + private static final String IMDb_SHARE_PREFIX = "IMDb:"; + private static final String CONFIRM_PLAY_ON_XBMC = "setting_confirm_play_on_xbmc"; + + private final IControlManager mControlManager; + private final IInfoManager mInfoManager; + private final IVideoManager mVideoManager; + + private DataResponse mXbmcStatusHandler; + + public UrlIntentController(Activity activity, Handler handler) { + super.onCreate(activity, handler); + mInfoManager = ManagerFactory.getInfoManager(this); + mControlManager = ManagerFactory.getControlManager(this); + mVideoManager = ManagerFactory.getVideoManager(this); + } + + private static boolean isValidURL(String path) { + if (path == null || path.equals("")) + return false; + try { + new URL(path); + } catch (MalformedURLException e) { + return false; + } + return true; + } + + private static String hasURL(String path) { + String[] words = path.split(" "); + for (String word : words) { + if (word.startsWith("http://") || word.startsWith("https://")) { + return word; + } + } + return null; + } + + /* (non-Javadoc) + * @see org.xbmc.android.remote.presentation.controller.IController#onActivityPause() + */ + public void onActivityPause() { + mInfoManager.setController(null); + mControlManager.setController(null); + mVideoManager.setController(null); + super.onActivityPause(); + } + + /* (non-Javadoc) + * @see org.xbmc.android.remote.presentation.controller.IController#onActivityResume(android.app.Activity) + */ + public void onActivityResume(Activity activity) { + super.onActivityResume(activity); + mInfoManager.setController(this); + mControlManager.setController(this); + mVideoManager.setController(this); + mInfoManager.getSystemInfo(mXbmcStatusHandler, SystemInfo.SYSTEM_BUILD_VERSION, + mActivity.getApplicationContext()); + } + + public void playUrl(String url) { + mControlManager.playUrl(new DataResponse(), url, mActivity.getApplicationContext()); + } + + public void setupStatusHandler() { + mXbmcStatusHandler = new DataResponse() { + public void run() { + if (!value.equals("")) { + checkIntent(); + } + } + }; + } + + @Override + public void onError(Exception exception) { + final AlertDialog.Builder builder = new AlertDialog.Builder(mActivity); + try { + throw exception; + } catch (Exception e) { + builder.setTitle("Unable to send URL to XBMC!"); + builder.setMessage(e.getMessage()); + builder.setNeutralButton("Ok", new OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + mActivity.finish(); + } + }); + final AlertDialog alert = builder.create(); + try { + alert.show(); + } catch (Exception ee) { + e.printStackTrace(); + } + } + + } + + /** + * Checks the intent that created/resumed this activity. Used to see if we are being handed + * an URL that should be passed to XBMC. + */ + private void checkIntent() { + Intent intent = mActivity.getIntent(); + final String action = intent.getAction(); + + if (action != null) { + Log.i("CHECKINTENT", action); + if (action.equals(UrlIntentActivity.ACTION)) { + //final String path = intent.getData().toString(); + final String path = hasURL(intent.getStringExtra(Intent.EXTRA_TEXT)); + final String subjectTxt = intent.getStringExtra(Intent.EXTRA_SUBJECT); + + if (isIMDB(subjectTxt)) { + handleIMDb(path); + cleaupIntent(intent); + } else if (isValidURL(path)) { + handleURL(path); + cleaupIntent(intent); + } + + } + } + } + + private void handleIMDb(String path) { + final Pattern pattern = Pattern.compile("^http://imdb\\.com/title/(tt\\d{7})$", Pattern.MULTILINE); + final Matcher matcher = pattern.matcher(path); + if (matcher.find()) { + final String imdbIdRequested = matcher.group(1); + final ProgressDialog dialog = ProgressDialog.show(mActivity, "Loading Movies", null, true); + mVideoManager.getMovies(new DataResponse>() { + public void run() { + dialog.dismiss(); + processImdbResults(imdbIdRequested, value); + } + + ; + }, mActivity.getApplicationContext()); + } else { + Toast.makeText(mActivity, "Error parsing IMDb link", Toast.LENGTH_LONG).show(); //TODO: Externalize string + mActivity.finish(); + } + } + + private void processImdbResults(String imdbIdRequested, ArrayList movies) { + Movie movieFound = null; + for (Movie movie : movies) { + if (movie.getIMDbId().equals(imdbIdRequested)) { + movieFound = movie; + break; + } + } + if (movieFound == null) { + Toast.makeText(mActivity, "Movie not found in XBMC library", Toast.LENGTH_LONG).show(); //TODO: + // Externalize string + mActivity.finish(); + } else { + maybePlayMovie(movieFound); + } + } + + private void maybePlayMovie(final Movie movie) { +// Toast.makeText(mActivity, movie.getName(), Toast.LENGTH_LONG).show(); + final String message = "Do you want to play\n" + movie.getName() + "\non XBMC?"; + boolean confirmPlayOnXBMC = getConfirmPlayOnXBMC(); + if (confirmPlayOnXBMC) { + final Builder builder = new Builder(mActivity); + builder.setTitle("Play Movie on XBMC?"); + builder.setMessage(message); + builder.setCancelable(true); + builder.setIcon(drawable.icon); + builder.setNeutralButton("Yes", new android.content.DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + playMovieThreaded(movie); + mActivity.finish(); + } + }); + builder.setCancelable(true); + builder.setNegativeButton("No", new android.content.DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + mActivity.finish(); + } + }); + + final AlertDialog alert = builder.create(); + try { + alert.show(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + playMovieThreaded(movie); + mActivity.finish(); + } + } + + private void playMovieThreaded(Movie movie) { + mControlManager.playFile(new DataResponse() { + public void run() { + if (value) { + mActivity.startActivity(new Intent(mActivity.getApplicationContext(), NowPlayingActivity.class)); + } + } + }, movie.getPath(), 1, mActivity.getApplicationContext()); + } + + private boolean isIMDB(String subjectTxt) { + return subjectTxt.startsWith(IMDb_SHARE_PREFIX); + } + + private void cleaupIntent(Intent intent) { + //cleanup so we won't trigger again. + intent.setAction(null); + intent.setData(null); + } + + private void handleURL(final String path) { + // If it is a youtube URL, we have to parse the video id from it and send it to the youtube plugin. + // The syntax for that is plugin://plugin.video + // .youtube/?path=/root/search%26action=play_video%26videoid=VIDEOID + Uri playuri = Uri.parse(path); + final String url; + final String message; + String youtubeVideoId = YoutubeURLParser.parseYoutubeURL(playuri); + + if (youtubeVideoId != null) { + url = "plugin://plugin.video.youtube/?path=/root/search&action=play_video&videoid=" + youtubeVideoId; + message = "Do you want to play\nYoutube video " + youtubeVideoId + " on XBMC? Youtube addon required!"; + } else { + // Not a youtube URL or unparsable YouTube URL so just pass it on to XBMC as-is + url = playuri.toString(); + message = "Do you want to play\n" + path + "\n on XBMC?"; + } + + boolean confirmPlayOnXBMC = getConfirmPlayOnXBMC(); + if (confirmPlayOnXBMC) { + final Builder builder = new Builder(mActivity); + builder.setTitle("Play URL on XBMC?"); + builder.setMessage(message); + builder.setCancelable(true); + builder.setIcon(drawable.icon); + builder.setNeutralButton("Yes", new android.content.DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + playUrlThreaded(url); + mActivity.finish(); + } + }); + builder.setCancelable(true); + builder.setNegativeButton("No", new android.content.DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + mActivity.finish(); + } + }); + + final AlertDialog alert = builder.create(); + try { + alert.show(); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + playUrlThreaded(url); + mActivity.finish(); + } + } + + private void playUrlThreaded(final String url) { + new Thread() { + public void run() { + Looper.prepare(); + playUrl(url); + Looper.loop(); + } + }.start(); + } + + private boolean getConfirmPlayOnXBMC() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mActivity.getApplicationContext + ()); + boolean confirmPlayOnXBMC = prefs.getBoolean(CONFIRM_PLAY_ON_XBMC, true); + return confirmPlayOnXBMC; + } +} diff --git a/app/src/main/java/org/xbmc/android/remote/presentation/drawable/CrossFadeDrawable.java b/app/src/main/java/org/xbmc/android/remote/presentation/drawable/CrossFadeDrawable.java new file mode 100644 index 00000000..c976e3c0 --- /dev/null +++ b/app/src/main/java/org/xbmc/android/remote/presentation/drawable/CrossFadeDrawable.java @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2008 The Android Open Source Project, Romain Guy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.xbmc.android.remote.presentation.drawable; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.SystemClock; + +public class CrossFadeDrawable extends Drawable { + private static final int TRANSITION_STARTING = 0; + private static final int TRANSITION_RUNNING = 1; + private static final int TRANSITION_NONE = 2; + + private int mTransitionState = TRANSITION_NONE; + private final Paint mStartPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private final Paint mEndPaint = new Paint(Paint.FILTER_BITMAP_FLAG); + private final Handler mHandler; + private final Runnable mInvalidater; + private boolean mCrossFade; + private boolean mReverse; + private long mStartTimeMillis; + private int mFrom; + private int mTo; + private int mDuration; + private int mOriginalDuration; + private int mAlpha; + private Bitmap mStart; + private Bitmap mEnd; + private float mStartX; + private float mStartY; + private float mEndX; + private float mEndY; + + public CrossFadeDrawable(Bitmap start, Bitmap end) { + mStart = start; + mEnd = end; + + /* This is apparently necessary to work around a bug in the + * drawing cache. Romain fixes his bug upstream here: + * http://code.google.com/p/shelves/source/detail?r=15 */ + mHandler = new Handler(); + mInvalidater = new Runnable() { + public void run() { + invalidateSelf(); + } + }; + } + + /** + * Begin the second layer on top of the first layer. + * + * @param durationMillis The length of the transition in milliseconds + */ + public void startTransition(int durationMillis) { + mFrom = 0; + mTo = 255; + mAlpha = 0; + mOriginalDuration = mDuration = durationMillis; + mReverse = false; + mTransitionState = mStart != mEnd ? TRANSITION_STARTING : TRANSITION_NONE; + invalidateSelf(); + } + + /** + * Show only the first layer. + */ + public void resetTransition() { + mAlpha = 0; + mTransitionState = TRANSITION_NONE; + invalidateSelf(); + } + + /** + * Reverses the transition, picking up where the transition currently is. + * If the transition is not currently running, this will start the transition + * with the specified duration. If the transition is already running, the last + * known duration will be used. + * + * @param duration The duration to use if no transition is running. + */ + public void reverseTransition(int duration) { + final long time = SystemClock.uptimeMillis(); + + if (time - mStartTimeMillis > mOriginalDuration) { + if (mAlpha == 0) { + mFrom = 0; + mTo = 255; + mAlpha = 0; + mReverse = false; + } else { + mFrom = 255; + mTo = 0; + mAlpha = 255; + mReverse = true; + } + mDuration = mOriginalDuration = duration; + mTransitionState = TRANSITION_STARTING; + mHandler.post(mInvalidater); + return; + } + + mReverse = !mReverse; + mFrom = mAlpha; + mTo = mReverse ? 0 : 255; + mDuration = (int) (mReverse ? time - mStartTimeMillis : + mOriginalDuration - (time - mStartTimeMillis)); + mTransitionState = TRANSITION_STARTING; + } + + @Override + public void draw(Canvas canvas) { + boolean done = true; + + switch (mTransitionState) { + case TRANSITION_STARTING: + mStartTimeMillis = SystemClock.uptimeMillis(); + done = false; + mTransitionState = TRANSITION_RUNNING; + break; + case TRANSITION_RUNNING: + if (mStartTimeMillis >= 0) { + float normalized = (float) (SystemClock.uptimeMillis() - mStartTimeMillis) / + mDuration; + + done = normalized >= 1.0f; + mAlpha = (int) (mFrom + (mTo - mFrom) * Math.min(normalized, 1.0f)); + + if (done) { + mTransitionState = TRANSITION_NONE; + mHandler.post(mInvalidater); + } + } + break; + } + + final int alpha = mAlpha; + final boolean crossFade = mCrossFade; + + Bitmap bitmap = mStart; + Paint paint = mStartPaint; + + if (!crossFade || 255 - alpha > 0) { + if (crossFade) { + paint.setAlpha(255 - alpha); + } + canvas.drawBitmap(bitmap, mStartX, mStartY, paint); + if (crossFade) { + paint.setAlpha(0xFF); + } + } + + if (alpha > 0) { + bitmap = mEnd; + paint = mEndPaint; + paint.setAlpha(alpha); + canvas.drawBitmap(bitmap, mEndX, mEndY, paint); + paint.setAlpha(0xFF); + } + + if (!done) { + mHandler.post(mInvalidater); + } + } + + Bitmap getStart() { + return mStart; + } + + void setStart(Bitmap start) { + mStart = start; + invalidateSelf(); + } + + Bitmap getEnd() { + return mEnd; + } + + public void setEnd(Bitmap end) { + mEnd = end; + invalidateSelf(); + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + + final int width = right - left; + final int height = bottom - top; + + mStartX = (width - mStart.getWidth()) / 2.0f; + mStartY = height - mStart.getHeight(); + + mEndX = (width - mEnd.getWidth()) / 2.0f; + mEndY = height - mEnd.getHeight(); + } + + @Override + public int getIntrinsicWidth() { + return Math.max(mStart.getWidth(), + mEnd.getWidth()); + } + + @Override + public int getIntrinsicHeight() { + return Math.max(mStart.getHeight(), mEnd.getHeight()); + } + + @Override + public int getMinimumWidth() { + return Math.max(mStart.getWidth(), mEnd.getWidth()); + } + + @Override + public int getMinimumHeight() { + return Math.max(mStart.getHeight(), mEnd.getHeight()); + } + + @Override + public void setDither(boolean dither) { + mStartPaint.setDither(true); + mEndPaint.setDither(true); + } + + @Override + public void setFilterBitmap(boolean filter) { + mStartPaint.setFilterBitmap(true); + mEndPaint.setFilterBitmap(true); + } + + /** + * Ignored. + */ + public void setAlpha(int alpha) { + } + + public void setColorFilter(ColorFilter cf) { + mStartPaint.setColorFilter(cf); + mEndPaint.setColorFilter(cf); + } + + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } + + /** + * Indicates whether the cross fade is enabled for this transition. + * + * @return True if cross fading is enabled, false otherwise. + */ + boolean isCrossFadeEnabled() { + return mCrossFade; + } + + /** + * Enables or disables the cross fade of the drawables. When cross fade + * is disabled, the first drawable is always drawn opaque. With cross + * fade enabled, the first drawable is drawn with the opposite alpha of + * the second drawable. + * + * @param enabled True to enable cross fading, false otherwise. + */ + public void setCrossFadeEnabled(boolean enabled) { + mCrossFade = enabled; + } +} diff --git a/src/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java b/app/src/main/java/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java similarity index 51% rename from src/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java rename to app/src/main/java/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java index 52a0df0c..49a66337 100644 --- a/src/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/drawable/FastBitmapDrawable.java @@ -16,58 +16,58 @@ package org.xbmc.android.remote.presentation.drawable; -import android.graphics.drawable.Drawable; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.PixelFormat; import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; public class FastBitmapDrawable extends Drawable { - private final Bitmap mBitmap; + private final Bitmap mBitmap; - public FastBitmapDrawable(Bitmap b) { - mBitmap = b; - } + public FastBitmapDrawable(Bitmap b) { + mBitmap = b; + } - @Override - public void draw(Canvas canvas) { - canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null); - } + @Override + public void draw(Canvas canvas) { + canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null); + } - @Override - public int getOpacity() { - return PixelFormat.TRANSLUCENT; - } + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } - @Override - public void setAlpha(int alpha) { - } + @Override + public void setAlpha(int alpha) { + } - @Override - public void setColorFilter(ColorFilter cf) { - } + @Override + public void setColorFilter(ColorFilter cf) { + } - @Override - public int getIntrinsicWidth() { - return mBitmap.getWidth(); - } + @Override + public int getIntrinsicWidth() { + return mBitmap.getWidth(); + } - @Override - public int getIntrinsicHeight() { - return mBitmap.getHeight(); - } + @Override + public int getIntrinsicHeight() { + return mBitmap.getHeight(); + } - @Override - public int getMinimumWidth() { - return mBitmap.getWidth(); - } + @Override + public int getMinimumWidth() { + return mBitmap.getWidth(); + } - @Override - public int getMinimumHeight() { - return mBitmap.getHeight(); - } + @Override + public int getMinimumHeight() { + return mBitmap.getHeight(); + } - public Bitmap getBitmap() { - return mBitmap; - } + public Bitmap getBitmap() { + return mBitmap; + } } diff --git a/app/src/main/java/org/xbmc/android/remote/presentation/notification/BigPictureNotificationBuilder.java b/app/src/main/java/org/xbmc/android/remote/presentation/notification/BigPictureNotificationBuilder.java new file mode 100644 index 00000000..90d7281c --- /dev/null +++ b/app/src/main/java/org/xbmc/android/remote/presentation/notification/BigPictureNotificationBuilder.java @@ -0,0 +1,37 @@ +package org.xbmc.android.remote.presentation.notification; + +import android.annotation.TargetApi; +import android.app.Notification; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +@TargetApi(16) +/** + * On Jelly Bean (level 16) and up, we can build on a large icon notification to expand the + * thumbnail and expose playback controls. + */ +public class BigPictureNotificationBuilder extends LargeIconNotificationBuilder { + + protected BigPictureNotificationBuilder(Context context) { + super(context); + } + + @Override + public Notification build(String title, String text, int icon, Bitmap thumb) { + Notification.Builder superBuilder = super.getBuilder(title, text, icon, thumb); + if (thumb == null) { + superBuilder + .setSmallIcon(icon) + .setContentText(text); + return finalize(superBuilder.build()); + } else { + Notification notification = new Notification.BigPictureStyle(superBuilder) + .bigPicture(thumb) + .bigLargeIcon(BitmapFactory.decodeResource(mContext.getResources(), icon)) + .setSummaryText(text) + .build(); + return finalize(notification); + } + } +} diff --git a/app/src/main/java/org/xbmc/android/remote/presentation/notification/LargeIconNotificationBuilder.java b/app/src/main/java/org/xbmc/android/remote/presentation/notification/LargeIconNotificationBuilder.java new file mode 100644 index 00000000..c43ca61b --- /dev/null +++ b/app/src/main/java/org/xbmc/android/remote/presentation/notification/LargeIconNotificationBuilder.java @@ -0,0 +1,52 @@ +package org.xbmc.android.remote.presentation.notification; + +import android.annotation.TargetApi; +import android.app.Notification; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; + +@TargetApi(11) +/** + * On Honeycomb (level 11) and up, we can include a thumbnail in addition to an icon. + */ +public class LargeIconNotificationBuilder extends NotificationBuilder { + protected LargeIconNotificationBuilder(Context context) { + super(context); + } + + protected Notification.Builder getBuilder(String title, String text, int icon, Bitmap thumb) { + // Left to its own devices, Notification.Builder will crop the thumbnail + // to the size of the view largeIcon goes into. This is rarely an + // informative image, so we crop the largest possible square from the + // center of the thumbnail and use that. + Bitmap scaledThumb = null; + if (thumb != null) { + Resources resources = mContext.getResources(); + int iconWidth = resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_width); + int iconHeight = resources.getDimensionPixelSize(android.R.dimen.notification_large_icon_height); + int thumbWidth = thumb.getWidth(); + int thumbHeight = thumb.getHeight(); + if (thumbWidth > thumbHeight) { + iconWidth = (int) (((float) iconHeight / thumbHeight) * thumbWidth); + } else { + iconHeight = (int) (((float) iconWidth / thumbWidth) * thumbHeight); + } + scaledThumb = Bitmap.createScaledBitmap(thumb, iconWidth, iconHeight, false); + } + Notification.Builder largeIconNotificationBuilder = new Notification.Builder(mContext) + .setContentTitle(title) + .setContentText(text) + .setSmallIcon(icon) + .setLargeIcon(scaledThumb) + .setContentIntent(mIntent); + return largeIconNotificationBuilder; + } + + @Override + public Notification build(String title, String text, int icon, Bitmap thumb) { + Notification.Builder builder = getBuilder(title, text, icon, thumb); + Notification notification = builder.getNotification(); + return finalize(notification); + } +} diff --git a/app/src/main/java/org/xbmc/android/remote/presentation/notification/NotificationBuilder.java b/app/src/main/java/org/xbmc/android/remote/presentation/notification/NotificationBuilder.java new file mode 100644 index 00000000..48cc1d2c --- /dev/null +++ b/app/src/main/java/org/xbmc/android/remote/presentation/notification/NotificationBuilder.java @@ -0,0 +1,62 @@ +package org.xbmc.android.remote.presentation.notification; + +import android.app.Notification; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.os.Build; + +import org.xbmc.android.remote.presentation.activity.NowPlayingActivity; + +public class NotificationBuilder { + protected final PendingIntent mIntent; + protected final Context mContext; + + protected NotificationBuilder(Context context) { + mContext = context; + final Intent actintent = new Intent(mContext, NowPlayingActivity.class); + actintent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent + .FLAG_ACTIVITY_PREVIOUS_IS_TOP); + mIntent = PendingIntent.getActivity(mContext, 0, actintent, 0); + } + + /** + * Return the richest NotificationBuilder that will work on this platform. + */ + public static NotificationBuilder getInstance(Context context) { + if (Integer.valueOf(Build.VERSION.SDK) >= Build.VERSION_CODES.JELLY_BEAN) { + return new BigPictureNotificationBuilder(context); + } + + if (Integer.valueOf(Build.VERSION.SDK) >= Build.VERSION_CODES.HONEYCOMB) { + return new LargeIconNotificationBuilder(context); + } + + return new NotificationBuilder(context); + } + + /** + * Create a simple notification. Subclasses may take advantage of newer APIs. + * + * @param title + * @param text + * @param icon The id of a drawable to be used as the small icon. Will display on all platforms. + * @param thumb A bitmap representing the currently playing item. Ignored on lower API levels. + * @return + */ + public Notification build(String title, String text, int icon, Bitmap thumb) { + Notification notification = new Notification(icon, title, System.currentTimeMillis()); + notification.setLatestEventInfo(mContext, title, text, mIntent); + return finalize(notification); + } + + /** + * Perform modifications to a notification that apply to all API levels. All definitions of + * buildNotification should call this before returning. + */ + protected Notification finalize(Notification notification) { + notification.flags |= Notification.FLAG_ONGOING_EVENT; + return notification; + } +} diff --git a/app/src/main/java/org/xbmc/android/remote/presentation/notification/NowPlayingNotificationManager.java b/app/src/main/java/org/xbmc/android/remote/presentation/notification/NowPlayingNotificationManager.java new file mode 100644 index 00000000..39a10503 --- /dev/null +++ b/app/src/main/java/org/xbmc/android/remote/presentation/notification/NowPlayingNotificationManager.java @@ -0,0 +1,162 @@ +package org.xbmc.android.remote.presentation.notification; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.graphics.Bitmap; +import android.os.Handler; +import android.os.Message; +import android.preference.PreferenceManager; +import android.util.Log; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.NowPlayingPollerThread; +import org.xbmc.android.util.ConnectionFactory; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.info.PlayStatus; +import org.xbmc.api.type.MediaType; + +public class NowPlayingNotificationManager implements OnSharedPreferenceChangeListener { + + public static final int NOW_PLAYING_ID = 0; + private static String TAG = "NowPlayingNotificationManager"; + private static NowPlayingNotificationManager mInstance = null; + private static NotificationBuilder mNotificationBuilder = null; + private static boolean mEnabled = true; + private final Handler mPollingHandler = new Handler() { + public void handleMessage(Message msg) { + Bitmap thumb = ConnectionFactory.getNowPlayingPoller(mContext).getNowPlayingCover(); + switch (msg.what) { + case NowPlayingPollerThread.MESSAGE_PLAYLIST_ITEM_CHANGED: + case NowPlayingPollerThread.MESSAGE_PLAYSTATE_CHANGED: + ICurrentlyPlaying curr = (ICurrentlyPlaying) msg.getData().get(NowPlayingPollerThread + .BUNDLE_CURRENTLY_PLAYING); + final int status = curr.getPlayStatus(); + if (status != PlayStatus.STOPPED) { + final int mediaType = curr.getMediaType(); + switch (mediaType) { + case MediaType.PICTURES: + showSlideshowNotification(curr.getTitle(), curr.getAlbum(), thumb); + break; + case MediaType.VIDEO_MOVIE: + case MediaType.VIDEO_TVEPISODE: + case MediaType.VIDEO_TVSEASON: + case MediaType.VIDEO_TVSHOW: + case MediaType.VIDEO: + showVideoNotification(curr.getTitle(), curr.getArtist(), thumb, status); + break; + default: + if (status == PlayStatus.PLAYING) { + showPlayingNotification(curr.getArtist(), curr.getTitle(), thumb); + } else if (status == PlayStatus.PAUSED) { + showPausedNotification(curr.getArtist(), curr.getTitle(), thumb); + } + break; + } + } else { + removeNotification(); + } + break; + case NowPlayingPollerThread.MESSAGE_CONNECTION_ERROR: + removeNotification(); + break; + case NowPlayingPollerThread.MESSAGE_RECONFIGURE: + + new Thread() { + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + Log.e(TAG, Log.getStackTraceString(e)); + } + startNotificating(); + } + }.start(); + } + } + }; + private Context mContext = null; + + private NowPlayingNotificationManager(Context context) { + mContext = context; + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); + mNotificationBuilder = NotificationBuilder.getInstance(mContext); + mEnabled = prefs.getBoolean("setting_show_notification", false); + prefs.registerOnSharedPreferenceChangeListener(this); + } + + public static NowPlayingNotificationManager getInstance(Context context) { + if (mInstance == null) + mInstance = new NowPlayingNotificationManager(context); + return mInstance; + } + + public void startNotificating() { + if (mEnabled) + ConnectionFactory.subscribeNowPlayingPollerThread(mContext, mPollingHandler); + } + + public void stopNotificating() { + ConnectionFactory.unSubscribeNowPlayingPollerThread(mContext, mPollingHandler, true); + removeNotification(); + } + + public void showPausedNotification(String artist, String title, Bitmap thumb) { + if ((artist == null || artist.equals("")) && (title == null || title.equals(""))) + removeNotification(); + else + showNotification(artist, title, "Paused on XBMC", R.drawable.notif_pause, thumb); + } + + public void showPlayingNotification(String artist, String title, Bitmap thumb) { + if ((artist == null || artist.equals("")) && (title == null || title.equals(""))) + removeNotification(); + else + showNotification(artist, title, "Now playing on XBMC", R.drawable.notif_play, thumb); + } + + public void showNotification(String artist, String title, String text, int icon, Bitmap thumb) { + Notification notification = mNotificationBuilder.build(artist + " - " + title, text, icon, thumb); + final String ns = Context.NOTIFICATION_SERVICE; + NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(ns); + notificationManager.notify(NOW_PLAYING_ID, notification); + } + + public void removeNotification() { + final String ns = Context.NOTIFICATION_SERVICE; + NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(ns); + notificationManager.cancel(NOW_PLAYING_ID); + } + + public void showSlideshowNotification(String fileName, String folder, Bitmap thumb) { + Notification notification = mNotificationBuilder.build(folder + "/" + fileName, "Slideshow on XBMC", + R.drawable.notif_pic, thumb); + final String ns = Context.NOTIFICATION_SERVICE; + NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(ns); + notificationManager.notify(NOW_PLAYING_ID, notification); + } + + public void showVideoNotification(String movie, String genre, Bitmap thumb, int status) { + int smallIconId = (status == PlayStatus.PAUSED) ? R.drawable.notif_pause : R.drawable.notif_play; + Notification notification = mNotificationBuilder.build(movie, genre, smallIconId, thumb); + final String ns = Context.NOTIFICATION_SERVICE; + NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(ns); + notificationManager.notify(NOW_PLAYING_ID, notification); + } + + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals("setting_show_notification")) { + boolean newState = sharedPreferences.getBoolean(key, true); + if (newState) { + mEnabled = true; + startNotificating(); + } else { + mEnabled = false; + stopNotificating(); + } + + } + } +} diff --git a/src/org/xbmc/android/remote/presentation/widget/AbstractItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/AbstractItemView.java similarity index 72% rename from src/org/xbmc/android/remote/presentation/widget/AbstractItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/AbstractItemView.java index 9c546fe2..a9780f0e 100644 --- a/src/org/xbmc/android/remote/presentation/widget/AbstractItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/AbstractItemView.java @@ -1,145 +1,141 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.CoverResponse; -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.view.View; - -public abstract class AbstractItemView extends View { - - protected final static Paint PAINT = new Paint(); - - protected final int padding; - protected final int size12, size18, size20, size25, size35, size42, size50, size55, size59, size65, size103; - - public final static int MSG_UPDATE_COVER = 1; - - protected static Bitmap sSelected; - - private final CoverResponse mResponse; - private final Bitmap mDefaultCover; - protected Bitmap mCover; - protected final int mWidth; - protected final Drawable mSelection; - protected int mDefaultColor = Color.WHITE; - - private final Handler mHandler = new Handler() { - public void handleMessage(android.os.Message msg) { - switch (msg.what) { - case MSG_UPDATE_COVER: - setCover((Bitmap)msg.obj); - break; - } - }; - }; - - public int position; - public String title; - - protected abstract Rect getPosterRect(); - - public AbstractItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, int thumbSize, boolean fixedSize) { - super(context); - - if (manager != null) { - mResponse = new CoverResponse(context, manager, defaultCover, thumbSize, mHandler); - } else { - mResponse = null; - } - - mWidth = width; - mDefaultCover = defaultCover; - mSelection = selection; - - final float screenScale = fixedSize ? 1 : ThumbSize.SCREEN_SCALE; - padding = (int)(5 * ThumbSize.PIXEL_SCALE * screenScale); - size12 = (int)(12 * ThumbSize.PIXEL_SCALE * screenScale); - size18 = (int)(18 * ThumbSize.PIXEL_SCALE * screenScale); - size20 = (int)(20 * ThumbSize.PIXEL_SCALE * screenScale); - size25 = (int)(25 * ThumbSize.PIXEL_SCALE * screenScale); - size35 = (int)(35 * ThumbSize.PIXEL_SCALE * screenScale); - size42 = (int)(42 * ThumbSize.PIXEL_SCALE * screenScale); - size50 = (int)(50 * ThumbSize.PIXEL_SCALE * screenScale); - size55 = (int)(55 * ThumbSize.PIXEL_SCALE * screenScale); - size59 = (int)(59 * ThumbSize.PIXEL_SCALE * screenScale); - size65 = (int)(65 * ThumbSize.PIXEL_SCALE * screenScale); - size103 = (int)(103 * ThumbSize.PIXEL_SCALE * screenScale); - } - - public AbstractItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - this(context, null, width, defaultCover, selection, 0, fixedSize); - } - - protected void drawPoster(Canvas canvas, int posterWidth, int posterHeight, int canvasWidth) { - // background - if ((isSelected() || isPressed()) && mSelection != null) { - mSelection.setBounds(posterWidth, 0, canvasWidth, posterHeight); - mSelection.draw(canvas); - } else { - PAINT.setColor(mDefaultColor); - canvas.drawRect(posterWidth, 0, canvasWidth, posterHeight, PAINT); - } - - // poster - Bitmap cover = mCover; - if(mCover == null || mCover.isRecycled()) - { - cover = mDefaultCover; - } - - if (cover != null && !cover.isRecycled()) { - int dx = (cover.getWidth() - posterWidth) / 2; - int dy = (cover.getHeight() - posterHeight) / 2; - Rect src = null; - if(dx > 0 || dy > 0) { - src = new Rect(dx, dy, dx + posterWidth, dy + posterHeight); - } - Rect dst = getPosterRect(); - PAINT.setColor(mDefaultColor); - canvas.drawRect(0, 0, posterWidth, posterHeight, PAINT); - canvas.drawBitmap(cover, src, dst, PAINT); - } - } - - protected String ellipse(String text, int width) { - if (PAINT.measureText(text) <= width) { - return text; - } - for (int i = text.length(); i >= 0; i--) { - if (PAINT.measureText(text.substring(0, i).concat("...")) <= width) { - return text.substring(0, text.charAt(i - 1) == ' ' ? i - 1 : i).concat("..."); - } - } - return ""; - } - - public void reset() { - mCover = null; - } - - public void setCover(Bitmap cover) { - mCover = cover; - invalidate(); - } - - public int getPosition() { - return position; - } - - public boolean hasBitmap() { - return mCover != null; - } - - public CoverResponse getResponse() { - return mResponse; - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.view.View; + +import org.xbmc.api.business.CoverResponse; +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.ThumbSize; + +public abstract class AbstractItemView extends View { + + public final static int MSG_UPDATE_COVER = 1; + private final Handler mHandler = new Handler() { + public void handleMessage(android.os.Message msg) { + switch (msg.what) { + case MSG_UPDATE_COVER: + setCover((Bitmap) msg.obj); + break; + } + } + + ; + }; + protected final static Paint PAINT = new Paint(); + protected static Bitmap sSelected; + protected final int padding; + protected final int size12, size18, size20, size25, size35, size42, size50, size55, size59, size65, size103; + protected final int mWidth; + protected final Drawable mSelection; + private final CoverResponse mResponse; + private final Bitmap mDefaultCover; + public int position; + public String title; + protected Bitmap mCover; + protected int mDefaultColor = Color.WHITE; + + public AbstractItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + int thumbSize, boolean fixedSize) { + super(context); + + if (manager != null) { + mResponse = new CoverResponse(context, manager, defaultCover, thumbSize, mHandler); + } else { + mResponse = null; + } + + mWidth = width; + mDefaultCover = defaultCover; + mSelection = selection; + + final float screenScale = fixedSize ? 1 : ThumbSize.SCREEN_SCALE; + padding = (int) (5 * ThumbSize.PIXEL_SCALE * screenScale); + size12 = (int) (12 * ThumbSize.PIXEL_SCALE * screenScale); + size18 = (int) (18 * ThumbSize.PIXEL_SCALE * screenScale); + size20 = (int) (20 * ThumbSize.PIXEL_SCALE * screenScale); + size25 = (int) (25 * ThumbSize.PIXEL_SCALE * screenScale); + size35 = (int) (35 * ThumbSize.PIXEL_SCALE * screenScale); + size42 = (int) (42 * ThumbSize.PIXEL_SCALE * screenScale); + size50 = (int) (50 * ThumbSize.PIXEL_SCALE * screenScale); + size55 = (int) (55 * ThumbSize.PIXEL_SCALE * screenScale); + size59 = (int) (59 * ThumbSize.PIXEL_SCALE * screenScale); + size65 = (int) (65 * ThumbSize.PIXEL_SCALE * screenScale); + size103 = (int) (103 * ThumbSize.PIXEL_SCALE * screenScale); + } + + public AbstractItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { + this(context, null, width, defaultCover, selection, 0, fixedSize); + } + + protected abstract Rect getPosterRect(); + + protected void drawPoster(Canvas canvas, int posterWidth, int posterHeight, int canvasWidth) { + // background + if ((isSelected() || isPressed()) && mSelection != null) { + mSelection.setBounds(posterWidth, 0, canvasWidth, posterHeight); + mSelection.draw(canvas); + } else { + PAINT.setColor(mDefaultColor); + canvas.drawRect(posterWidth, 0, canvasWidth, posterHeight, PAINT); + } + + // poster + Bitmap cover = mCover; + if (mCover == null || mCover.isRecycled()) { + cover = mDefaultCover; + } + + if (cover != null && !cover.isRecycled()) { + int dx = (cover.getWidth() - posterWidth) / 2; + int dy = (cover.getHeight() - posterHeight) / 2; + Rect src = null; + if (dx > 0 || dy > 0) { + src = new Rect(dx, dy, dx + posterWidth, dy + posterHeight); + } + Rect dst = getPosterRect(); + PAINT.setColor(mDefaultColor); + canvas.drawRect(0, 0, posterWidth, posterHeight, PAINT); + canvas.drawBitmap(cover, src, dst, PAINT); + } + } + + protected String ellipse(String text, int width) { + if (PAINT.measureText(text) <= width) { + return text; + } + for (int i = text.length(); i >= 0; i--) { + if (PAINT.measureText(text.substring(0, i).concat("...")) <= width) { + return text.substring(0, text.charAt(i - 1) == ' ' ? i - 1 : i).concat("..."); + } + } + return ""; + } + + public void reset() { + mCover = null; + } + + public void setCover(Bitmap cover) { + mCover = cover; + invalidate(); + } + + public int getPosition() { + return position; + } + + public boolean hasBitmap() { + return mCover != null; + } + + public CoverResponse getResponse() { + return mResponse; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java similarity index 86% rename from src/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java index e0ff6cab..6f9ab947 100644 --- a/src/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/FiveLabelsItemView.java @@ -1,121 +1,125 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; - -public class FiveLabelsItemView extends AbstractItemView { - - protected int posterWidth; - protected int posterHeight; - protected Rect posterRect; - - public Bitmap posterOverlay; - public String subtitle; - public String subtitleRight; - public String bottomtitle; - public String bottomright; - - public FiveLabelsItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); - - posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); - posterHeight = (int)(posterWidth * ThumbSize.POSTER_AR);; - posterRect = new Rect(0, 0, posterWidth, posterHeight); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(mWidth, posterHeight); - } - - protected void onDraw(Canvas canvas) { - drawPoster(canvas, posterWidth, posterHeight, mWidth); - drawPosterOverlay(canvas, posterWidth, posterHeight); - drawPortraitText(canvas); - } - - protected void drawPosterOverlay(Canvas canvas, int posterWidth, int posterHeight) { - if (posterOverlay != null) { - final int w = posterOverlay.getWidth(); - final int h = posterOverlay.getHeight(); - int dx = posterWidth - w; - int dy = posterHeight - h; - canvas.drawBitmap(posterOverlay, dx, dy, null); - } - } - - /** - * Draws text labels for portrait text view - *

-	 * ,-----. 
-	 * |     | title (big)
-	 * |     | subtitle           subtitleRight
-	 * |     | bottomtitle          bottomRight
-	 * `-----'
-	 * 
- * @param canvas Canvas to draw on - */ - protected void drawPortraitText(Canvas canvas) { - final int width = mWidth; - final boolean isSelected = isSelected() || isPressed(); - - // init paint - PAINT.setTextAlign(Align.LEFT); - PAINT.setColor(Color.WHITE); - PAINT.setFakeBoldText(false); - PAINT.setTextAlign(Align.LEFT); - PAINT.setAntiAlias(true); - - // title - if (title != null) { - PAINT.setColor(isSelected ? Color.WHITE : Color.BLACK); - PAINT.setTextSize(size18); - canvas.drawText(title, posterWidth + padding, size25, PAINT); - } - - // subtitle right - PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); - PAINT.setTextSize(size12); - PAINT.setTextAlign(Align.RIGHT); - int subtitleRightWidth = 0; - if (subtitleRight != null) { - subtitleRightWidth = (int)PAINT.measureText(subtitleRight); - canvas.drawText(subtitleRight, width - padding, size42, PAINT); - } - - // bottom right - int bottomrightWidth = 0; - if (bottomright != null) { - PAINT.setTextSize(size20); - PAINT.setFakeBoldText(true); - PAINT.setColor(isSelected ? Color.WHITE : Color.argb(68, 0, 0, 0)); - bottomrightWidth = (int)PAINT.measureText(subtitleRight); - canvas.drawText(bottomright, width - padding, size65, PAINT); - } - - // subtitle - PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); - PAINT.setTextSize(size12); - PAINT.setTextAlign(Align.LEFT); - PAINT.setFakeBoldText(false); - if (subtitle != null) { - canvas.drawText(ellipse(subtitle, width - subtitleRightWidth - size50 - (3 * padding)), size55, size42, PAINT); - } - if (bottomtitle != null) { - canvas.drawText(ellipse(bottomtitle, width - bottomrightWidth - size50 - (3 * padding)), size55, size59, PAINT); - } - } - - @Override - protected Rect getPosterRect() { - return posterRect; - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.ThumbSize; + +public class FiveLabelsItemView extends AbstractItemView { + + public Bitmap posterOverlay; + public String subtitle; + public String subtitleRight; + public String bottomtitle; + public String bottomright; + protected int posterWidth; + protected int posterHeight; + protected Rect posterRect; + + public FiveLabelsItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + boolean fixedSize) { + super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); + + posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); + posterHeight = (int) (posterWidth * ThumbSize.POSTER_AR); + ; + posterRect = new Rect(0, 0, posterWidth, posterHeight); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(mWidth, posterHeight); + } + + protected void onDraw(Canvas canvas) { + drawPoster(canvas, posterWidth, posterHeight, mWidth); + drawPosterOverlay(canvas, posterWidth, posterHeight); + drawPortraitText(canvas); + } + + protected void drawPosterOverlay(Canvas canvas, int posterWidth, int posterHeight) { + if (posterOverlay != null) { + final int w = posterOverlay.getWidth(); + final int h = posterOverlay.getHeight(); + int dx = posterWidth - w; + int dy = posterHeight - h; + canvas.drawBitmap(posterOverlay, dx, dy, null); + } + } + + /** + * Draws text labels for portrait text view + *
+	 * ,-----.
+	 * |     | title (big)
+	 * |     | subtitle           subtitleRight
+	 * |     | bottomtitle          bottomRight
+	 * `-----'
+	 * 
+ * + * @param canvas Canvas to draw on + */ + protected void drawPortraitText(Canvas canvas) { + final int width = mWidth; + final boolean isSelected = isSelected() || isPressed(); + + // init paint + PAINT.setTextAlign(Align.LEFT); + PAINT.setColor(Color.WHITE); + PAINT.setFakeBoldText(false); + PAINT.setTextAlign(Align.LEFT); + PAINT.setAntiAlias(true); + + // title + if (title != null) { + PAINT.setColor(isSelected ? Color.WHITE : Color.BLACK); + PAINT.setTextSize(size18); + canvas.drawText(title, posterWidth + padding, size25, PAINT); + } + + // subtitle right + PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); + PAINT.setTextSize(size12); + PAINT.setTextAlign(Align.RIGHT); + int subtitleRightWidth = 0; + if (subtitleRight != null) { + subtitleRightWidth = (int) PAINT.measureText(subtitleRight); + canvas.drawText(subtitleRight, width - padding, size42, PAINT); + } + + // bottom right + int bottomrightWidth = 0; + if (bottomright != null) { + PAINT.setTextSize(size20); + PAINT.setFakeBoldText(true); + PAINT.setColor(isSelected ? Color.WHITE : Color.argb(68, 0, 0, 0)); + bottomrightWidth = (int) PAINT.measureText(subtitleRight); + canvas.drawText(bottomright, width - padding, size65, PAINT); + } + + // subtitle + PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); + PAINT.setTextSize(size12); + PAINT.setTextAlign(Align.LEFT); + PAINT.setFakeBoldText(false); + if (subtitle != null) { + canvas.drawText(ellipse(subtitle, width - subtitleRightWidth - size50 - (3 * padding)), size55, size42, + PAINT); + } + if (bottomtitle != null) { + canvas.drawText(ellipse(bottomtitle, width - bottomrightWidth - size50 - (3 * padding)), size55, size59, + PAINT); + } + } + + @Override + protected Rect getPosterRect() { + return posterRect; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java similarity index 84% rename from src/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java index b183965f..126e1dc0 100644 --- a/src/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/FlexibleItemView.java @@ -1,123 +1,124 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.MediaType; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.api.type.ThumbSize.Dimension; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; - -public class FlexibleItemView extends FiveLabelsItemView { - private int POSTER_FORMAT = Dimension.PORTRAIT; - - public FlexibleItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, manager, width, defaultCover, selection, fixedSize); - } - - protected void onDraw(Canvas canvas) { - if (mCover != null && !mCover.isRecycled()) { - drawPoster(canvas, posterWidth, posterHeight, mWidth); - drawPosterOverlay(canvas, posterWidth, posterHeight); - switch (POSTER_FORMAT) { - case Dimension.SQUARE: - case Dimension.PORTRAIT: - drawPortrait(canvas); - break; - case Dimension.LANDSCAPE: - drawLandscape(canvas, posterWidth); - break; - case Dimension.BANNER: - drawBanner(canvas); - break; - default: - } - } else { - super.onDraw(canvas); - } - } - - private void drawPortrait(Canvas canvas) { - drawPortraitText(canvas); - } - - /** - * Draws text labels for landscape text view - *
-	 * ,----------. 
-	 * |          | title (big)
-	 * |          | subtitle           subtitleRight
-	 * `----------'
-	 * 
- * @param canvas Canvas to draw on - */ - private void drawLandscape(Canvas canvas, int drawWidth) { - final int width = mWidth; - final boolean isSelected = isSelected() || isPressed(); - - // init paint - PAINT.setTextAlign(Align.LEFT); - PAINT.setColor(Color.WHITE); - PAINT.setFakeBoldText(false); - PAINT.setTextAlign(Align.LEFT); - PAINT.setAntiAlias(true); - - // title - if (title != null) { - PAINT.setColor(isSelected ? Color.WHITE : Color.BLACK); - PAINT.setTextSize(size18); - canvas.drawText(ellipse(title, width - drawWidth + padding), drawWidth + padding, size25, PAINT); - } - - // subtitle right - PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); - PAINT.setTextSize(size12); - PAINT.setTextAlign(Align.RIGHT); - float subtitleRightWidth = 0; - if (subtitleRight != null) { - subtitleRightWidth = PAINT.measureText(subtitleRight); - canvas.drawText(subtitleRight, width - padding, size42, PAINT); - } - - // subtitle - PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); - PAINT.setTextSize(size12); - PAINT.setTextAlign(Align.LEFT); - PAINT.setFakeBoldText(false); - if (subtitle != null) { - canvas.drawText(ellipse(subtitle, width - (int)subtitleRightWidth - size50), drawWidth + padding, size42, PAINT); - } - - } - - private void drawBanner(Canvas canvas) { - - } - - - public void setCover(Bitmap cover) { - mCover = cover; - if(mCover != null) - { - Dimension renderDim = ThumbSize.getTargetDimension(ThumbSize.SMALL, MediaType.VIDEO, mCover.getWidth(), mCover.getHeight()); - posterWidth = renderDim.x; - posterHeight = renderDim.y; - posterRect = new Rect(0, 0, posterWidth, posterHeight); - POSTER_FORMAT = renderDim.format; - } - else - { - posterWidth = ThumbSize.getPixel(ThumbSize.SMALL); - posterHeight = (int)(posterWidth * ThumbSize.POSTER_AR); - posterRect = new Rect(0, 0, posterWidth, posterHeight); - POSTER_FORMAT = Dimension.PORTRAIT; - } - requestLayout(); - invalidate(); - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.MediaType; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.api.type.ThumbSize.Dimension; + +public class FlexibleItemView extends FiveLabelsItemView { + private int POSTER_FORMAT = Dimension.PORTRAIT; + + public FlexibleItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + boolean fixedSize) { + super(context, manager, width, defaultCover, selection, fixedSize); + } + + protected void onDraw(Canvas canvas) { + if (mCover != null && !mCover.isRecycled()) { + drawPoster(canvas, posterWidth, posterHeight, mWidth); + drawPosterOverlay(canvas, posterWidth, posterHeight); + switch (POSTER_FORMAT) { + case Dimension.SQUARE: + case Dimension.PORTRAIT: + drawPortrait(canvas); + break; + case Dimension.LANDSCAPE: + drawLandscape(canvas, posterWidth); + break; + case Dimension.BANNER: + drawBanner(canvas); + break; + default: + } + } else { + super.onDraw(canvas); + } + } + + private void drawPortrait(Canvas canvas) { + drawPortraitText(canvas); + } + + /** + * Draws text labels for landscape text view + *
+	 * ,----------.
+	 * |          | title (big)
+	 * |          | subtitle           subtitleRight
+	 * `----------'
+	 * 
+ * + * @param canvas Canvas to draw on + */ + private void drawLandscape(Canvas canvas, int drawWidth) { + final int width = mWidth; + final boolean isSelected = isSelected() || isPressed(); + + // init paint + PAINT.setTextAlign(Align.LEFT); + PAINT.setColor(Color.WHITE); + PAINT.setFakeBoldText(false); + PAINT.setTextAlign(Align.LEFT); + PAINT.setAntiAlias(true); + + // title + if (title != null) { + PAINT.setColor(isSelected ? Color.WHITE : Color.BLACK); + PAINT.setTextSize(size18); + canvas.drawText(ellipse(title, width - drawWidth + padding), drawWidth + padding, size25, PAINT); + } + + // subtitle right + PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); + PAINT.setTextSize(size12); + PAINT.setTextAlign(Align.RIGHT); + float subtitleRightWidth = 0; + if (subtitleRight != null) { + subtitleRightWidth = PAINT.measureText(subtitleRight); + canvas.drawText(subtitleRight, width - padding, size42, PAINT); + } + + // subtitle + PAINT.setColor(isSelected ? Color.WHITE : Color.rgb(80, 80, 80)); + PAINT.setTextSize(size12); + PAINT.setTextAlign(Align.LEFT); + PAINT.setFakeBoldText(false); + if (subtitle != null) { + canvas.drawText(ellipse(subtitle, width - (int) subtitleRightWidth - size50), drawWidth + padding, size42, + PAINT); + } + + } + + private void drawBanner(Canvas canvas) { + + } + + + public void setCover(Bitmap cover) { + mCover = cover; + if (mCover != null) { + Dimension renderDim = ThumbSize.getTargetDimension(ThumbSize.SMALL, MediaType.VIDEO, mCover.getWidth(), + mCover.getHeight()); + posterWidth = renderDim.x; + posterHeight = renderDim.y; + posterRect = new Rect(0, 0, posterWidth, posterHeight); + POSTER_FORMAT = renderDim.format; + } else { + posterWidth = ThumbSize.getPixel(ThumbSize.SMALL); + posterHeight = (int) (posterWidth * ThumbSize.POSTER_AR); + posterRect = new Rect(0, 0, posterWidth, posterHeight); + POSTER_FORMAT = Dimension.PORTRAIT; + } + requestLayout(); + invalidate(); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java similarity index 88% rename from src/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java index 96c671ca..73e721f9 100644 --- a/src/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/GridPosterItemView.java @@ -1,57 +1,58 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; - -public class GridPosterItemView extends AbstractItemView { - - private final static int POSTER_WIDTH = ThumbSize.getPixel(ThumbSize.MEDIUM); - private final static int POSTER_HEIGHT = (int)((float)POSTER_WIDTH * ThumbSize.POSTER_AR); - private final static Rect POSTER_RECT = new Rect(0, 0, POSTER_WIDTH, POSTER_HEIGHT); - - public GridPosterItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, width, defaultCover, selection, fixedSize); - } - - public GridPosterItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, manager, width, defaultCover, selection, ThumbSize.MEDIUM, fixedSize); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(POSTER_WIDTH, POSTER_HEIGHT + size25); - } - - protected void onDraw(Canvas canvas) { - final int width = mWidth; - PAINT.setTextAlign(Align.LEFT); - drawPoster(canvas, POSTER_WIDTH, POSTER_HEIGHT, width); - - // background - PAINT.setColor(Color.BLACK); - canvas.drawRect(0, POSTER_HEIGHT, POSTER_WIDTH, POSTER_HEIGHT + size25, PAINT); - - // label - PAINT.setColor(Color.WHITE); - PAINT.setAntiAlias(true); - if (title != null) { - PAINT.setTextAlign(Align.CENTER); -// PAINT.setColor(isSelected() || isPressed() ? Color.BLACK : Color.WHITE); - PAINT.setTextSize(size18); - canvas.drawText(title, POSTER_WIDTH / 2, POSTER_HEIGHT + size18, PAINT); - } - } - - @Override - protected Rect getPosterRect() { - return POSTER_RECT; - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.ThumbSize; + +public class GridPosterItemView extends AbstractItemView { + + private final static int POSTER_WIDTH = ThumbSize.getPixel(ThumbSize.MEDIUM); + private final static int POSTER_HEIGHT = (int) ((float) POSTER_WIDTH * ThumbSize.POSTER_AR); + private final static Rect POSTER_RECT = new Rect(0, 0, POSTER_WIDTH, POSTER_HEIGHT); + + public GridPosterItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { + super(context, width, defaultCover, selection, fixedSize); + } + + public GridPosterItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + boolean fixedSize) { + super(context, manager, width, defaultCover, selection, ThumbSize.MEDIUM, fixedSize); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(POSTER_WIDTH, POSTER_HEIGHT + size25); + } + + protected void onDraw(Canvas canvas) { + final int width = mWidth; + PAINT.setTextAlign(Align.LEFT); + drawPoster(canvas, POSTER_WIDTH, POSTER_HEIGHT, width); + + // background + PAINT.setColor(Color.BLACK); + canvas.drawRect(0, POSTER_HEIGHT, POSTER_WIDTH, POSTER_HEIGHT + size25, PAINT); + + // label + PAINT.setColor(Color.WHITE); + PAINT.setAntiAlias(true); + if (title != null) { + PAINT.setTextAlign(Align.CENTER); +// PAINT.setColor(isSelected() || isPressed() ? Color.BLACK : Color.WHITE); + PAINT.setTextSize(size18); + canvas.drawText(title, POSTER_WIDTH / 2, POSTER_HEIGHT + size18, PAINT); + } + } + + @Override + protected Rect getPosterRect() { + return POSTER_RECT; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/JewelView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/JewelView.java similarity index 81% rename from src/org/xbmc/android/remote/presentation/widget/JewelView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/JewelView.java index 6f4ab983..9e91c93d 100644 --- a/src/org/xbmc/android/remote/presentation/widget/JewelView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/JewelView.java @@ -1,244 +1,254 @@ -package org.xbmc.android.remote.presentation.widget; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.xbmc.android.remote.R; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; - -public class JewelView extends View { - - private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; - - private Bitmap mPosterOverlay; - private Bitmap mPoster; - private Paint mPaint; - private float mPosterAR; - - private int coverWidth, coverHeight; - private int originalWidth, originalHeight; - private int totalWidth, totalHeight; - private int specifiedWidth = 0; - private int specifiedHeight = 0; - private float scaled; - private int originalCoverHeight, originalCoverWidth; - private JewelType mType; - - public final static float AR_LANDSCAPE_SQUARE = 0.8f; - public final static float AR_SQUARE_POSTER = 1.25f; - public final static float AR_OVERLAY = 1.25f; - - private final static String TAG = "JewelView"; - - public JewelView(Context context) { - super(context); - init(context); - } - - public JewelView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context); - - // read layout width and height from xml element - final Pattern p = Pattern.compile("([\\-\\d]+)"); - final String h = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_height"); - final String w = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_width"); - if (w != null) { - try { - Matcher matcher = p.matcher(w); - if (matcher.find()) { - specifiedWidth = Integer.parseInt(matcher.group(1)); - } - } catch (Exception e) { } - - } - if (h != null) { - try { - Matcher matcher = p.matcher(h); - if (matcher.find()) { - specifiedHeight = Integer.parseInt(matcher.group(1)); - } - } catch (Exception e) { } - } - } - - public void setCover(int coverResource) { -// Log.d(TAG, "setCover(" + coverResource + ")"); - setCover(BitmapFactory.decodeResource(getContext().getResources(), coverResource)); - } - - public void setCover(Bitmap cover) { - mPoster = cover; - mPosterAR = (float) cover.getHeight() / (float) cover.getWidth(); -// Log.d(TAG, "setCover(), AR = " + mPosterAR); - mType = JewelType.get(mPosterAR); - if (mType != null) { - Log.i(TAG, "Set aspect ratio type for " + mPosterAR + " to " + mType); - mPosterOverlay = BitmapFactory.decodeResource(getContext().getResources(), mType.overlayResource); - } else { - Log.w(TAG, "Unable to get aspect ratio type for " + mPosterAR); - } - requestLayout(); - invalidate(); - } - - private final void init(Context context) { - mPaint = new Paint(); -// final int padding = ThumbSize.scale(3); -// setPadding(padding, padding, padding, padding); - setCover(R.drawable.default_jewel); - } - - /** - * @see android.view.View#measure(int, int) - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { -// Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", " + MeasureSpec.toString(heightMeasureSpec)); - - if (mType == null) { - setMeasuredDimension(0, 0); - return; - } - - final int modeWidth = specifiedWidth > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(widthMeasureSpec); - final int modeHeight = specifiedHeight > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(heightMeasureSpec); - originalWidth = mPosterOverlay.getWidth(); - originalHeight = mPosterOverlay.getHeight(); - - if (modeHeight == modeWidth) { - final float canvasAR = (float)MeasureSpec.getSize(heightMeasureSpec) / (float)MeasureSpec.getSize(widthMeasureSpec); -// Log.d(TAG, "Patt, calculating from canvas AR (" + canvasAR + ")"); - if (mPosterAR > canvasAR * mType.overlayAR) { - setMeasuredDimensionByHeight(MeasureSpec.getSize(heightMeasureSpec)); - } else { - setMeasuredDimensionByWidth(MeasureSpec.getSize(widthMeasureSpec)); - } - } else if (modeHeight == MeasureSpec.EXACTLY && modeWidth != MeasureSpec.EXACTLY && mPosterAR > AR_LANDSCAPE_SQUARE) { - // reference is height, make width dependent on height. - setMeasuredDimensionByHeight(specifiedHeight > 0 ? ThumbSize.scale(specifiedHeight) : MeasureSpec.getSize(heightMeasureSpec)); - } else { - // reference is width, make height dependent on width. - setMeasuredDimensionByWidth(specifiedWidth > 0 ? ThumbSize.scale(specifiedWidth) : MeasureSpec.getSize(widthMeasureSpec)); - } - - // fill_parent -> MeasureSpec.EXACTLY - // wrap_content -> MeasureSpec.AT_MOST - } - - private void setMeasuredDimensionByHeight(int height) { - - final Rect posterPosition = mType.posterPosition; - - totalHeight = height; - originalCoverHeight = originalHeight - ThumbSize.scale(posterPosition.top + posterPosition.bottom); - originalCoverWidth = Math.round((float) originalCoverHeight / mPosterAR); - scaled = (float) totalHeight / (float) originalHeight; - coverHeight = Math.round((float) originalCoverHeight * scaled); - coverWidth = Math.round((float) originalCoverWidth * scaled); - totalWidth = coverWidth + Math.round((float) ThumbSize.scale(posterPosition.left + posterPosition.right) * scaled); - -// Log.d(TAG, "Measuring by height (" + height + ") -> " + totalWidth + "x" + totalHeight); - setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding); - } - - private void setMeasuredDimensionByWidth(int width) { - - final Rect posterPosition = mType.posterPosition; - - totalWidth = width; - originalCoverWidth = originalWidth - ThumbSize.scale(posterPosition.left + posterPosition.right); - originalCoverHeight = Math.round((float) originalCoverWidth * mPosterAR); - scaled = (float) totalWidth / (float) originalWidth; - coverHeight = Math.round((float) originalCoverHeight * scaled); - coverWidth = Math.round((float) originalCoverWidth * scaled); - totalHeight = coverHeight + Math.round((float) ThumbSize.scale(posterPosition.top + posterPosition.bottom) * scaled); - -// Log.d(TAG, "Measuring by width (" + width + ") -> " + totalWidth + "x" + totalHeight); - setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding); - } - - /** - * Render the text - * - * @see android.view.View#onDraw(android.graphics.Canvas) - */ - @Override - protected void onDraw(Canvas canvas) { - - synchronized (this) { - - if (mType != null) { - -// Log.i(TAG, "Drawing " + mType); - - // Rect(left: 48, top: 11, right: 17, bottom: 19) - final Rect posterPosition = mType.posterPosition; - final int pdnLeft = Math.round((float) ThumbSize.scale(posterPosition.left) * scaled); - final int pdnTop = Math.round((float) ThumbSize.scale(posterPosition.top) * scaled); - - mPaint.setDither(true); - mPaint.setFilterBitmap(true); - - // draw actual poster - canvas.drawBitmap(mPoster, new Rect(0, 0, mPoster.getWidth(), mPoster.getHeight()), - new Rect(pdnLeft, pdnTop, pdnLeft + coverWidth, pdnTop + coverHeight), mPaint); - // draw case overlay - canvas.drawBitmap(mPosterOverlay, new Rect(0, 0, originalWidth, originalHeight), - new Rect(0, 0, totalWidth, totalHeight), mPaint); - } - } - } - - private static class JewelType { - - private final static JewelType[] TYPES = { - // l t r b - new JewelType(new Rect(48, 11, 17, 19), AR_SQUARE_POSTER, 2000f, R.drawable.jewel_dvd, "Portrait (1:1.48)", 0, 1), - new JewelType(new Rect(41, 12, 17, 18), AR_LANDSCAPE_SQUARE, AR_SQUARE_POSTER, R.drawable.jewel_cd, "Cover (square)", 0, 1.105263157894737f), - new JewelType(new Rect(16, 11, 10, 34), 0.35f, AR_LANDSCAPE_SQUARE, R.drawable.jewel_tv, "Landscape (16:9)", ThumbSize.scale(30), 1) - }; - - public static final JewelType get(float ar) { - for (JewelType jewelType : TYPES) { - if (ar >= jewelType.minAR && ar < jewelType.maxAR) { - return jewelType; - } - } - return null; - } - - public final Rect posterPosition; - public final float minAR, maxAR; - public final int overlayResource; - public final String name; - public final int bottomPadding; - public final float overlayAR; - - public JewelType(Rect posterPosition, float minAR, float maxAR, int overlayResource, String name, int bottomPadding, float overlayAR) { - this.posterPosition = posterPosition; - this.minAR = minAR; - this.maxAR = maxAR; - this.overlayResource = overlayResource; - this.name = name; - this.bottomPadding = bottomPadding; - this.overlayAR = overlayAR; - } - - @Override - public String toString() { - return name; - } - } - +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +import org.xbmc.android.remote.R; +import org.xbmc.api.type.ThumbSize; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class JewelView extends View { + + public final static float AR_LANDSCAPE_SQUARE = 0.8f; + public final static float AR_SQUARE_POSTER = 1.25f; + public final static float AR_OVERLAY = 1.25f; + private static final String ANDROID_NAMESPACE = "http://schemas.android.com/apk/res/android"; + private final static String TAG = "JewelView"; + private Bitmap mPosterOverlay; + private Bitmap mPoster; + private Paint mPaint; + private float mPosterAR; + private int coverWidth, coverHeight; + private int originalWidth, originalHeight; + private int totalWidth, totalHeight; + private int specifiedWidth = 0; + private int specifiedHeight = 0; + private float scaled; + private int originalCoverHeight, originalCoverWidth; + private JewelType mType; + + public JewelView(Context context) { + super(context); + init(context); + } + + public JewelView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context); + + // read layout width and height from xml element + final Pattern p = Pattern.compile("([\\-\\d]+)"); + final String h = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_height"); + final String w = attrs.getAttributeValue(ANDROID_NAMESPACE, "layout_width"); + if (w != null) { + try { + Matcher matcher = p.matcher(w); + if (matcher.find()) { + specifiedWidth = Integer.parseInt(matcher.group(1)); + } + } catch (Exception e) { + } + + } + if (h != null) { + try { + Matcher matcher = p.matcher(h); + if (matcher.find()) { + specifiedHeight = Integer.parseInt(matcher.group(1)); + } + } catch (Exception e) { + } + } + } + + public void setCover(int coverResource) { +// Log.d(TAG, "setCover(" + coverResource + ")"); + setCover(BitmapFactory.decodeResource(getContext().getResources(), coverResource)); + } + + public void setCover(Bitmap cover) { + mPoster = cover; + mPosterAR = (float) cover.getHeight() / (float) cover.getWidth(); +// Log.d(TAG, "setCover(), AR = " + mPosterAR); + mType = JewelType.get(mPosterAR); + if (mType != null) { + Log.i(TAG, "Set aspect ratio type for " + mPosterAR + " to " + mType); + mPosterOverlay = BitmapFactory.decodeResource(getContext().getResources(), mType.overlayResource); + } else { + Log.w(TAG, "Unable to get aspect ratio type for " + mPosterAR); + } + requestLayout(); + invalidate(); + } + + private final void init(Context context) { + mPaint = new Paint(); +// final int padding = ThumbSize.scale(3); +// setPadding(padding, padding, padding, padding); + setCover(R.drawable.default_jewel); + } + + /** + * @see android.view.View#measure(int, int) + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { +// Log.d(TAG, "onMeasure(" + MeasureSpec.toString(widthMeasureSpec) + ", +// " + MeasureSpec.toString(heightMeasureSpec)); + + if (mType == null) { + setMeasuredDimension(0, 0); + return; + } + + final int modeWidth = specifiedWidth > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(widthMeasureSpec); + final int modeHeight = specifiedHeight > 0 ? MeasureSpec.EXACTLY : MeasureSpec.getMode(heightMeasureSpec); + originalWidth = mPosterOverlay.getWidth(); + originalHeight = mPosterOverlay.getHeight(); + + if (modeHeight == modeWidth) { + final float canvasAR = (float) MeasureSpec.getSize(heightMeasureSpec) / (float) MeasureSpec.getSize + (widthMeasureSpec); +// Log.d(TAG, "Patt, calculating from canvas AR (" + canvasAR + ")"); + if (mPosterAR > canvasAR * mType.overlayAR) { + setMeasuredDimensionByHeight(MeasureSpec.getSize(heightMeasureSpec)); + } else { + setMeasuredDimensionByWidth(MeasureSpec.getSize(widthMeasureSpec)); + } + } else if (modeHeight == MeasureSpec.EXACTLY && modeWidth != MeasureSpec.EXACTLY && mPosterAR > + AR_LANDSCAPE_SQUARE) { + // reference is height, make width dependent on height. + setMeasuredDimensionByHeight(specifiedHeight > 0 ? ThumbSize.scale(specifiedHeight) : MeasureSpec.getSize + (heightMeasureSpec)); + } else { + // reference is width, make height dependent on width. + setMeasuredDimensionByWidth(specifiedWidth > 0 ? ThumbSize.scale(specifiedWidth) : MeasureSpec.getSize + (widthMeasureSpec)); + } + + // fill_parent -> MeasureSpec.EXACTLY + // wrap_content -> MeasureSpec.AT_MOST + } + + private void setMeasuredDimensionByHeight(int height) { + + final Rect posterPosition = mType.posterPosition; + + totalHeight = height; + originalCoverHeight = originalHeight - ThumbSize.scale(posterPosition.top + posterPosition.bottom); + originalCoverWidth = Math.round((float) originalCoverHeight / mPosterAR); + scaled = (float) totalHeight / (float) originalHeight; + coverHeight = Math.round((float) originalCoverHeight * scaled); + coverWidth = Math.round((float) originalCoverWidth * scaled); + totalWidth = coverWidth + Math.round((float) ThumbSize.scale(posterPosition.left + posterPosition.right) * + scaled); + +// Log.d(TAG, "Measuring by height (" + height + ") -> " + totalWidth + "x" + totalHeight); + setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding); + } + + private void setMeasuredDimensionByWidth(int width) { + + final Rect posterPosition = mType.posterPosition; + + totalWidth = width; + originalCoverWidth = originalWidth - ThumbSize.scale(posterPosition.left + posterPosition.right); + originalCoverHeight = Math.round((float) originalCoverWidth * mPosterAR); + scaled = (float) totalWidth / (float) originalWidth; + coverHeight = Math.round((float) originalCoverHeight * scaled); + coverWidth = Math.round((float) originalCoverWidth * scaled); + totalHeight = coverHeight + Math.round((float) ThumbSize.scale(posterPosition.top + posterPosition.bottom) * + scaled); + +// Log.d(TAG, "Measuring by width (" + width + ") -> " + totalWidth + "x" + totalHeight); + setMeasuredDimension(totalWidth, totalHeight + mType.bottomPadding); + } + + /** + * Render the text + * + * @see android.view.View#onDraw(android.graphics.Canvas) + */ + @Override + protected void onDraw(Canvas canvas) { + + synchronized (this) { + + if (mType != null) { + +// Log.i(TAG, "Drawing " + mType); + + // Rect(left: 48, top: 11, right: 17, bottom: 19) + final Rect posterPosition = mType.posterPosition; + final int pdnLeft = Math.round((float) ThumbSize.scale(posterPosition.left) * scaled); + final int pdnTop = Math.round((float) ThumbSize.scale(posterPosition.top) * scaled); + + mPaint.setDither(true); + mPaint.setFilterBitmap(true); + + // draw actual poster + canvas.drawBitmap(mPoster, new Rect(0, 0, mPoster.getWidth(), mPoster.getHeight()), + new Rect(pdnLeft, pdnTop, pdnLeft + coverWidth, pdnTop + coverHeight), mPaint); + // draw case overlay + canvas.drawBitmap(mPosterOverlay, new Rect(0, 0, originalWidth, originalHeight), + new Rect(0, 0, totalWidth, totalHeight), mPaint); + } + } + } + + private static class JewelType { + + public final Rect posterPosition; + public final float minAR, maxAR; + public final int overlayResource; + private final static JewelType[] TYPES = { + // l t r b + new JewelType(new Rect(48, 11, 17, 19), AR_SQUARE_POSTER, 2000f, R.drawable.jewel_dvd, + "Portrait (1:1.48)", 0, 1), + new JewelType(new Rect(41, 12, 17, 18), AR_LANDSCAPE_SQUARE, AR_SQUARE_POSTER, R.drawable.jewel_cd, + "Cover (square)", 0, 1.105263157894737f), + new JewelType(new Rect(16, 11, 10, 34), 0.35f, AR_LANDSCAPE_SQUARE, R.drawable.jewel_tv, + "Landscape (16:9)", ThumbSize.scale(30), 1) + }; + public final String name; + public final int bottomPadding; + public final float overlayAR; + + public JewelType(Rect posterPosition, float minAR, float maxAR, int overlayResource, String name, + int bottomPadding, float overlayAR) { + this.posterPosition = posterPosition; + this.minAR = minAR; + this.maxAR = maxAR; + this.overlayResource = overlayResource; + this.name = name; + this.bottomPadding = bottomPadding; + this.overlayAR = overlayAR; + } + + public static final JewelType get(float ar) { + for (JewelType jewelType : TYPES) { + if (ar >= jewelType.minAR && ar < jewelType.maxAR) { + return jewelType; + } + } + return null; + } + + @Override + public String toString() { + return name; + } + + + } + } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java similarity index 92% rename from src/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java index dd486450..0d6f4bb2 100644 --- a/src/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/OneLabelItemView.java @@ -1,54 +1,55 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; - -public class OneLabelItemView extends AbstractItemView { - - private final int posterWidth, posterHeight; - private final Rect posterRect; - - public OneLabelItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); - posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); - posterHeight = posterWidth; - posterRect = new Rect(0, 0, posterWidth, posterHeight); - } - - public OneLabelItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - this(context, null, width, defaultCover, selection, fixedSize); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(mWidth, posterHeight); - } - - protected void onDraw(Canvas canvas) { - final int width = mWidth; - PAINT.setTextAlign(Align.LEFT); - - drawPoster(canvas, posterWidth, posterHeight, width); - - // label - PAINT.setAntiAlias(true); - if (title != null) { - PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.BLACK); - PAINT.setTextSize(size18); - canvas.drawText(title, posterWidth + padding, size35, PAINT); - } - } - - @Override - protected Rect getPosterRect() { - return posterRect; - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.ThumbSize; + +public class OneLabelItemView extends AbstractItemView { + + private final int posterWidth, posterHeight; + private final Rect posterRect; + + public OneLabelItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + boolean fixedSize) { + super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); + posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); + posterHeight = posterWidth; + posterRect = new Rect(0, 0, posterWidth, posterHeight); + } + + public OneLabelItemView(Context context, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { + this(context, null, width, defaultCover, selection, fixedSize); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(mWidth, posterHeight); + } + + protected void onDraw(Canvas canvas) { + final int width = mWidth; + PAINT.setTextAlign(Align.LEFT); + + drawPoster(canvas, posterWidth, posterHeight, width); + + // label + PAINT.setAntiAlias(true); + if (title != null) { + PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.BLACK); + PAINT.setTextSize(size18); + canvas.drawText(title, posterWidth + padding, size35, PAINT); + } + } + + @Override + protected Rect getPosterRect() { + return posterRect; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java b/app/src/main/java/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java similarity index 92% rename from src/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java rename to app/src/main/java/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java index 3c37678c..c642537a 100644 --- a/src/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/widget/ThreeLabelsItemView.java @@ -1,64 +1,64 @@ -package org.xbmc.android.remote.presentation.widget; - -import org.xbmc.api.business.IManager; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.Paint.Align; -import android.graphics.drawable.Drawable; - -public class ThreeLabelsItemView extends AbstractItemView { - - public String subtitle; - public String subsubtitle; - - private final int posterWidth, posterHeight; - private final Rect posterRect; - - public ThreeLabelsItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, boolean fixedSize) { - super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); - - posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); - posterHeight = posterWidth; - posterRect = new Rect(0, 0, posterWidth, posterHeight); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(mWidth, posterHeight); - } - - @Override - protected void onDraw(Canvas canvas) { - final int width = mWidth; - PAINT.setTextAlign(Align.LEFT); - - drawPoster(canvas, posterWidth, posterHeight, width); - - // text - PAINT.setAntiAlias(true); - if (title != null) { - PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.BLACK); - PAINT.setTextSize(size18); - canvas.drawText(ellipse(title, width - size50 - padding), posterWidth + padding, size25, PAINT); - } - PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.rgb(80, 80, 80)); - PAINT.setTextSize(size12); - if (subtitle != null) { - canvas.drawText(subtitle, posterWidth + padding, size42, PAINT); - } - if (subsubtitle != null) { - PAINT.setTextAlign(Align.RIGHT); - canvas.drawText(subsubtitle, width - padding, size42, PAINT); - } - } - - @Override - protected Rect getPosterRect() { - return posterRect; - } +package org.xbmc.android.remote.presentation.widget; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; + +import org.xbmc.api.business.IManager; +import org.xbmc.api.type.ThumbSize; + +public class ThreeLabelsItemView extends AbstractItemView { + + private final int posterWidth, posterHeight; + private final Rect posterRect; + public String subtitle; + public String subsubtitle; + + public ThreeLabelsItemView(Context context, IManager manager, int width, Bitmap defaultCover, Drawable selection, + boolean fixedSize) { + super(context, manager, width, defaultCover, selection, ThumbSize.SMALL, fixedSize); + + posterWidth = ThumbSize.getPixel(ThumbSize.SMALL, fixedSize); + posterHeight = posterWidth; + posterRect = new Rect(0, 0, posterWidth, posterHeight); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(mWidth, posterHeight); + } + + @Override + protected void onDraw(Canvas canvas) { + final int width = mWidth; + PAINT.setTextAlign(Align.LEFT); + + drawPoster(canvas, posterWidth, posterHeight, width); + + // text + PAINT.setAntiAlias(true); + if (title != null) { + PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.BLACK); + PAINT.setTextSize(size18); + canvas.drawText(ellipse(title, width - size50 - padding), posterWidth + padding, size25, PAINT); + } + PAINT.setColor(isSelected() || isPressed() ? Color.WHITE : Color.rgb(80, 80, 80)); + PAINT.setTextSize(size12); + if (subtitle != null) { + canvas.drawText(subtitle, posterWidth + padding, size42, PAINT); + } + if (subsubtitle != null) { + PAINT.setTextAlign(Align.RIGHT); + canvas.drawText(subsubtitle, width - padding, size42, PAINT); + } + } + + @Override + protected Rect getPosterRect() { + return posterRect; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/remote/presentation/wizard/Wizard.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/Wizard.java similarity index 82% rename from src/org/xbmc/android/remote/presentation/wizard/Wizard.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/Wizard.java index 7bc6c7bf..511f5986 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/Wizard.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/Wizard.java @@ -1,130 +1,130 @@ -package org.xbmc.android.remote.presentation.wizard; - -import java.util.ArrayList; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.wizard.listener.PageCanFinishListener; - -import android.app.Activity; -import android.os.Bundle; -import android.view.View; -import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.LinearLayout; -import android.widget.TextView; - - -public abstract class Wizard extends Activity { - - private ArrayList> pages = new ArrayList>(); - private ArrayList> shownPagesStack = new ArrayList>(); - private WizardPage currentPage = null; - private int currentPos = -1; - - private Button next; - private Button prev; - private FrameLayout main; - private LinearLayout overlay; - private TextView msg; - - public Wizard() { - super(); - } - - @Override - protected final void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - this.setContentView(R.layout.setup_wizard); - main = (FrameLayout) findViewById(R.id.setup_wizard_root); - next = (Button) findViewById(R.id.setup_button_next); - prev = (Button) findViewById(R.id.setup_button_prev); - - next.setEnabled(false); - prev.setEnabled(false); - - overlay = (LinearLayout) findViewById(R.id.setup_wizard_msg_overlay); - msg = (TextView) findViewById(R.id.setup_wizard_msg); - overlay.setVisibility(View.GONE); - - doSetupPages(); - checkButtons(); - for(WizardPage page : pages) { - page.init(); - main.addView(page, 0); - page.setVisibility(View.GONE); - } - currentPage.setVisibility(View.VISIBLE); - shownPagesStack.add(currentPage); - next.setOnClickListener(currentPage.getNextClickListener()); - } - - public abstract void doSetupPages(); - - void showNextPage() { - - if(currentPage != null && currentPage.getNextPage() != null) { - currentPage.hide(); - currentPage = currentPage.getNextPage(); - currentPage.show(); - shownPagesStack.add(currentPage); - next.setOnClickListener(currentPage.getNextClickListener()); - }else{ - if(currentPos < pages.size() - 1) { - WizardPage page = pages.get(++currentPos); - page.setInput(currentPage.getInput()); - checkButtons(); - currentPage.hide(); - currentPage = page; - currentPage.show(); - shownPagesStack.add(currentPage); - next.setOnClickListener(currentPage.getNextClickListener()); - }else{ - //finish wizard - doFinish(); - finish(); - } - } - } - - protected abstract void doFinish(); - - void showPrevPage() { - - } - - void showBusyMessage(String msg) { - this.msg.setText(msg); - overlay.setVisibility(View.VISIBLE); - } - - void removeBusyMessage() { - overlay.setVisibility(View.GONE); - } - - protected void addPage(final WizardPage page) { - if(currentPage == null) { - currentPage = page; - currentPos = 0; - } - pages.add(page); - page.addCanFinishListener(new PageCanFinishListener() { - public void canFinish(boolean b) { - next.setEnabled(b); - } - }); - checkButtons(); - } - - private void checkButtons() { - if(currentPos == pages.size() -1 ) { - next.setText("Finish"); - } else { - next.setText("Next"); - } - /*if(currentPos == 0) { - prev.setEnabled(false); - }else { - prev.setEnabled(true); - }*/ - } -} +package org.xbmc.android.remote.presentation.wizard; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.wizard.listener.PageCanFinishListener; + +import java.util.ArrayList; + + +public abstract class Wizard extends Activity { + + private ArrayList> pages = new ArrayList>(); + private ArrayList> shownPagesStack = new ArrayList>(); + private WizardPage currentPage = null; + private int currentPos = -1; + + private Button next; + private Button prev; + private FrameLayout main; + private LinearLayout overlay; + private TextView msg; + + public Wizard() { + super(); + } + + @Override + protected final void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + this.setContentView(R.layout.setup_wizard); + main = (FrameLayout) findViewById(R.id.setup_wizard_root); + next = (Button) findViewById(R.id.setup_button_next); + prev = (Button) findViewById(R.id.setup_button_prev); + + next.setEnabled(false); + prev.setEnabled(false); + + overlay = (LinearLayout) findViewById(R.id.setup_wizard_msg_overlay); + msg = (TextView) findViewById(R.id.setup_wizard_msg); + overlay.setVisibility(View.GONE); + + doSetupPages(); + checkButtons(); + for (WizardPage page : pages) { + page.init(); + main.addView(page, 0); + page.setVisibility(View.GONE); + } + currentPage.setVisibility(View.VISIBLE); + shownPagesStack.add(currentPage); + next.setOnClickListener(currentPage.getNextClickListener()); + } + + public abstract void doSetupPages(); + + void showNextPage() { + + if (currentPage != null && currentPage.getNextPage() != null) { + currentPage.hide(); + currentPage = currentPage.getNextPage(); + currentPage.show(); + shownPagesStack.add(currentPage); + next.setOnClickListener(currentPage.getNextClickListener()); + } else { + if (currentPos < pages.size() - 1) { + WizardPage page = pages.get(++currentPos); + page.setInput(currentPage.getInput()); + checkButtons(); + currentPage.hide(); + currentPage = page; + currentPage.show(); + shownPagesStack.add(currentPage); + next.setOnClickListener(currentPage.getNextClickListener()); + } else { + //finish wizard + doFinish(); + finish(); + } + } + } + + protected abstract void doFinish(); + + void showPrevPage() { + + } + + void showBusyMessage(String msg) { + this.msg.setText(msg); + overlay.setVisibility(View.VISIBLE); + } + + void removeBusyMessage() { + overlay.setVisibility(View.GONE); + } + + protected void addPage(final WizardPage page) { + if (currentPage == null) { + currentPage = page; + currentPos = 0; + } + pages.add(page); + page.addCanFinishListener(new PageCanFinishListener() { + public void canFinish(boolean b) { + next.setEnabled(b); + } + }); + checkButtons(); + } + + private void checkButtons() { + if (currentPos == pages.size() - 1) { + next.setText("Finish"); + } else { + next.setText("Next"); + } + /*if(currentPos == 0) { + prev.setEnabled(false); + }else { + prev.setEnabled(true); + }*/ + } +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/WizardPage.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/WizardPage.java similarity index 90% rename from src/org/xbmc/android/remote/presentation/wizard/WizardPage.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/WizardPage.java index 0c99bcc3..bd5cfdba 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/WizardPage.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/WizardPage.java @@ -1,110 +1,110 @@ -package org.xbmc.android.remote.presentation.wizard; - -import java.util.ArrayList; - -import org.xbmc.android.remote.presentation.wizard.listener.PageCanFinishListener; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.ScrollView; - -public abstract class WizardPage extends ScrollView { - - private ArrayList listeners = new ArrayList(); - private boolean canFinish = false; - protected T input = null; - protected Wizard wizard; - - public WizardPage(Context context, AttributeSet attrs, int defStyle, Wizard wizard) { - super(context, attrs, defStyle); - this.wizard = wizard; - } - - public WizardPage(Context context, AttributeSet attrs, Wizard wizard) { - super(context, attrs); - this.wizard = wizard; - } - - public WizardPage(Context context, Wizard wizard) { - super(context); - this.wizard = wizard; - } - - public void init() { - inflate(getContext(), getLayoutId(), this); - onInit(); - } - - public OnClickListener getNextClickListener() { - return new OnClickListener() { - public void onClick(View v) { - showNextPage(); - } - }; - } - - protected void showNextPage() { - wizard.showNextPage(); - } - - public abstract WizardPage getNextPage() ; - - public abstract int getLayoutId(); - - protected abstract void onInit(); - - protected void showBusyMessage(String msg) { - wizard.showBusyMessage(msg); - } - - protected void removeBusyMessage() { - wizard.removeBusyMessage(); - } - - public void setInput(T input) { - this.input = input; - } - - public T getInput() { - return input; - } - - public boolean canFinish() { - return canFinish; - } - - protected void setCanFinish(boolean canFinish) { - this.canFinish = canFinish; - notifyCanFinishListeners(); - } - - private void notifyCanFinishListeners() { - for(PageCanFinishListener listener : listeners) { - listener.canFinish(canFinish); - } - } - - public void addCanFinishListener(PageCanFinishListener listener) { - listeners.add(listener); - } - - public void removeCanFinishListener(PageCanFinishListener listener) { - listeners.remove(listener); - } - - public void show() { - Animation animation = AnimationUtils.makeInAnimation(getContext(), false); - this.setAnimation(animation); - setVisibility(View.VISIBLE); - } - - public void hide() { - Animation animation = AnimationUtils.makeOutAnimation(getContext(), false); - this.setAnimation(animation); - this.setVisibility(View.GONE); - } - -} +package org.xbmc.android.remote.presentation.wizard; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.ScrollView; + +import org.xbmc.android.remote.presentation.wizard.listener.PageCanFinishListener; + +import java.util.ArrayList; + +public abstract class WizardPage extends ScrollView { + + protected T input = null; + protected Wizard wizard; + private ArrayList listeners = new ArrayList(); + private boolean canFinish = false; + + public WizardPage(Context context, AttributeSet attrs, int defStyle, Wizard wizard) { + super(context, attrs, defStyle); + this.wizard = wizard; + } + + public WizardPage(Context context, AttributeSet attrs, Wizard wizard) { + super(context, attrs); + this.wizard = wizard; + } + + public WizardPage(Context context, Wizard wizard) { + super(context); + this.wizard = wizard; + } + + public void init() { + inflate(getContext(), getLayoutId(), this); + onInit(); + } + + public OnClickListener getNextClickListener() { + return new OnClickListener() { + public void onClick(View v) { + showNextPage(); + } + }; + } + + protected void showNextPage() { + wizard.showNextPage(); + } + + public abstract WizardPage getNextPage(); + + public abstract int getLayoutId(); + + protected abstract void onInit(); + + protected void showBusyMessage(String msg) { + wizard.showBusyMessage(msg); + } + + protected void removeBusyMessage() { + wizard.removeBusyMessage(); + } + + public T getInput() { + return input; + } + + public void setInput(T input) { + this.input = input; + } + + public boolean canFinish() { + return canFinish; + } + + protected void setCanFinish(boolean canFinish) { + this.canFinish = canFinish; + notifyCanFinishListeners(); + } + + private void notifyCanFinishListeners() { + for (PageCanFinishListener listener : listeners) { + listener.canFinish(canFinish); + } + } + + public void addCanFinishListener(PageCanFinishListener listener) { + listeners.add(listener); + } + + public void removeCanFinishListener(PageCanFinishListener listener) { + listeners.remove(listener); + } + + public void show() { + Animation animation = AnimationUtils.makeInAnimation(getContext(), false); + this.setAnimation(animation); + setVisibility(View.VISIBLE); + } + + public void hide() { + Animation animation = AnimationUtils.makeOutAnimation(getContext(), false); + this.setAnimation(animation); + this.setVisibility(View.GONE); + } + +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java similarity index 95% rename from src/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java index 915306e5..5e99f711 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/ActionListener.java @@ -1,7 +1,8 @@ -package org.xbmc.android.remote.presentation.wizard.listener; - -public interface ActionListener { - - public void onPreviousAction(); - public void onNextAction(); -} +package org.xbmc.android.remote.presentation.wizard.listener; + +public interface ActionListener { + + public void onPreviousAction(); + + public void onNextAction(); +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java similarity index 95% rename from src/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java index 8f22ed7b..1de7e3d2 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/listener/PageCanFinishListener.java @@ -1,7 +1,7 @@ -package org.xbmc.android.remote.presentation.wizard.listener; - - -public interface PageCanFinishListener { - - public void canFinish(boolean b); -} +package org.xbmc.android.remote.presentation.wizard.listener; + + +public interface PageCanFinishListener { + + public void canFinish(boolean b); +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java similarity index 96% rename from src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java index 5920eee2..393d9e91 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizard.java @@ -1,29 +1,29 @@ -package org.xbmc.android.remote.presentation.wizard.setupwizard; - -import org.xbmc.android.remote.presentation.wizard.Wizard; -import org.xbmc.android.remote.presentation.wizard.WizardPage; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.android.util.HostFactory; -import org.xbmc.api.object.Host; - -public class SetupWizard extends Wizard { - - private Host host; - - @Override - public void doSetupPages() { - host = new Host(); - WizardPage page = new SetupWizardPage1(this, this); - page.setInput(host); - addPage(page); - addPage(new SetupWizardPage2(this, this)); - addPage(new SetupWizardPage3(this, this)); - } - - @Override - protected void doFinish() { - HostFactory.addHost(this, host); - ClientFactory.resetClient(host); - } - -} +package org.xbmc.android.remote.presentation.wizard.setupwizard; + +import org.xbmc.android.remote.presentation.wizard.Wizard; +import org.xbmc.android.remote.presentation.wizard.WizardPage; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.android.util.HostFactory; +import org.xbmc.api.object.Host; + +public class SetupWizard extends Wizard { + + private Host host; + + @Override + public void doSetupPages() { + host = new Host(); + WizardPage page = new SetupWizardPage1(this, this); + page.setInput(host); + addPage(page); + addPage(new SetupWizardPage2(this, this)); + addPage(new SetupWizardPage3(this, this)); + } + + @Override + protected void doFinish() { + HostFactory.addHost(this, host); + ClientFactory.resetClient(host); + } + +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java similarity index 89% rename from src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java index b9e91573..9708532d 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage1.java @@ -1,161 +1,160 @@ -package org.xbmc.android.remote.presentation.wizard.setupwizard; - -import java.net.HttpURLConnection; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.http.HttpException; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.wizard.Wizard; -import org.xbmc.android.remote.presentation.wizard.WizardPage; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.android.util.HostFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.object.Host; -import org.xbmc.api.presentation.INotifiableController; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; - -public class SetupWizardPage1 extends WizardPage { - - private EditText port; - private EditText ip; - private EditText name; - private TextView errorMsg; - private final Handler mHandler; - private boolean needsLogin = false; - - private static final String validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; - - private static final String validHostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9])$"; - - private Pattern validHostPattern = Pattern.compile(validIpAddressRegex + "|" + validHostnameRegex); - - public SetupWizardPage1(Context context, AttributeSet attrs, int defStyle, - Wizard wizard) { - super(context, attrs, defStyle, wizard); - mHandler = new Handler(); - } - - public SetupWizardPage1(Context context, AttributeSet attrs, - Wizard wizard) { - super(context, attrs, wizard); - mHandler = new Handler(); - } - - public SetupWizardPage1(Context context, Wizard wizard) { - super(context, wizard); - mHandler = new Handler(); - } - - protected void onInit() { - name = (EditText) findViewById(R.id.setup_wizard_name); - ip = (EditText) findViewById(R.id.setup_wizard_ip); - port = (EditText) findViewById(R.id.setup_wizard_port); - errorMsg = (TextView) findViewById(R.id.setup_wizard_host_msg); - // test = (Button) findViewById(R.id.setup_wizard_test_connection); - // test.setOnClickListener(new OnClickListener() { - // public void onClick(View v) { - // testConnection(); - // } - // }); - setCanFinish(true); - } - - private void testConnection() { - showBusyMessage(getContext().getString( - R.string.setup_wizard_connecting_wait)); - final Host currHost = HostFactory.host; - getInput().name = name.getText().toString().trim(); - getInput().addr = ip.getText().toString().trim(); - getInput().port = Integer.parseInt(port.getText().toString()); - ClientFactory.resetClient(getInput()); - final IInfoManager info = ManagerFactory - .getInfoManager(new INotifiableController() { - public void runOnUI(Runnable action) { - mHandler.post(action); - } - - public void onWrongConnectionState(int state, - INotifiableManager manager, Command source) { - } - - public void onMessage(String message) { - } - - public void onError(final Exception e) { - runOnUI(new Runnable() { - public void run() { - // setCanFinish(false); - e.printStackTrace(); - if (e instanceof HttpException - && e.getMessage() - .equals(HttpURLConnection.HTTP_UNAUTHORIZED)) { - needsLogin = true; - errorMsg.setText(""); - showNextPage(); - } - ClientFactory.resetClient(currHost); - removeBusyMessage(); - errorMsg.setText(getContext().getString( - R.string.setup_wizard_cant_connect) - + e.getMessage()); - } - }); - } - }); - info.getSystemInfo(new DataResponse() { - @Override - public void run() { - if (value != null && !value.equals("")) { - removeBusyMessage(); - ClientFactory.resetClient(currHost); - errorMsg.setText(""); - // setCanFinish(true); - showNextPage(); - } - } - }, SystemInfo.SYSTEM_BUILD_VERSION, getContext()); - } - - @Override - public OnClickListener getNextClickListener() { - return new OnClickListener() { - public void onClick(View v) { - Matcher matcher = validHostPattern.matcher(ip.getText().toString().trim()); - if(!matcher.matches()) { - errorMsg.setText("Please enter a valid hostname or IP"); - }else { - errorMsg.setText(""); - testConnection(); - } - } - }; - } - - @Override - public WizardPage getNextPage() { - if (needsLogin) { - WizardPage page = new SetupWizardPageLogin(getContext(), - wizard); - page.init(); - return page; - } - return null; - } - - @Override - public int getLayoutId() { - return R.layout.setup_page_1; - } -} +package org.xbmc.android.remote.presentation.wizard.setupwizard; + +import android.content.Context; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import org.apache.http.HttpException; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.wizard.Wizard; +import org.xbmc.android.remote.presentation.wizard.WizardPage; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.android.util.HostFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.object.Host; +import org.xbmc.api.presentation.INotifiableController; + +import java.net.HttpURLConnection; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SetupWizardPage1 extends WizardPage { + + private static final String validIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}" + + "([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$"; + private static final String validHostnameRegex = "^(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*" + + "([A-Za-z]|[A-Za-z][A-Za-z0-9\\-]*[A-Za-z0-9])$"; + private Pattern validHostPattern = Pattern.compile(validIpAddressRegex + "|" + validHostnameRegex); + private final Handler mHandler; + private EditText port; + private EditText ip; + private EditText name; + private TextView errorMsg; + private boolean needsLogin = false; + + public SetupWizardPage1(Context context, AttributeSet attrs, int defStyle, + Wizard wizard) { + super(context, attrs, defStyle, wizard); + mHandler = new Handler(); + } + + public SetupWizardPage1(Context context, AttributeSet attrs, + Wizard wizard) { + super(context, attrs, wizard); + mHandler = new Handler(); + } + + public SetupWizardPage1(Context context, Wizard wizard) { + super(context, wizard); + mHandler = new Handler(); + } + + protected void onInit() { + name = (EditText) findViewById(R.id.setup_wizard_name); + ip = (EditText) findViewById(R.id.setup_wizard_ip); + port = (EditText) findViewById(R.id.setup_wizard_port); + errorMsg = (TextView) findViewById(R.id.setup_wizard_host_msg); + // test = (Button) findViewById(R.id.setup_wizard_test_connection); + // test.setOnClickListener(new OnClickListener() { + // public void onClick(View v) { + // testConnection(); + // } + // }); + setCanFinish(true); + } + + private void testConnection() { + showBusyMessage(getContext().getString( + R.string.setup_wizard_connecting_wait)); + final Host currHost = HostFactory.host; + getInput().name = name.getText().toString().trim(); + getInput().addr = ip.getText().toString().trim(); + getInput().port = Integer.parseInt(port.getText().toString()); + ClientFactory.resetClient(getInput()); + final IInfoManager info = ManagerFactory + .getInfoManager(new INotifiableController() { + public void runOnUI(Runnable action) { + mHandler.post(action); + } + + public void onWrongConnectionState(int state, + INotifiableManager manager, Command source) { + } + + public void onMessage(String message) { + } + + public void onError(final Exception e) { + runOnUI(new Runnable() { + public void run() { + // setCanFinish(false); + e.printStackTrace(); + if (e instanceof HttpException + && e.getMessage() + .equals(HttpURLConnection.HTTP_UNAUTHORIZED)) { + needsLogin = true; + errorMsg.setText(""); + showNextPage(); + } + ClientFactory.resetClient(currHost); + removeBusyMessage(); + errorMsg.setText(getContext().getString( + R.string.setup_wizard_cant_connect) + + e.getMessage()); + } + }); + } + }); + info.getSystemInfo(new DataResponse() { + @Override + public void run() { + if (value != null && !value.equals("")) { + removeBusyMessage(); + ClientFactory.resetClient(currHost); + errorMsg.setText(""); + // setCanFinish(true); + showNextPage(); + } + } + }, SystemInfo.SYSTEM_BUILD_VERSION, getContext()); + } + + @Override + public OnClickListener getNextClickListener() { + return new OnClickListener() { + public void onClick(View v) { + Matcher matcher = validHostPattern.matcher(ip.getText().toString().trim()); + if (!matcher.matches()) { + errorMsg.setText("Please enter a valid hostname or IP"); + } else { + errorMsg.setText(""); + testConnection(); + } + } + }; + } + + @Override + public WizardPage getNextPage() { + if (needsLogin) { + WizardPage page = new SetupWizardPageLogin(getContext(), + wizard); + page.init(); + return page; + } + return null; + } + + @Override + public int getLayoutId() { + return R.layout.setup_page_1; + } +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java similarity index 93% rename from src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java index 17a81919..1df61f93 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage2.java @@ -1,172 +1,172 @@ -package org.xbmc.android.remote.presentation.wizard.setupwizard; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.wizard.Wizard; -import org.xbmc.android.remote.presentation.wizard.WizardPage; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.info.GuiSettings; -import org.xbmc.api.object.Host; -import org.xbmc.api.presentation.INotifiableController; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.View; -import android.widget.CheckBox; -import android.widget.TextView; - -public class SetupWizardPage2 extends WizardPage { - - private IInfoManager info; - private Handler mHandler; - private TextView port; - private CheckBox enableES; - - private boolean esEnabled = false; - private boolean esAllEnabled = false; - private IControlManager control; - - public SetupWizardPage2(Context context, AttributeSet attrs, int defStyle, Wizard wizard) { - super(context, attrs, defStyle, wizard); - } - - public SetupWizardPage2(Context context, AttributeSet attrs, Wizard wizard) { - super(context, attrs, wizard); - } - - public SetupWizardPage2(Context context, Wizard wizard) { - super(context, wizard); - } - - protected void onInit() { - mHandler = new Handler(); - port = (TextView) findViewById(R.id.setup_wizard_es_port); - enableES = (CheckBox) findViewById(R.id.setup_wizard_enable_es); - } - - @Override - public void show() { - super.show(); - showBusyMessage(getContext().getString(R.string.setup_wizard_checking_es_wait)); - ClientFactory.resetClient(getInput()); - info = ManagerFactory.getInfoManager(new INotifiableController() { - - public void runOnUI(Runnable action) { - mHandler.post(action); - } - - public void onWrongConnectionState(int state, - INotifiableManager manager, Command source) { - } - - public void onMessage(String message) { - } - - public void onError(Exception e) { - - } - }); - control = ManagerFactory.getControlManager(new INotifiableController() { - public void runOnUI(Runnable action) { - mHandler.post(action); - } - - public void onWrongConnectionState(int state, - INotifiableManager manager, Command source) { - } - - public void onMessage(String message) { - } - - public void onError(Exception e) { - } - }); - info.getGuiSettingBool(new DataResponse() { - @Override - public void run() { - esEnabled = value.booleanValue(); - checkEnabledAll(); - } - }, GuiSettings.Services.EVENTSERVER_ENABLED, getContext()); - } - - private void checkEnabledAll() { - info.getGuiSettingBool(new DataResponse() { - public void run() { - esAllEnabled = value.booleanValue(); - getPort(); - } - }, GuiSettings.Services.EVENTSERVER_ENABLED_ALL, getContext()); - } - - private void getPort() { - info.getGuiSettingInt(new DataResponse() { - @Override - public void run() { - mHandler.post(new Runnable() { - public void run() { - if(value > 0) - port.setText(Integer.toString(value)); - removeBusyMessage(); - enableES.setChecked(esAllEnabled); - enableES.setEnabled(!esAllEnabled); - port.setEnabled(!esAllEnabled); - getInput().esPort = Integer.valueOf(port.getText().toString()); - setCanFinish(esEnabled && esAllEnabled); - enableES.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - enableES.setEnabled(false); - showBusyMessage(getContext().getString( - R.string.setup_wizard_enable_es_wait)); - enableES(); - } - }); - } - }); - } - }, GuiSettings.Services.EVENTSERVER_PORT, getContext()); - } - - private void enableES() { - if (!esEnabled) - control.setGuiSetting(new DataResponse() { - @Override - public void run() { - enableEsAll(); - } - }, GuiSettings.Services.EVENTSERVER_ENABLED, "true", getContext()); - else - enableEsAll(); - } - - private void enableEsAll() { - control.setGuiSetting(new DataResponse() { - @Override - public void run() { - enableES.setChecked(value); - enableES.setEnabled(!value); - port.setEnabled(!value); - setCanFinish(value); - removeBusyMessage(); - } - }, GuiSettings.Services.EVENTSERVER_ENABLED_ALL, "true", getContext()); - } - - @Override - public WizardPage getNextPage() { - return null; - } - - @Override - public int getLayoutId() { - return R.layout.setup_page_2; - } - - -} +package org.xbmc.android.remote.presentation.wizard.setupwizard; + +import android.content.Context; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.View; +import android.widget.CheckBox; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.wizard.Wizard; +import org.xbmc.android.remote.presentation.wizard.WizardPage; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.info.GuiSettings; +import org.xbmc.api.object.Host; +import org.xbmc.api.presentation.INotifiableController; + +public class SetupWizardPage2 extends WizardPage { + + private IInfoManager info; + private Handler mHandler; + private TextView port; + private CheckBox enableES; + + private boolean esEnabled = false; + private boolean esAllEnabled = false; + private IControlManager control; + + public SetupWizardPage2(Context context, AttributeSet attrs, int defStyle, Wizard wizard) { + super(context, attrs, defStyle, wizard); + } + + public SetupWizardPage2(Context context, AttributeSet attrs, Wizard wizard) { + super(context, attrs, wizard); + } + + public SetupWizardPage2(Context context, Wizard wizard) { + super(context, wizard); + } + + protected void onInit() { + mHandler = new Handler(); + port = (TextView) findViewById(R.id.setup_wizard_es_port); + enableES = (CheckBox) findViewById(R.id.setup_wizard_enable_es); + } + + @Override + public void show() { + super.show(); + showBusyMessage(getContext().getString(R.string.setup_wizard_checking_es_wait)); + ClientFactory.resetClient(getInput()); + info = ManagerFactory.getInfoManager(new INotifiableController() { + + public void runOnUI(Runnable action) { + mHandler.post(action); + } + + public void onWrongConnectionState(int state, + INotifiableManager manager, Command source) { + } + + public void onMessage(String message) { + } + + public void onError(Exception e) { + + } + }); + control = ManagerFactory.getControlManager(new INotifiableController() { + public void runOnUI(Runnable action) { + mHandler.post(action); + } + + public void onWrongConnectionState(int state, + INotifiableManager manager, Command source) { + } + + public void onMessage(String message) { + } + + public void onError(Exception e) { + } + }); + info.getGuiSettingBool(new DataResponse() { + @Override + public void run() { + esEnabled = value.booleanValue(); + checkEnabledAll(); + } + }, GuiSettings.Services.EVENTSERVER_ENABLED, getContext()); + } + + private void checkEnabledAll() { + info.getGuiSettingBool(new DataResponse() { + public void run() { + esAllEnabled = value.booleanValue(); + getPort(); + } + }, GuiSettings.Services.EVENTSERVER_ENABLED_ALL, getContext()); + } + + private void getPort() { + info.getGuiSettingInt(new DataResponse() { + @Override + public void run() { + mHandler.post(new Runnable() { + public void run() { + if (value > 0) + port.setText(Integer.toString(value)); + removeBusyMessage(); + enableES.setChecked(esAllEnabled); + enableES.setEnabled(!esAllEnabled); + port.setEnabled(!esAllEnabled); + getInput().esPort = Integer.valueOf(port.getText().toString()); + setCanFinish(esEnabled && esAllEnabled); + enableES.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + enableES.setEnabled(false); + showBusyMessage(getContext().getString( + R.string.setup_wizard_enable_es_wait)); + enableES(); + } + }); + } + }); + } + }, GuiSettings.Services.EVENTSERVER_PORT, getContext()); + } + + private void enableES() { + if (!esEnabled) + control.setGuiSetting(new DataResponse() { + @Override + public void run() { + enableEsAll(); + } + }, GuiSettings.Services.EVENTSERVER_ENABLED, "true", getContext()); + else + enableEsAll(); + } + + private void enableEsAll() { + control.setGuiSetting(new DataResponse() { + @Override + public void run() { + enableES.setChecked(value); + enableES.setEnabled(!value); + port.setEnabled(!value); + setCanFinish(value); + removeBusyMessage(); + } + }, GuiSettings.Services.EVENTSERVER_ENABLED_ALL, "true", getContext()); + } + + @Override + public WizardPage getNextPage() { + return null; + } + + @Override + public int getLayoutId() { + return R.layout.setup_page_2; + } + + +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java similarity index 92% rename from src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java index 9e79fd2b..dca25b63 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPage3.java @@ -1,126 +1,129 @@ -package org.xbmc.android.remote.presentation.wizard.setupwizard; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.wizard.Wizard; -import org.xbmc.android.remote.presentation.wizard.WizardPage; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IControlManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.Host; -import org.xbmc.api.presentation.INotifiableController; -import org.xbmc.eventclient.ButtonCodes; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -public class SetupWizardPage3 extends WizardPage { - - private Button retry; - private TextView msg; - private Handler mHandler; - private IControlManager control; - - private int initialVolume = -1; - private IEventClientManager event; - - public SetupWizardPage3(Context context, AttributeSet attrs, int defStyle, - Wizard wizard) { - super(context, attrs, defStyle, wizard); - } - - public SetupWizardPage3(Context context, AttributeSet attrs, - Wizard wizard) { - super(context, attrs, wizard); - } - - public SetupWizardPage3(Context context, Wizard wizard) { - super(context, wizard); - } - - @Override - public WizardPage getNextPage() { - return null; - } - - @Override - public int getLayoutId() { - return R.layout.setup_page_3; - } - - @Override - protected void onInit() { - - retry = (Button) findViewById(R.id.setup_page3_retry); - msg = (TextView) findViewById(R.id.setup_page3_msg); - } - - private void testEventServer() { - showBusyMessage(getContext().getString(R.string.setup_wizard_trying_mute)); - control.getVolume(new DataResponse() { - @Override - public void run() { - initialVolume = value; - mute(); - } - }, getContext()); - - } - - @Override - public void show() { - super.show(); - ClientFactory.resetClient(getInput()); - mHandler = new Handler(); - INotifiableController controller = new INotifiableController() { - public void runOnUI(Runnable action) { - mHandler.post(action); - } - public void onWrongConnectionState(int state, INotifiableManager manager, - Command source) { - } - public void onMessage(String message) { - } - public void onError(Exception e) { - } - }; - retry.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - msg.setText(""); - retry.setVisibility(View.INVISIBLE); - testEventServer(); - } - }); - control = ManagerFactory.getControlManager(controller); - event = ManagerFactory.getEventClientManager(controller); - testEventServer(); - } - - private void mute() { - - event.sendButton("R1", ButtonCodes.REMOTE_MUTE, false, true, true, (short) 0, (byte) 0); - control.getVolume(new DataResponse() { - @Override - public void run() { - removeBusyMessage(); - if(initialVolume != value) { - //it worked, we muted xbmc through the eventserver - msg.setText(R.string.setup_wizard_final_message); - event.sendButton("R1", ButtonCodes.REMOTE_MUTE, false, true, true, (short) 0, (byte) 0); - setCanFinish(true); - }else{ - //we couldn't mute xbmc through the eventserver, so display some help. - retry.setVisibility(View.VISIBLE); - msg.setText(R.string.setup_wizard_muting_failed); - } - } - }, getContext()); - } -} +package org.xbmc.android.remote.presentation.wizard.setupwizard; + +import android.content.Context; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.wizard.Wizard; +import org.xbmc.android.remote.presentation.wizard.WizardPage; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IControlManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.Host; +import org.xbmc.api.presentation.INotifiableController; +import org.xbmc.eventclient.ButtonCodes; + +public class SetupWizardPage3 extends WizardPage { + + private Button retry; + private TextView msg; + private Handler mHandler; + private IControlManager control; + + private int initialVolume = -1; + private IEventClientManager event; + + public SetupWizardPage3(Context context, AttributeSet attrs, int defStyle, + Wizard wizard) { + super(context, attrs, defStyle, wizard); + } + + public SetupWizardPage3(Context context, AttributeSet attrs, + Wizard wizard) { + super(context, attrs, wizard); + } + + public SetupWizardPage3(Context context, Wizard wizard) { + super(context, wizard); + } + + @Override + public WizardPage getNextPage() { + return null; + } + + @Override + public int getLayoutId() { + return R.layout.setup_page_3; + } + + @Override + protected void onInit() { + + retry = (Button) findViewById(R.id.setup_page3_retry); + msg = (TextView) findViewById(R.id.setup_page3_msg); + } + + private void testEventServer() { + showBusyMessage(getContext().getString(R.string.setup_wizard_trying_mute)); + control.getVolume(new DataResponse() { + @Override + public void run() { + initialVolume = value; + mute(); + } + }, getContext()); + + } + + @Override + public void show() { + super.show(); + ClientFactory.resetClient(getInput()); + mHandler = new Handler(); + INotifiableController controller = new INotifiableController() { + public void runOnUI(Runnable action) { + mHandler.post(action); + } + + public void onWrongConnectionState(int state, INotifiableManager manager, + Command source) { + } + + public void onMessage(String message) { + } + + public void onError(Exception e) { + } + }; + retry.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + msg.setText(""); + retry.setVisibility(View.INVISIBLE); + testEventServer(); + } + }); + control = ManagerFactory.getControlManager(controller); + event = ManagerFactory.getEventClientManager(controller); + testEventServer(); + } + + private void mute() { + + event.sendButton("R1", ButtonCodes.REMOTE_MUTE, false, true, true, (short) 0, (byte) 0); + control.getVolume(new DataResponse() { + @Override + public void run() { + removeBusyMessage(); + if (initialVolume != value) { + //it worked, we muted xbmc through the eventserver + msg.setText(R.string.setup_wizard_final_message); + event.sendButton("R1", ButtonCodes.REMOTE_MUTE, false, true, true, (short) 0, (byte) 0); + setCanFinish(true); + } else { + //we couldn't mute xbmc through the eventserver, so display some help. + retry.setVisibility(View.VISIBLE); + msg.setText(R.string.setup_wizard_muting_failed); + } + } + }, getContext()); + } +} diff --git a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java similarity index 85% rename from src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java rename to app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java index afe99216..8c9562a2 100644 --- a/src/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java +++ b/app/src/main/java/org/xbmc/android/remote/presentation/wizard/setupwizard/SetupWizardPageLogin.java @@ -1,109 +1,109 @@ -package org.xbmc.android.remote.presentation.wizard.setupwizard; - -import java.net.HttpURLConnection; - -import org.apache.http.HttpException; -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.business.Command; -import org.xbmc.android.remote.business.ManagerFactory; -import org.xbmc.android.remote.presentation.wizard.Wizard; -import org.xbmc.android.remote.presentation.wizard.WizardPage; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.IInfoManager; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.object.Host; -import org.xbmc.api.presentation.INotifiableController; - -import android.content.Context; -import android.os.Handler; -import android.util.AttributeSet; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; - -public class SetupWizardPageLogin extends WizardPage { - - private EditText username; - private EditText password; - private Handler mHandler; - private TextView errorMsg; - - public SetupWizardPageLogin(Context context, AttributeSet attrs, - int defStyle, Wizard wizard) { - super(context, attrs, defStyle, wizard); - } - - public SetupWizardPageLogin(Context context, AttributeSet attrs, - Wizard wizard) { - super(context, attrs, wizard); - } - - public SetupWizardPageLogin(Context context, Wizard wizard) { - super(context, wizard); - } - - @Override - public WizardPage getNextPage() { - return null; - } - - @Override - public int getLayoutId() { - return R.layout.setup_page_login; - } - - @Override - protected void onInit() { - mHandler = new Handler(); - username = (EditText)findViewById(R.id.setup_wizard_username); - password = (EditText)findViewById(R.id.setup_wizard_password); - errorMsg = (TextView)findViewById(R.id.setup_page_login_msg); - setCanFinish(true); - } - - @Override - public OnClickListener getNextClickListener() { - return new OnClickListener() { - public void onClick(View v) { - getInput().user = username.getText().toString(); - getInput().pass = password.getText().toString(); - ClientFactory.resetClient(getInput()); - testConnection(); - } - }; - } - - private void testConnection() { - IInfoManager info = ManagerFactory.getInfoManager(new INotifiableController() { - public void runOnUI(Runnable action) { - mHandler.post(action); - } - - public void onWrongConnectionState(int state, INotifiableManager manager, - Command source) { - } - - public void onMessage(String message) { - } - - public void onError(Exception e) { - if (e instanceof HttpException - && e.getMessage() - .equals(HttpURLConnection.HTTP_UNAUTHORIZED)) { - errorMsg.setText(R.string.setup_wizard_login_wrong); - } - } - }); - info.getSystemInfo(new DataResponse() { - @Override - public void run() { - if(value != null && !value.equals("")) { - //ok, finally we got it, we can login into xbmc - showNextPage(); - } - } - }, SystemInfo.SYSTEM_BUILD_VERSION, getContext()); - } -} +package org.xbmc.android.remote.presentation.wizard.setupwizard; + +import android.content.Context; +import android.os.Handler; +import android.util.AttributeSet; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import org.apache.http.HttpException; +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.business.Command; +import org.xbmc.android.remote.business.ManagerFactory; +import org.xbmc.android.remote.presentation.wizard.Wizard; +import org.xbmc.android.remote.presentation.wizard.WizardPage; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.IInfoManager; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.object.Host; +import org.xbmc.api.presentation.INotifiableController; + +import java.net.HttpURLConnection; + +public class SetupWizardPageLogin extends WizardPage { + + private EditText username; + private EditText password; + private Handler mHandler; + private TextView errorMsg; + + public SetupWizardPageLogin(Context context, AttributeSet attrs, + int defStyle, Wizard wizard) { + super(context, attrs, defStyle, wizard); + } + + public SetupWizardPageLogin(Context context, AttributeSet attrs, + Wizard wizard) { + super(context, attrs, wizard); + } + + public SetupWizardPageLogin(Context context, Wizard wizard) { + super(context, wizard); + } + + @Override + public WizardPage getNextPage() { + return null; + } + + @Override + public int getLayoutId() { + return R.layout.setup_page_login; + } + + @Override + protected void onInit() { + mHandler = new Handler(); + username = (EditText) findViewById(R.id.setup_wizard_username); + password = (EditText) findViewById(R.id.setup_wizard_password); + errorMsg = (TextView) findViewById(R.id.setup_page_login_msg); + setCanFinish(true); + } + + @Override + public OnClickListener getNextClickListener() { + return new OnClickListener() { + public void onClick(View v) { + getInput().user = username.getText().toString(); + getInput().pass = password.getText().toString(); + ClientFactory.resetClient(getInput()); + testConnection(); + } + }; + } + + private void testConnection() { + IInfoManager info = ManagerFactory.getInfoManager(new INotifiableController() { + public void runOnUI(Runnable action) { + mHandler.post(action); + } + + public void onWrongConnectionState(int state, INotifiableManager manager, + Command source) { + } + + public void onMessage(String message) { + } + + public void onError(Exception e) { + if (e instanceof HttpException + && e.getMessage() + .equals(HttpURLConnection.HTTP_UNAUTHORIZED)) { + errorMsg.setText(R.string.setup_wizard_login_wrong); + } + } + }); + info.getSystemInfo(new DataResponse() { + @Override + public void run() { + if (value != null && !value.equals("")) { + //ok, finally we got it, we can login into xbmc + showNextPage(); + } + } + }, SystemInfo.SYSTEM_BUILD_VERSION, getContext()); + } +} diff --git a/app/src/main/java/org/xbmc/android/util/Base64.java b/app/src/main/java/org/xbmc/android/util/Base64.java new file mode 100644 index 00000000..e27b888b --- /dev/null +++ b/app/src/main/java/org/xbmc/android/util/Base64.java @@ -0,0 +1,2094 @@ +package org.xbmc.android.util; + +/** + *

Encodes and decodes to and from Base64 notation.

+ *

Homepage: http://iharder.net/base64.

+ *

+ *

Example:

+ *

+ * String encoded = Base64.encode( myByteArray ); + *
+ * byte[] myByteArray = Base64.decode( encoded ); + *

+ *

The options parameter, which appears in a few places, is used to pass + * several pieces of information to the encoder. In the "higher level" methods such as + * encodeBytes( bytes, options ) the options parameter can be used to indicate such + * things as first gzipping the bytes before encoding them, not inserting linefeeds, + * and encoding using the URL-safe and Ordered dialects.

+ *

+ *

Note, according to RFC3548, + * Section 2.1, implementations should not add line feeds unless explicitly told + * to do so. I've got Base64 set to this behavior now, although earlier versions + * broke lines by default.

+ *

+ *

The constants defined in Base64 can be OR-ed together to combine options, so you + * might make a call like this:

+ *

+ * String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES ); + *

to compress the data before encoding it and then making the output have newline characters.

+ *

Also...

+ * String encoded = Base64.encodeBytes( crazyString.getBytes() ); + *

+ *

+ *

+ *

+ * Change Log: + *

+ *
    + *
  • v2.3.4 - Fixed bug when working with gzipped streams whereby flushing + * the Base64.OutputStream closed the Base64 encoding (by padding with equals + * signs) too soon. Also added an option to suppress the automatic decoding + * of gzipped streams. Also added experimental support for specifying a + * class loader when using the + * {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)} + * method.
  • + *
  • v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java + * footprint with its CharEncoders and so forth. Fixed some javadocs that were + * inconsistent. Removed imports and specified things like java.io.IOException + * explicitly inline.
  • + *
  • v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the + * final encoded data will be so that the code doesn't have to create two output + * arrays: an oversized initial one and then a final, exact-sized one. Big win + * when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not + * using the gzip options which uses a different mechanism with streams and stuff).
  • + *
  • v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some + * similar helper methods to be more efficient with memory by not returning a + * String but just a byte array.
  • + *
  • v2.3 - This is not a drop-in replacement! This is two years of comments + * and bug fixes queued up and finally executed. Thanks to everyone who sent + * me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else. + * Much bad coding was cleaned up including throwing exceptions where necessary + * instead of returning null values or something similar. Here are some changes + * that may affect you: + *
      + *
    • Does not break lines, by default. This is to keep in compliance with + * RFC3548.
    • + *
    • Throws exceptions instead of returning null values. Because some operations + * (especially those that may permit the GZIP option) use IO streams, there + * is a possiblity of an java.io.IOException being thrown. After some discussion and + * thought, I've changed the behavior of the methods to throw java.io.IOExceptions + * rather than return null if ever there's an error. I think this is more + * appropriate, though it will require some changes to your code. Sorry, + * it should have been done this way to begin with.
    • + *
    • Removed all references to System.out, System.err, and the like. + * Shame on me. All I can say is sorry they were ever there.
    • + *
    • Throws NullPointerExceptions and IllegalArgumentExceptions as needed + * such as when passed arrays are null or offsets are invalid.
    • + *
    • Cleaned up as much javadoc as I could to avoid any javadoc warnings. + * This was especially annoying before for people who were thorough in their + * own projects and then had gobs of javadoc warnings on this file.
    • + *
    + *
  • v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug + * when using very small files (~< 40 bytes).
  • + *
  • v2.2 - Added some helper methods for encoding/decoding directly from + * one file to the next. Also added a main() method to support command line + * encoding/decoding from one file to the next. Also added these Base64 dialects: + *
      + *
    1. The default is RFC3548 format.
    2. + *
    3. Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates + * URL and file name friendly format as described in Section 4 of RFC3548. + * http://www.faqs.org/rfcs/rfc3548.html
    4. + *
    5. Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates + * URL and file name friendly format that preserves lexical ordering as described + * in http://www.faqs.org/qa/rfcc-1940.html
    6. + *
    + * Special thanks to Jim Kellerman at http://www.powerset.com/ + * for contributing the new Base64 dialects. + *
  • + *

    + *

  • v2.1 - Cleaned up javadoc comments and unused variables and methods. Added + * some convenience methods for reading and writing to and from files.
  • + *
  • v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems + * with other encodings (like EBCDIC).
  • + *
  • v2.0.1 - Fixed an error when decoding a single byte, that is, when the + * encoded data was a single byte.
  • + *
  • v2.0 - I got rid of methods that used booleans to set options. + * Now everything is more consolidated and cleaner. The code now detects + * when data that's being decoded is gzip-compressed and will decompress it + * automatically. Generally things are cleaner. You'll probably have to + * change some method calls that you were making to support the new + * options format (ints that you "OR" together).
  • + *
  • v1.5.1 - Fixed bug when decompressing and decoding to a + * byte[] using decode( String s, boolean gzipCompressed ). + * Added the ability to "suspend" encoding in the Output Stream so + * you can turn on and off the encoding if you need to embed base64 + * data in an otherwise "normal" stream (like an XML file).
  • + *
  • v1.5 - Output stream pases on flush() command but doesn't do anything itself. + * This helps when using GZIP streams. + * Added the ability to GZip-compress objects before encoding them.
  • + *
  • v1.4 - Added helper methods to read/write files.
  • + *
  • v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.
  • + *
  • v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream + * where last buffer being read, if not completely full, was not returned.
  • + *
  • v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.
  • + *
  • v1.3.3 - Fixed I/O streams which were totally messed up.
  • + *
+ *

+ *

+ * I am placing this code in the Public Domain. Do with it as you will. + * This software comes with no guarantees or warranties but with + * plenty of well-wishing instead! + * Please visit http://iharder.net/base64 + * periodically to check for updates or to contribute improvements. + *

+ * + * @author Robert Harder + * @author rob@iharder.net + * @version 2.3.3 + */ +public class Base64 { + +/* ******** P U B L I C F I E L D S ******** */ + + + /** + * No options specified. Value is zero. + */ + public final static int NO_OPTIONS = 0; + + /** + * Specify encoding in first bit. Value is one. + */ + public final static int ENCODE = 1; + + + /** + * Specify decoding in first bit. Value is zero. + */ + public final static int DECODE = 0; + + + /** + * Specify that data should be gzip-compressed in second bit. Value is two. + */ + public final static int GZIP = 2; + + /** + * Specify that gzipped data should not be automatically gunzipped. + */ + public final static int DONT_GUNZIP = 4; + + + /** + * Do break lines when encoding. Value is 8. + */ + public final static int DO_BREAK_LINES = 8; + + /** + * Encode using Base64-like encoding that is URL- and Filename-safe as described + * in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * It is important to note that data encoded this way is not officially valid Base64, + * or at the very least should not be called Base64 without also specifying that is + * was encoded using the URL- and Filename-safe dialect. + */ + public final static int URL_SAFE = 16; + + + /** + * Encode using the special "ordered" dialect of Base64 described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + public final static int ORDERED = 32; + + +/* ******** P R I V A T E F I E L D S ******** */ + + + /** + * Maximum line length (76) of Base64 output. + */ + private final static int MAX_LINE_LENGTH = 76; + + + /** + * The equals sign (=) as a byte. + */ + private final static byte EQUALS_SIGN = (byte) '='; + + + /** + * The new line character (\n) as a byte. + */ + private final static byte NEW_LINE = (byte) '\n'; + + + /** + * Preferred encoding. + */ + private final static String PREFERRED_ENCODING = "US-ASCII"; + + + private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding + private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding + + +/* ******** S T A N D A R D B A S E 6 4 A L P H A B E T ******** */ + + /** + * The 64 valid Base64 values. + */ + /* Host platform me be something funny like EBCDIC, so we hardcode these values. */ + private final static byte[] _STANDARD_ALPHABET = { + (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', + (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', + (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', + (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', + (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', + (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', + (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', + (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '+', (byte) '/' + }; + + + /** + * Translates a Base64 value to either its 6-bit reconstruction value + * or a negative number indicating some other meaning. + */ + private final static byte[] _STANDARD_DECODABET = { + -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + 62, // Plus sign at decimal 43 + -9, -9, -9, // Decimal 44 - 46 + 63, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** U R L S A F E B A S E 6 4 A L P H A B E T ******** */ + + /** + * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: + * http://www.faqs.org/rfcs/rfc3548.html. + * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash." + */ + private final static byte[] _URL_SAFE_ALPHABET = { + (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', + (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', + (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', + (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', + (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', + (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z', + (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', + (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) '-', (byte) '_' + }; + + /** + * Used in decoding URL- and Filename-safe dialects of Base64. + */ + private final static byte[] _URL_SAFE_DECODABET = { + -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 62, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' + -9, -9, -9, -9, // Decimal 91 - 94 + 63, // Underscore at decimal 95 + -9, // Decimal 96 + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + + +/* ******** O R D E R E D B A S E 6 4 A L P H A B E T ******** */ + + /** + * I don't get the point of this technique, but someone requested it, + * and it is described here: + * http://www.faqs.org/qa/rfcc-1940.html. + */ + private final static byte[] _ORDERED_ALPHABET = { + (byte) '-', + (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', + (byte) '5', (byte) '6', (byte) '7', (byte) '8', (byte) '9', + (byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', (byte) 'G', + (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', (byte) 'L', (byte) 'M', (byte) 'N', + (byte) 'O', (byte) 'P', (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', + (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', + (byte) '_', + (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f', (byte) 'g', + (byte) 'h', (byte) 'i', (byte) 'j', (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', + (byte) 'o', (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', (byte) 'u', + (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', (byte) 'z' + }; + + /** + * Used in decoding the "ordered" dialect of Base64. + */ + private final static byte[] _ORDERED_DECODABET = { + -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 + -5, -5, // Whitespace: Tab and Linefeed + -9, -9, // Decimal 11 - 12 + -5, // Whitespace: Carriage Return + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 + -9, -9, -9, -9, -9, // Decimal 27 - 31 + -5, // Whitespace: Space + -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 + -9, // Plus sign at decimal 43 + -9, // Decimal 44 + 0, // Minus sign at decimal 45 + -9, // Decimal 46 + -9, // Slash at decimal 47 + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // Numbers zero through nine + -9, -9, -9, // Decimal 58 - 60 + -1, // Equals sign at decimal 61 + -9, -9, -9, // Decimal 62 - 64 + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, // Letters 'A' through 'M' + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, // Letters 'N' through 'Z' + -9, -9, -9, -9, // Decimal 91 - 94 + 37, // Underscore at decimal 95 + -9, // Decimal 96 + 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, // Letters 'a' through 'm' + 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // Letters 'n' through 'z' + -9, -9, -9, -9 // Decimal 123 - 126 + /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 + -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ + }; + + +/* ******** D E T E R M I N E W H I C H A L H A B E T ******** */ + + + /** + * Defeats instantiation. + */ + private Base64() { + } + + /** + * Returns one of the _SOMETHING_ALPHABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URLSAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getAlphabet(int options) { + if ((options & URL_SAFE) == URL_SAFE) { + return _URL_SAFE_ALPHABET; + } else if ((options & ORDERED) == ORDERED) { + return _ORDERED_ALPHABET; + } else { + return _STANDARD_ALPHABET; + } + } // end getAlphabet + + /** + * Returns one of the _SOMETHING_DECODABET byte arrays depending on + * the options specified. + * It's possible, though silly, to specify ORDERED and URL_SAFE + * in which case one of them will be picked, though there is + * no guarantee as to which one will be picked. + */ + private final static byte[] getDecodabet(int options) { + if ((options & URL_SAFE) == URL_SAFE) { + return _URL_SAFE_DECODABET; + } else if ((options & ORDERED) == ORDERED) { + return _ORDERED_DECODABET; + } else { + return _STANDARD_DECODABET; + } + } // end getAlphabet + + + + +/* ******** E N C O D I N G M E T H O D S ******** */ + + /** + * Encodes up to the first three bytes of array threeBytes + * and returns a four-byte array in Base64 notation. + * The actual number of significant bytes in your array is + * given by numSigBytes. + * The array threeBytes needs only be as big as + * numSigBytes. + * Code can reuse a byte array by passing a four-byte array as b4. + * + * @param b4 A reusable byte array to reduce array instantiation + * @param threeBytes the array to convert + * @param numSigBytes the number of significant bytes in your array + * @return four byte array in Base64 notation. + * @since 1.5.1 + */ + private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes, int options) { + encode3to4(threeBytes, 0, numSigBytes, b4, 0, options); + return b4; + } // end encode3to4 + + + /** + *

Encodes up to three bytes of the array source + * and writes the resulting four Base64 bytes to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 3 for + * the source array or destOffset + 4 for + * the destination array. + * The actual number of significant bytes in your array is + * given by numSigBytes.

+ *

This is the lowest level of the encoding methods with + * all possible parameters.

+ * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param numSigBytes the number of significant bytes in your array + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @return the destination array + * @since 1.3 + */ + private static byte[] encode3to4( + byte[] source, int srcOffset, int numSigBytes, + byte[] destination, int destOffset, int options) { + + byte[] ALPHABET = getAlphabet(options); + + // 1 2 3 + // 01234567890123456789012345678901 Bit position + // --------000000001111111122222222 Array position from threeBytes + // --------| || || || | Six bit groups to index ALPHABET + // >>18 >>12 >> 6 >> 0 Right shift necessary + // 0x3f 0x3f 0x3f Additional AND + + // Create buffer with zero-padding if there are only one or two + // significant bytes passed in the array. + // We have to shift left 24 in order to flush out the 1's that appear + // when Java treats a value as negative that is cast from a byte to an int. + int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) + | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) + | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); + + switch (numSigBytes) { + case 3: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f]; + return destination; + + case 2: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f]; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + case 1: + destination[destOffset] = ALPHABET[(inBuff >>> 18)]; + destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f]; + destination[destOffset + 2] = EQUALS_SIGN; + destination[destOffset + 3] = EQUALS_SIGN; + return destination; + + default: + return destination; + } // end switch + } // end encode3to4 + + + /** + * Performs Base64 encoding on the raw ByteBuffer, + * writing it to the encoded ByteBuffer. + * This is an experimental feature. Currently it does not + * pass along any options (such as {@link #DO_BREAK_LINES} + * or {@link #GZIP}. + * + * @param raw input buffer + * @param encoded output buffer + * @since 2.3 + */ + public static void encode(java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded) { + byte[] raw3 = new byte[3]; + byte[] enc4 = new byte[4]; + + while (raw.hasRemaining()) { + int rem = Math.min(3, raw.remaining()); + raw.get(raw3, 0, rem); + Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS); + encoded.put(enc4); + } // end input remaining + } + + + /** + * Performs Base64 encoding on the raw ByteBuffer, + * writing it to the encoded CharBuffer. + * This is an experimental feature. Currently it does not + * pass along any options (such as {@link #DO_BREAK_LINES} + * or {@link #GZIP}. + * + * @param raw input buffer + * @param encoded output buffer + * @since 2.3 + */ + public static void encode(java.nio.ByteBuffer raw, java.nio.CharBuffer encoded) { + byte[] raw3 = new byte[3]; + byte[] enc4 = new byte[4]; + + while (raw.hasRemaining()) { + int rem = Math.min(3, raw.remaining()); + raw.get(raw3, 0, rem); + Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS); + for (int i = 0; i < 4; i++) { + encoded.put((char) (enc4[i] & 0xFF)); + } + } // end input remaining + } + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. + *

+ *

As of v 2.3, if the object + * cannot be serialized or there is another error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.

+ *

+ * The object is not GZip-compressed before being encoded. + * + * @param serializableObject The object to encode + * @return The Base64-encoded object + * @throws java.io.IOException if there is an error + * @throws NullPointerException if serializedObject is null + * @since 1.4 + */ + public static String encodeObject(java.io.Serializable serializableObject) + throws java.io.IOException { + return encodeObject(serializableObject, NO_OPTIONS); + } // end encodeObject + + + /** + * Serializes an object and returns the Base64-encoded + * version of that serialized object. + *

+ *

As of v 2.3, if the object + * cannot be serialized or there is another error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.

+ *

+ * The object is not GZip-compressed before being encoded. + *

+ * Example options:

+	 *   GZIP: gzip-compresses object before encoding it.
+	 *   DO_BREAK_LINES: break lines at 76 characters
+	 * 
+ *

+ * Example: encodeObject( myObj, Base64.GZIP ) or + *

+ * Example: encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES ) + * + * @param serializableObject The object to encode + * @param options Specified options + * @return The Base64-encoded object + * @throws java.io.IOException if there is an error + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @since 2.0 + */ + public static String encodeObject(java.io.Serializable serializableObject, int options) + throws java.io.IOException { + + if (serializableObject == null) { + throw new NullPointerException("Cannot serialize a null object."); + } // end if: null + + // Streams + java.io.ByteArrayOutputStream baos = null; + java.io.OutputStream b64os = null; + java.util.zip.GZIPOutputStream gzos = null; + java.io.ObjectOutputStream oos = null; + + + try { + // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream(baos, ENCODE | options); + if ((options & GZIP) != 0) { + // Gzip + gzos = new java.util.zip.GZIPOutputStream(b64os); + oos = new java.io.ObjectOutputStream(gzos); + } else { + // Not gzipped + oos = new java.io.ObjectOutputStream(b64os); + } + oos.writeObject(serializableObject); + } // end try + catch (java.io.IOException e) { + // Catch it and then throw it immediately so that + // the finally{} block is called for cleanup. + throw e; + } // end catch + finally { + try { + oos.close(); + } catch (Exception e) { + } + try { + gzos.close(); + } catch (Exception e) { + } + try { + b64os.close(); + } catch (Exception e) { + } + try { + baos.close(); + } catch (Exception e) { + } + } // end finally + + // Return value according to relevant encoding. + try { + return new String(baos.toByteArray(), PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + // Fall back to some Java default + return new String(baos.toByteArray()); + } // end catch + + } // end encode + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + * + * @param source The data to convert + * @return The data in Base64-encoded form + * @throws NullPointerException if source array is null + * @since 1.4 + */ + public static String encodeBytes(byte[] source) { + // Since we're not going to have the GZIP encoding turned on, + // we're not going to have an java.io.IOException thrown, so + // we should not force the user to have to catch it. + String encoded = null; + try { + encoded = encodeBytes(source, 0, source.length, NO_OPTIONS); + } catch (java.io.IOException ex) { + assert false : ex.getMessage(); + } // end catch + assert encoded != null; + return encoded; + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + *

+ * Example options:

+	 *   GZIP: gzip-compresses object before encoding it.
+	 *   DO_BREAK_LINES: break lines at 76 characters
+	 *     Note: Technically, this makes your encoding non-compliant.
+	 * 
+ *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) + *

+ *

+ *

As of v 2.3, if there is an error with the GZIP stream, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param source The data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes(byte[] source, int options) throws java.io.IOException { + return encodeBytes(source, 0, source.length, options); + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + * Does not GZip-compress data. + *

+ *

As of v 2.3, if there is an error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @return The Base64-encoded data as a String + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @since 1.4 + */ + public static String encodeBytes(byte[] source, int off, int len) { + // Since we're not going to have the GZIP encoding turned on, + // we're not going to have an java.io.IOException thrown, so + // we should not force the user to have to catch it. + String encoded = null; + try { + encoded = encodeBytes(source, off, len, NO_OPTIONS); + } catch (java.io.IOException ex) { + assert false : ex.getMessage(); + } // end catch + assert encoded != null; + return encoded; + } // end encodeBytes + + + /** + * Encodes a byte array into Base64 notation. + *

+ * Example options:

+	 *   GZIP: gzip-compresses object before encoding it.
+	 *   DO_BREAK_LINES: break lines at 76 characters
+	 *     Note: Technically, this makes your encoding non-compliant.
+	 * 
+ *

+ * Example: encodeBytes( myData, Base64.GZIP ) or + *

+ * Example: encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES ) + *

+ *

+ *

As of v 2.3, if there is an error with the GZIP stream, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned a null value, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @since 2.0 + */ + public static String encodeBytes(byte[] source, int off, int len, int options) throws java.io.IOException { + byte[] encoded = encodeBytesToBytes(source, off, len, options); + + // Return value according to relevant encoding. + try { + return new String(encoded, PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uue) { + return new String(encoded); + } // end catch + + } // end encodeBytes + + + /** + * Similar to {@link #encodeBytes(byte[])} but returns + * a byte array instead of instantiating a String. This is more efficient + * if you're working with I/O streams and have large data sets to encode. + * + * @param source The data to convert + * @return The Base64-encoded data as a byte[] (of ASCII characters) + * @throws NullPointerException if source array is null + * @since 2.3.1 + */ + public static byte[] encodeBytesToBytes(byte[] source) { + byte[] encoded = null; + try { + encoded = encodeBytesToBytes(source, 0, source.length, Base64.NO_OPTIONS); + } catch (java.io.IOException ex) { + assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); + } + return encoded; + } + + + /** + * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns + * a byte array instead of instantiating a String. This is more efficient + * if you're working with I/O streams and have large data sets to encode. + * + * @param source The data to convert + * @param off Offset in array where conversion should begin + * @param len Length of data to convert + * @param options Specified options + * @return The Base64-encoded data as a String + * @throws java.io.IOException if there is an error + * @throws NullPointerException if source array is null + * @throws IllegalArgumentException if source array, offset, or length are invalid + * @see Base64#GZIP + * @see Base64#DO_BREAK_LINES + * @since 2.3.1 + */ + public static byte[] encodeBytesToBytes(byte[] source, int off, int len, int options) throws java.io.IOException { + + if (source == null) { + throw new NullPointerException("Cannot serialize a null array."); + } // end if: null + + if (off < 0) { + throw new IllegalArgumentException("Cannot have negative offset: " + off); + } // end if: off < 0 + + if (len < 0) { + throw new IllegalArgumentException("Cannot have length offset: " + len); + } // end if: len < 0 + + if (off + len > source.length) { + throw new IllegalArgumentException( + String.format("Cannot have offset of %d and length of %d with array of length %d", off, len, + source.length) + ); + } // end if: off < 0 + + + // Compress? + if ((options & GZIP) != 0) { + java.io.ByteArrayOutputStream baos = null; + java.util.zip.GZIPOutputStream gzos = null; + Base64.OutputStream b64os = null; + + try { + // GZip -> Base64 -> ByteArray + baos = new java.io.ByteArrayOutputStream(); + b64os = new Base64.OutputStream(baos, ENCODE | options); + gzos = new java.util.zip.GZIPOutputStream(b64os); + + gzos.write(source, off, len); + gzos.close(); + } // end try + catch (java.io.IOException e) { + // Catch it and then throw it immediately so that + // the finally{} block is called for cleanup. + throw e; + } // end catch + finally { + try { + gzos.close(); + } catch (Exception e) { + } + try { + b64os.close(); + } catch (Exception e) { + } + try { + baos.close(); + } catch (Exception e) { + } + } // end finally + + return baos.toByteArray(); + } // end if: compress + + // Else, don't compress. Better not to use streams at all then. + else { + boolean breakLines = (options & DO_BREAK_LINES) > 0; + + //int len43 = len * 4 / 3; + //byte[] outBuff = new byte[ ( len43 ) // Main 4:3 + // + ( (len % 3) > 0 ? 4 : 0 ) // Account for padding + // + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines + // Try to determine more precisely how big the array needs to be. + // If we get it right, we don't have to do an array copy, and + // we save a bunch of memory. + int encLen = (len / 3) * 4 + (len % 3 > 0 ? 4 : 0); // Bytes needed for actual encoding + if (breakLines) { + encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters + } + byte[] outBuff = new byte[encLen]; + + + int d = 0; + int e = 0; + int len2 = len - 2; + int lineLength = 0; + for (; d < len2; d += 3, e += 4) { + encode3to4(source, d + off, 3, outBuff, e, options); + + lineLength += 4; + if (breakLines && lineLength >= MAX_LINE_LENGTH) { + outBuff[e + 4] = NEW_LINE; + e++; + lineLength = 0; + } // end if: end of line + } // en dfor: each piece of array + + if (d < len) { + encode3to4(source, d + off, len - d, outBuff, e, options); + e += 4; + } // end if: some padding needed + + + // Only resize array if we didn't guess it right. + if (e < outBuff.length - 1) { + byte[] finalOut = new byte[e]; + System.arraycopy(outBuff, 0, finalOut, 0, e); + //System.err.println("Having to resize array from " + outBuff.length + " to " + e ); + return finalOut; + } else { + //System.err.println("No need to resize array."); + return outBuff; + } + + } // end else: don't compress + + } // end encodeBytesToBytes + + + + + +/* ******** D E C O D I N G M E T H O D S ******** */ + + + /** + * Decodes four bytes from array source + * and writes the resulting bytes (up to three of them) + * to destination. + * The source and destination arrays can be manipulated + * anywhere along their length by specifying + * srcOffset and destOffset. + * This method does not check to make sure your arrays + * are large enough to accomodate srcOffset + 4 for + * the source array or destOffset + 3 for + * the destination array. + * This method returns the actual number of bytes that + * were converted from the Base64 encoding. + *

This is the lowest level of the decoding methods with + * all possible parameters.

+ * + * @param source the array to convert + * @param srcOffset the index where conversion begins + * @param destination the array to hold the conversion + * @param destOffset the index where output will be put + * @param options alphabet type is pulled from this (standard, url-safe, ordered) + * @return the number of decoded bytes converted + * @throws NullPointerException if source or destination arrays are null + * @throws IllegalArgumentException if srcOffset or destOffset are invalid + * or there is not enough room in the array. + * @since 1.3 + */ + private static int decode4to3( + byte[] source, int srcOffset, + byte[] destination, int destOffset, int options) { + + // Lots of error checking and exception throwing + if (source == null) { + throw new NullPointerException("Source array was null."); + } // end if + if (destination == null) { + throw new NullPointerException("Destination array was null."); + } // end if + if (srcOffset < 0 || srcOffset + 3 >= source.length) { + throw new IllegalArgumentException(String.format( + "Source array with length %d cannot have offset of %d and still process four bytes.", + source.length, + srcOffset)); + } // end if + if (destOffset < 0 || destOffset + 2 >= destination.length) { + throw new IllegalArgumentException(String.format( + "Destination array with length %d cannot have offset of %d and still store three bytes.", + destination.length, destOffset)); + } // end if + + + byte[] DECODABET = getDecodabet(options); + + // Example: Dk== + if (source[srcOffset + 2] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12); + + destination[destOffset] = (byte) (outBuff >>> 16); + return 1; + } + + // Example: DkL= + else if (source[srcOffset + 3] == EQUALS_SIGN) { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) + | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6); + + destination[destOffset] = (byte) (outBuff >>> 16); + destination[destOffset + 1] = (byte) (outBuff >>> 8); + return 2; + } + + // Example: DkLE + else { + // Two ways to do the same thing. Don't know which way I like best. + //int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 ) + // | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 ) + // | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 ) + // | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 ); + int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) + | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12) + | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) + | ((DECODABET[source[srcOffset + 3]] & 0xFF)); + + + destination[destOffset] = (byte) (outBuff >> 16); + destination[destOffset + 1] = (byte) (outBuff >> 8); + destination[destOffset + 2] = (byte) (outBuff); + + return 3; + } + } // end decodeToBytes + + + /** + * Low-level access to decoding ASCII characters in + * the form of a byte array. Ignores GUNZIP option, if + * it's set. This is not generally a recommended method, + * although it is used internally as part of the decoding process. + * Special case: if len = 0, an empty array is returned. Still, + * if you need more speed and reduced memory footprint (and aren't + * gzipping), consider this method. + * + * @param source The Base64 encoded data + * @return decoded data + * @since 2.3.1 + */ + public static byte[] decode(byte[] source) { + byte[] decoded = null; + try { + decoded = decode(source, 0, source.length, Base64.NO_OPTIONS); + } catch (java.io.IOException ex) { + assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage(); + } + return decoded; + } + + + /** + * Low-level access to decoding ASCII characters in + * the form of a byte array. Ignores GUNZIP option, if + * it's set. This is not generally a recommended method, + * although it is used internally as part of the decoding process. + * Special case: if len = 0, an empty array is returned. Still, + * if you need more speed and reduced memory footprint (and aren't + * gzipping), consider this method. + * + * @param source The Base64 encoded data + * @param off The offset of where to begin decoding + * @param len The length of characters to decode + * @param options Can specify options such as alphabet type to use + * @return decoded data + * @throws java.io.IOException If bogus characters exist in source data + * @since 1.3 + */ + public static byte[] decode(byte[] source, int off, int len, int options) + throws java.io.IOException { + + // Lots of error checking and exception throwing + if (source == null) { + throw new NullPointerException("Cannot decode null source array."); + } // end if + if (off < 0 || off + len > source.length) { + throw new IllegalArgumentException(String.format( + "Source array with length %d cannot have offset of %d and process %d bytes.", source.length, off, + len)); + } // end if + + if (len == 0) { + return new byte[0]; + } else if (len < 4) { + throw new IllegalArgumentException( + "Base64-encoded string must have at least four characters, but length specified was " + len); + } // end if + + byte[] DECODABET = getDecodabet(options); + + int len34 = len * 3 / 4; // Estimate on array size + byte[] outBuff = new byte[len34]; // Upper limit on size of output + int outBuffPosn = 0; // Keep track of where we're writing + + byte[] b4 = new byte[4]; // Four byte buffer from source, eliminating white space + int b4Posn = 0; // Keep track of four byte input buffer + int i = 0; // Source array counter + byte sbiCrop = 0; // Low seven bits (ASCII) of input + byte sbiDecode = 0; // Special value from DECODABET + + for (i = off; i < off + len; i++) { // Loop through source + + sbiCrop = (byte) (source[i] & 0x7f); // Only the low seven bits + sbiDecode = DECODABET[sbiCrop]; // Special value + + // White space, Equals sign, or legit Base64 character + // Note the values such as -5 and -9 in the + // DECODABETs at the top of the file. + if (sbiDecode >= WHITE_SPACE_ENC) { + if (sbiDecode >= EQUALS_SIGN_ENC) { + b4[b4Posn++] = sbiCrop; // Save non-whitespace + if (b4Posn > 3) { // Time to decode? + outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, options); + b4Posn = 0; + + // If that was the equals sign, break out of 'for' loop + if (sbiCrop == EQUALS_SIGN) { + break; + } // end if: equals sign + } // end if: quartet built + } // end if: equals sign or better + } // end if: white space, equals sign or better + else { + // There's a bad input character in the Base64 stream. + throw new java.io.IOException(String.format( + "Bad Base64 input character '%c' in array position %d", source[i], i)); + } // end else: + } // each input character + + byte[] out = new byte[outBuffPosn]; + System.arraycopy(outBuff, 0, out, 0, outBuffPosn); + return out; + } // end decode + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @return the decoded data + * @throws java.io.IOException If there is a problem + * @since 1.4 + */ + public static byte[] decode(String s) throws java.io.IOException { + return decode(s, NO_OPTIONS); + } + + + /** + * Decodes data from Base64 notation, automatically + * detecting gzip-compressed data and decompressing it. + * + * @param s the string to decode + * @param options encode options such as URL_SAFE + * @return the decoded data + * @throws java.io.IOException if there is an error + * @throws NullPointerException if s is null + * @since 1.4 + */ + public static byte[] decode(String s, int options) throws java.io.IOException { + + if (s == null) { + throw new NullPointerException("Input string was null."); + } // end if + + byte[] bytes; + try { + bytes = s.getBytes(PREFERRED_ENCODING); + } // end try + catch (java.io.UnsupportedEncodingException uee) { + bytes = s.getBytes(); + } // end catch + // + + // Decode + bytes = decode(bytes, 0, bytes.length, options); + + // Check to see if it's gzip-compressed + // GZIP Magic Two-Byte Number: 0x8b1f (35615) + boolean dontGunzip = (options & DONT_GUNZIP) != 0; + if ((bytes != null) && (bytes.length >= 4) && (!dontGunzip)) { + + int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00); + if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head) { + java.io.ByteArrayInputStream bais = null; + java.util.zip.GZIPInputStream gzis = null; + java.io.ByteArrayOutputStream baos = null; + byte[] buffer = new byte[2048]; + int length = 0; + + try { + baos = new java.io.ByteArrayOutputStream(); + bais = new java.io.ByteArrayInputStream(bytes); + gzis = new java.util.zip.GZIPInputStream(bais); + + while ((length = gzis.read(buffer)) >= 0) { + baos.write(buffer, 0, length); + } // end while: reading input + + // No error? Get new bytes. + bytes = baos.toByteArray(); + + } // end try + catch (java.io.IOException e) { + e.printStackTrace(); + // Just return originally-decoded bytes + } // end catch + finally { + try { + baos.close(); + } catch (Exception e) { + } + try { + gzis.close(); + } catch (Exception e) { + } + try { + bais.close(); + } catch (Exception e) { + } + } // end finally + + } // end if: gzipped + } // end if: bytes.length >= 2 + + return bytes; + } // end decode + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * + * @param encodedObject The Base64 data to decode + * @return The decoded and deserialized object + * @throws NullPointerException if encodedObject is null + * @throws java.io.IOException if there is a general error + * @throws ClassNotFoundException if the decoded object is of a + * class that cannot be found by the JVM + * @since 1.5 + */ + public static Object decodeToObject(String encodedObject) + throws java.io.IOException, java.lang.ClassNotFoundException { + return decodeToObject(encodedObject, NO_OPTIONS, null); + } + + + /** + * Attempts to decode Base64 data and deserialize a Java + * Object within. Returns null if there was an error. + * If loader is not null, it will be the class loader + * used when deserializing. + * + * @param encodedObject The Base64 data to decode + * @param options Various parameters related to decoding + * @param loader Optional class loader to use in deserializing classes. + * @return The decoded and deserialized object + * @throws NullPointerException if encodedObject is null + * @throws java.io.IOException if there is a general error + * @throws ClassNotFoundException if the decoded object is of a + * class that cannot be found by the JVM + * @since 2.3.4 + */ + public static Object decodeToObject( + String encodedObject, int options, final ClassLoader loader) + throws java.io.IOException, java.lang.ClassNotFoundException { + + // Decode and gunzip if necessary + byte[] objBytes = decode(encodedObject, options); + + java.io.ByteArrayInputStream bais = null; + java.io.ObjectInputStream ois = null; + Object obj = null; + + try { + bais = new java.io.ByteArrayInputStream(objBytes); + + // If no custom class loader is provided, use Java's builtin OIS. + if (loader == null) { + ois = new java.io.ObjectInputStream(bais); + } // end if: no loader provided + + // Else make a customized object input stream that uses + // the provided class loader. + else { + ois = new java.io.ObjectInputStream(bais) { + @Override + public Class resolveClass(java.io.ObjectStreamClass streamClass) + throws java.io.IOException, ClassNotFoundException { + Class c = Class.forName(streamClass.getName(), false, loader); + if (c == null) { + return super.resolveClass(streamClass); + } else { + return c; // Class loader knows of this class. + } // end else: not null + } // end resolveClass + }; // end ois + } // end else: no custom class loader + + obj = ois.readObject(); + } // end try + catch (java.io.IOException e) { + throw e; // Catch and throw in order to execute finally{} + } // end catch + catch (java.lang.ClassNotFoundException e) { + throw e; // Catch and throw in order to execute finally{} + } // end catch + finally { + try { + bais.close(); + } catch (Exception e) { + } + try { + ois.close(); + } catch (Exception e) { + } + } // end finally + + return obj; + } // end decodeObject + + + /** + * Convenience method for encoding data to a file. + *

+ *

As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param dataToEncode byte array of data to encode in base64 form + * @param filename Filename for saving encoded data + * @throws java.io.IOException if there is an error + * @throws NullPointerException if dataToEncode is null + * @since 2.1 + */ + public static void encodeToFile(byte[] dataToEncode, String filename) + throws java.io.IOException { + + if (dataToEncode == null) { + throw new NullPointerException("Data to encode was null."); + } // end iff + + Base64.OutputStream bos = null; + try { + bos = new Base64.OutputStream( + new java.io.FileOutputStream(filename), Base64.ENCODE); + bos.write(dataToEncode); + } // end try + catch (java.io.IOException e) { + throw e; // Catch and throw to execute finally{} block + } // end catch: java.io.IOException + finally { + try { + bos.close(); + } catch (Exception e) { + } + } // end finally + + } // end encodeToFile + + + /** + * Convenience method for decoding data to a file. + *

+ *

As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param dataToDecode Base64-encoded data as a string + * @param filename Filename for saving decoded data + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static void decodeToFile(String dataToDecode, String filename) + throws java.io.IOException { + + Base64.OutputStream bos = null; + try { + bos = new Base64.OutputStream( + new java.io.FileOutputStream(filename), Base64.DECODE); + bos.write(dataToDecode.getBytes(PREFERRED_ENCODING)); + } // end try + catch (java.io.IOException e) { + throw e; // Catch and throw to execute finally{} block + } // end catch: java.io.IOException + finally { + try { + bos.close(); + } catch (Exception e) { + } + } // end finally + + } // end decodeToFile + + + /** + * Convenience method for reading a base64-encoded + * file and decoding it. + *

+ *

As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param filename Filename for reading encoded data + * @return decoded byte array + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static byte[] decodeFromFile(String filename) + throws java.io.IOException { + + byte[] decodedData = null; + Base64.InputStream bis = null; + try { + // Set up some useful variables + java.io.File file = new java.io.File(filename); + byte[] buffer = null; + int length = 0; + int numBytes = 0; + + // Check for size of file + if (file.length() > Integer.MAX_VALUE) { + throw new java.io.IOException("File is too big for this convenience method (" + file.length() + " " + + "bytes)."); + } // end if: file too big for int index + buffer = new byte[(int) file.length()]; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream(file)), Base64.DECODE + ); + + // Read until done + while ((numBytes = bis.read(buffer, length, 4096)) >= 0) { + length += numBytes; + } // end while + + // Save in a variable to return + decodedData = new byte[length]; + System.arraycopy(buffer, 0, decodedData, 0, length); + + } // end try + catch (java.io.IOException e) { + throw e; // Catch and release to execute finally{} + } // end catch: java.io.IOException + finally { + try { + bis.close(); + } catch (Exception e) { + } + } // end finally + + return decodedData; + } // end decodeFromFile + + + /** + * Convenience method for reading a binary file + * and base64-encoding it. + *

+ *

As of v 2.3, if there is a error, + * the method will throw an java.io.IOException. This is new to v2.3! + * In earlier versions, it just returned false, but + * in retrospect that's a pretty poor way to handle it.

+ * + * @param filename Filename for reading binary data + * @return base64-encoded string + * @throws java.io.IOException if there is an error + * @since 2.1 + */ + public static String encodeFromFile(String filename) + throws java.io.IOException { + + String encodedData = null; + Base64.InputStream bis = null; + try { + // Set up some useful variables + java.io.File file = new java.io.File(filename); + byte[] buffer = new byte[Math.max((int) (file.length() * 1.4), 40)]; // Need max() for math on small files + // (v2.2.1) + int length = 0; + int numBytes = 0; + + // Open a stream + bis = new Base64.InputStream( + new java.io.BufferedInputStream( + new java.io.FileInputStream(file)), Base64.ENCODE + ); + + // Read until done + while ((numBytes = bis.read(buffer, length, 4096)) >= 0) { + length += numBytes; + } // end while + + // Save in a variable to return + encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING); + + } // end try + catch (java.io.IOException e) { + throw e; // Catch and release to execute finally{} + } // end catch: java.io.IOException + finally { + try { + bis.close(); + } catch (Exception e) { + } + } // end finally + + return encodedData; + } // end encodeFromFile + + /** + * Reads infile and encodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @throws java.io.IOException if there is an error + * @since 2.2 + */ + public static void encodeFileToFile(String infile, String outfile) + throws java.io.IOException { + + String encoded = Base64.encodeFromFile(infile); + java.io.OutputStream out = null; + try { + out = new java.io.BufferedOutputStream( + new java.io.FileOutputStream(outfile)); + out.write(encoded.getBytes("US-ASCII")); // Strict, 7-bit output. + } // end try + catch (java.io.IOException e) { + throw e; // Catch and release to execute finally{} + } // end catch + finally { + try { + out.close(); + } catch (Exception ex) { + } + } // end finally + } // end encodeFileToFile + + + /** + * Reads infile and decodes it to outfile. + * + * @param infile Input file + * @param outfile Output file + * @throws java.io.IOException if there is an error + * @since 2.2 + */ + public static void decodeFileToFile(String infile, String outfile) + throws java.io.IOException { + + byte[] decoded = Base64.decodeFromFile(infile); + java.io.OutputStream out = null; + try { + out = new java.io.BufferedOutputStream( + new java.io.FileOutputStream(outfile)); + out.write(decoded); + } // end try + catch (java.io.IOException e) { + throw e; // Catch and release to execute finally{} + } // end catch + finally { + try { + out.close(); + } catch (Exception ex) { + } + } // end finally + } // end decodeFileToFile + + + /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */ + + + /** + * A {@link Base64.InputStream} will read data from another + * java.io.InputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class InputStream extends java.io.FilterInputStream { + + private boolean encode; // Encoding or decoding + private int position; // Current position in the buffer + private byte[] buffer; // Small buffer holding converted data + private int bufferLength; // Length of buffer (3 or 4) + private int numSigBytes; // Number of meaningful bytes in the buffer + private int lineLength; + private boolean breakLines; // Break lines at less than 80 characters + private int options; // Record options used to create the stream. + private byte[] decodabet; // Local copies to avoid extra method calls + + + /** + * Constructs a {@link Base64.InputStream} in DECODE mode. + * + * @param in the java.io.InputStream from which to read data. + * @since 1.3 + */ + public InputStream(java.io.InputStream in) { + this(in, DECODE); + } // end constructor + + + /** + * Constructs a {@link Base64.InputStream} in + * either ENCODE or DECODE mode. + *

+ * Valid options:

+		 *   ENCODE or DECODE: Encode or Decode as data is read.
+		 *   DO_BREAK_LINES: break lines at 76 characters
+		 *     (only meaningful when encoding)
+		 * 
+ *

+ * Example: new Base64.InputStream( in, Base64.DECODE ) + * + * @param in the java.io.InputStream from which to read data. + * @param options Specified options + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DO_BREAK_LINES + * @since 2.0 + */ + public InputStream(java.io.InputStream in, int options) { + + super(in); + this.options = options; // Record for later + this.breakLines = (options & DO_BREAK_LINES) > 0; + this.encode = (options & ENCODE) > 0; + this.bufferLength = encode ? 4 : 3; + this.buffer = new byte[bufferLength]; + this.position = -1; + this.lineLength = 0; + this.decodabet = getDecodabet(options); + } // end constructor + + /** + * Reads enough of the input stream to convert + * to/from Base64 and returns the next byte. + * + * @return next byte + * @since 1.3 + */ + @Override + public int read() throws java.io.IOException { + + // Do we need to get data? + if (position < 0) { + if (encode) { + byte[] b3 = new byte[3]; + int numBinaryBytes = 0; + for (int i = 0; i < 3; i++) { + int b = in.read(); + + // If end of stream, b is -1. + if (b >= 0) { + b3[i] = (byte) b; + numBinaryBytes++; + } else { + break; // out of for loop + } // end else: end of stream + + } // end for: each needed input byte + + if (numBinaryBytes > 0) { + encode3to4(b3, 0, numBinaryBytes, buffer, 0, options); + position = 0; + numSigBytes = 4; + } // end if: got data + else { + return -1; // Must be end of stream + } // end else + } // end if: encoding + + // Else decoding + else { + byte[] b4 = new byte[4]; + int i = 0; + for (i = 0; i < 4; i++) { + // Read four "meaningful" bytes: + int b = 0; + do { + b = in.read(); + } + while (b >= 0 && decodabet[b & 0x7f] <= WHITE_SPACE_ENC); + + if (b < 0) { + break; // Reads a -1 if end of stream + } // end if: end of stream + + b4[i] = (byte) b; + } // end for: each needed input byte + + if (i == 4) { + numSigBytes = decode4to3(b4, 0, buffer, 0, options); + position = 0; + } // end if: got four characters + else if (i == 0) { + return -1; + } // end else if: also padded correctly + else { + // Must have broken out from above. + throw new java.io.IOException("Improperly padded Base64 input."); + } // end + + } // end else: decode + } // end else: get data + + // Got data? + if (position >= 0) { + // End of relevant data? + if ( /*!encode &&*/ position >= numSigBytes) { + return -1; + } // end if: got data + + if (encode && breakLines && lineLength >= MAX_LINE_LENGTH) { + lineLength = 0; + return '\n'; + } // end if + else { + lineLength++; // This isn't important when decoding + // but throwing an extra "if" seems + // just as wasteful. + + int b = buffer[position++]; + + if (position >= bufferLength) { + position = -1; + } // end if: end + + return b & 0xFF; // This is how you "cast" a byte that's + // intended to be unsigned. + } // end else + } // end if: position >= 0 + + // Else error + else { + throw new java.io.IOException("Error in Base64 code reading stream."); + } // end else + } // end read + + + /** + * Calls {@link #read()} repeatedly until the end of stream + * is reached or len bytes are read. + * Returns number of bytes read into array or -1 if + * end of stream is encountered. + * + * @param dest array to hold values + * @param off offset for array + * @param len max number of bytes to read into array + * @return bytes read into array or -1 if end of stream is encountered. + * @since 1.3 + */ + @Override + public int read(byte[] dest, int off, int len) + throws java.io.IOException { + int i; + int b; + for (i = 0; i < len; i++) { + b = read(); + + if (b >= 0) { + dest[off + i] = (byte) b; + } else if (i == 0) { + return -1; + } else { + break; // Out of 'for' loop + } // Out of 'for' loop + } // end for: each byte read + return i; + } // end read + + } // end inner class InputStream + + + + + + + /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */ + + + /** + * A {@link Base64.OutputStream} will write data to another + * java.io.OutputStream, given in the constructor, + * and encode/decode to/from Base64 notation on the fly. + * + * @see Base64 + * @since 1.3 + */ + public static class OutputStream extends java.io.FilterOutputStream { + + private boolean encode; + private int position; + private byte[] buffer; + private int bufferLength; + private int lineLength; + private boolean breakLines; + private byte[] b4; // Scratch used in a few places + private boolean suspendEncoding; + private int options; // Record for later + private byte[] decodabet; // Local copies to avoid extra method calls + + /** + * Constructs a {@link Base64.OutputStream} in ENCODE mode. + * + * @param out the java.io.OutputStream to which data will be written. + * @since 1.3 + */ + public OutputStream(java.io.OutputStream out) { + this(out, ENCODE); + } // end constructor + + + /** + * Constructs a {@link Base64.OutputStream} in + * either ENCODE or DECODE mode. + *

+ * Valid options:

+		 *   ENCODE or DECODE: Encode or Decode as data is read.
+		 *   DO_BREAK_LINES: don't break lines at 76 characters
+		 *     (only meaningful when encoding)
+		 * 
+ *

+ * Example: new Base64.OutputStream( out, Base64.ENCODE ) + * + * @param out the java.io.OutputStream to which data will be written. + * @param options Specified options. + * @see Base64#ENCODE + * @see Base64#DECODE + * @see Base64#DO_BREAK_LINES + * @since 1.3 + */ + public OutputStream(java.io.OutputStream out, int options) { + super(out); + this.breakLines = (options & DO_BREAK_LINES) != 0; + this.encode = (options & ENCODE) != 0; + this.bufferLength = encode ? 3 : 4; + this.buffer = new byte[bufferLength]; + this.position = 0; + this.lineLength = 0; + this.suspendEncoding = false; + this.b4 = new byte[4]; + this.options = options; + this.decodabet = getDecodabet(options); + } // end constructor + + + /** + * Writes the byte to the output stream after + * converting to/from Base64 notation. + * When encoding, bytes are buffered three + * at a time before the output stream actually + * gets a write() call. + * When decoding, bytes are buffered four + * at a time. + * + * @param theByte the byte to write + * @since 1.3 + */ + @Override + public void write(int theByte) + throws java.io.IOException { + // Encoding suspended? + if (suspendEncoding) { + this.out.write(theByte); + return; + } // end if: supsended + + // Encode? + if (encode) { + buffer[position++] = (byte) theByte; + if (position >= bufferLength) { // Enough to encode. + + this.out.write(encode3to4(b4, buffer, bufferLength, options)); + + lineLength += 4; + if (breakLines && lineLength >= MAX_LINE_LENGTH) { + this.out.write(NEW_LINE); + lineLength = 0; + } // end if: end of line + + position = 0; + } // end if: enough to output + } // end if: encoding + + // Else, Decoding + else { + // Meaningful Base64 character? + if (decodabet[theByte & 0x7f] > WHITE_SPACE_ENC) { + buffer[position++] = (byte) theByte; + if (position >= bufferLength) { // Enough to output. + + int len = Base64.decode4to3(buffer, 0, b4, 0, options); + out.write(b4, 0, len); + position = 0; + } // end if: enough to output + } // end if: meaningful base64 character + else if (decodabet[theByte & 0x7f] != WHITE_SPACE_ENC) { + throw new java.io.IOException("Invalid character in Base64 data."); + } // end else: not white space either + } // end else: decoding + } // end write + + + /** + * Calls {@link #write(int)} repeatedly until len + * bytes are written. + * + * @param theBytes array from which to read bytes + * @param off offset for array + * @param len max number of bytes to read into array + * @since 1.3 + */ + @Override + public void write(byte[] theBytes, int off, int len) + throws java.io.IOException { + // Encoding suspended? + if (suspendEncoding) { + this.out.write(theBytes, off, len); + return; + } // end if: supsended + + for (int i = 0; i < len; i++) { + write(theBytes[off + i]); + } // end for: each byte written + + } // end write + + + /** + * Method added by PHIL. [Thanks, PHIL. -Rob] + * This pads the buffer without closing the stream. + * + * @throws java.io.IOException if there's an error. + */ + public void flushBase64() throws java.io.IOException { + if (position > 0) { + if (encode) { + out.write(encode3to4(b4, buffer, position, options)); + position = 0; + } // end if: encoding + else { + throw new java.io.IOException("Base64 input not properly padded."); + } // end else: decoding + } // end if: buffer partially full + + } // end flush + + + /** + * Flushes and closes (I think, in the superclass) the stream. + * + * @since 1.3 + */ + @Override + public void close() throws java.io.IOException { + // 1. Ensure that pending characters are written + flushBase64(); + + // 2. Actually close the stream + // Base class both flushes and closes. + super.close(); + + buffer = null; + out = null; + } // end close + + + /** + * Suspends encoding of the stream. + * May be helpful if you need to embed a piece of + * base64-encoded data in a stream. + * + * @throws java.io.IOException if there's an error flushing + * @since 1.5.1 + */ + public void suspendEncoding() throws java.io.IOException { + flushBase64(); + this.suspendEncoding = true; + } // end suspendEncoding + + + /** + * Resumes encoding of the stream. + * May be helpful if you need to embed a piece of + * base64-encoded data in a stream. + * + * @since 1.5.1 + */ + public void resumeEncoding() { + this.suspendEncoding = false; + } // end resumeEncoding + + + } // end inner class OutputStream + + +} // end class Base64 diff --git a/src/org/xbmc/android/util/ClientFactory.java b/app/src/main/java/org/xbmc/android/util/ClientFactory.java similarity index 87% rename from src/org/xbmc/android/util/ClientFactory.java rename to app/src/main/java/org/xbmc/android/util/ClientFactory.java index fc6fc270..16c56bb4 100644 --- a/src/org/xbmc/android/util/ClientFactory.java +++ b/app/src/main/java/org/xbmc/android/util/ClientFactory.java @@ -1,300 +1,301 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.util; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IEventClient; -import org.xbmc.api.data.IInfoClient; -import org.xbmc.api.data.IMusicClient; -import org.xbmc.api.data.ITvShowClient; -import org.xbmc.api.data.IVideoClient; -import org.xbmc.api.info.SystemInfo; -import org.xbmc.api.object.Host; -import org.xbmc.eventclient.EventClient; -import org.xbmc.jsonrpc.JsonRpc; -import org.xbmc.httpapi.HttpApi; -import org.xbmc.httpapi.WifiStateException; - -import android.content.Context; -import android.util.Log; - -public abstract class ClientFactory { - - public static int XBMC_REV = -1; - - public static final int MIN_JSONRPC_REV = 27770; - public static final int MICROHTTPD_REV = 27770; - public static final int THUMB_TO_VFS_REV = 29743; - - public static final int API_TYPE_UNSET = 0; - public static final int API_TYPE_HTTPIAPI = 1; - public static final int API_TYPE_JSONRPC = 2; - - private static HttpApi sHttpClient; - private static JsonRpc sJsonClient; - private static EventClient sEventClient; - private static int sApiType = API_TYPE_JSONRPC; - - private static final String TAG = "ClientFactory"; - private static final String NAME = "Android XBMC Remote"; - - public static IInfoClient getInfoClient(INotifiableManager manager, Context context) throws WifiStateException { - assertWifiState(context); - probeQueryApiType(manager); - switch (sApiType) { - case API_TYPE_JSONRPC: - return createJsonClient(manager).info; - case API_TYPE_UNSET: - case API_TYPE_HTTPIAPI: - default: - return createHttpClient(manager).info; - } - } - - public static IControlClient getControlClient(INotifiableManager manager, Context context) throws WifiStateException { - assertWifiState(context); - probeQueryApiType(manager); - switch (sApiType) { - case API_TYPE_JSONRPC: - return createJsonClient(manager).control; - case API_TYPE_UNSET: - case API_TYPE_HTTPIAPI: - default: - return createHttpClient(manager).control; - } - } - - public static IVideoClient getVideoClient(INotifiableManager manager, Context context) throws WifiStateException { - assertWifiState(context); - probeQueryApiType(manager); - switch (sApiType) { - case API_TYPE_JSONRPC: - return createJsonClient(manager).video; - case API_TYPE_UNSET: - case API_TYPE_HTTPIAPI: - default: - return createHttpClient(manager).video; - } - } - - public static IMusicClient getMusicClient(INotifiableManager manager, Context context) throws WifiStateException { - assertWifiState(context); - probeQueryApiType(manager); - switch (sApiType) { - case API_TYPE_JSONRPC: - return createJsonClient(manager).music; - case API_TYPE_UNSET: - case API_TYPE_HTTPIAPI: - default: - return createHttpClient(manager).music; - } - } - - public static ITvShowClient getTvShowClient(INotifiableManager manager, Context context) throws WifiStateException { - assertWifiState(context); - probeQueryApiType(manager); - switch (sApiType) { - case API_TYPE_JSONRPC: - return createJsonClient(manager).shows; - case API_TYPE_UNSET: - case API_TYPE_HTTPIAPI: - default: - return createHttpClient(manager).shows; - } - } - - private static void assertWifiState(Context context) throws WifiStateException { - if (context != null && HostFactory.host != null && HostFactory.host.wifi_only){ - final int state = WifiHelper.getInstance(context).getWifiState(); - if (state != WifiHelper.WIFI_STATE_CONNECTED) { - throw new WifiStateException(state); - } - } - } - - public static IEventClient getEventClient(INotifiableManager manager) { - return createEventClient(manager); - } - - /** - * Resets the client so it has to re-read the settings and recreate the instance. - * @param host New host settings, can be null. - */ - public static void resetClient(Host host) { - //sApiType = API_TYPE_UNSET; - if (sHttpClient != null) { - sHttpClient.setHost(host); - } else if(sJsonClient != null){ - sJsonClient.setHost(host); - }else{ - Log.w(TAG, "Not updating http client's host because no instance is set yet."); - } - Log.i(TAG, "Resetting client to " + (host == null ? "" : host.addr)); - if (sEventClient != null) { - try { - if (host != null) { - InetAddress addr = Inet4Address.getByName(host.addr); - sEventClient.setHost(addr, host.esPort > 0 ? host.esPort : Host.DEFAULT_EVENTSERVER_PORT); - } else { - sEventClient.setHost(null, 0); - } - } catch (UnknownHostException e) { - Log.e(TAG, "Unknown host: " + (host == null ? "" : host.addr)); - } - } else { - Log.w(TAG, "Not updating event client's host because no instance is set yet."); - } - } - - /** - * Returns an instance of the HTTP Client. Instantiation takes place only - * once, otherwise the first instance is returned. - * - * @param manager Upper layer reference - * @return HTTP client - */ - private static HttpApi createHttpClient(final INotifiableManager manager) { - final Host host = HostFactory.host; - if (sHttpClient == null) { - if (host != null && !host.addr.equals("")){ - sHttpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); - } else { - sHttpClient = new HttpApi(null, -1); - } - // do some init stuff - (new Thread("Init-Connection") { - public void run() { - sHttpClient.control.setResponseFormat(manager); - } - }).start(); - } - return sHttpClient; - } - - /** - * Returns an instance of the JSON-RPC Client. Instantiation takes place only - * once, otherwise the first instance is returned. - * - * @param manager Upper layer reference - * @return JSON-RPC client - */ - private static JsonRpc createJsonClient(final INotifiableManager manager) { - final Host host = HostFactory.host; - if (sJsonClient == null) { - if (host != null && !host.addr.equals("")){ - sJsonClient = new JsonRpc(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); - } else { - sJsonClient = new JsonRpc(null, -1); - } - } - return sJsonClient; - } - - - /** - * Tries to find out which xbmc flavor and which API is running. - * @param manager Upper layer reference - */ - private static void probeQueryApiType(final INotifiableManager manager) { - - final Host host = HostFactory.host; - - if (sApiType != API_TYPE_UNSET) { - return; - } - - // try to get version string via http api - final HttpApi httpClient; - if (host != null && !host.addr.equals("")){ - httpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); - } else { - httpClient = new HttpApi(null, -1); - } - final String version = httpClient.info.getSystemInfo(manager, SystemInfo.SYSTEM_BUILD_VERSION); - Log.i(TAG, "VERSION = " + version); - - // 1. try to match xbmc's version - Pattern pattern = Pattern.compile("r\\d+"); - Matcher matcher = pattern.matcher(version); - if (matcher.find()) { - final int rev = Integer.parseInt(matcher.group().substring(1)); - Log.i(TAG, "Found XBMC at revision " + rev + "!"); - XBMC_REV = rev; - sApiType = rev >= MIN_JSONRPC_REV ? API_TYPE_JSONRPC : API_TYPE_HTTPIAPI; - } else { - // parse git version - pattern = Pattern.compile("Git.([a-f\\d]+)"); - matcher = pattern.matcher(version); - if (matcher.find()) { - final String commit = matcher.group(1); - Log.i(TAG, "Found XBMC at Git commit " + commit + "!"); - - // set to last revision where we used SVN - XBMC_REV = 35744; - sApiType = API_TYPE_JSONRPC; - } - - - // 2. try to match boxee's version - // 3. plex? duh. - - //sApiType = API_TYPE_UNSET; - } - } - - - /** - * Returns an instance of the Event Server Client. Instantiation takes - * place only once, otherwise the first instance is returned. - * - * @param manager Upper layer reference - * @return Client for XBMC's Event Server - */ - private static IEventClient createEventClient(final INotifiableManager manager) { - if (sEventClient == null) { - final Host host = HostFactory.host; - if (host != null) { - try { - final InetAddress addr = Inet4Address.getByName(host.addr); - sEventClient = new EventClient(addr, host.esPort > 0 ? host.esPort : Host.DEFAULT_EVENTSERVER_PORT, NAME); - Log.i(TAG, "EventClient created on " + addr); - } catch (UnknownHostException e) { - manager.onMessage("EventClient: Cannot parse address \"" + host.addr + "\"."); - Log.e(TAG, "EventClient: Cannot parse address \"" + host.addr + "\"."); - sEventClient = new EventClient(NAME); - } - } else { - manager.onMessage("EventClient: Failed to read host settings."); - Log.e(TAG, "EventClient: Failed to read host settings."); - sEventClient = new EventClient(NAME); - } - } - return sEventClient; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.util; + +import android.content.Context; +import android.util.Log; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IControlClient; +import org.xbmc.api.data.IEventClient; +import org.xbmc.api.data.IInfoClient; +import org.xbmc.api.data.IMusicClient; +import org.xbmc.api.data.ITvShowClient; +import org.xbmc.api.data.IVideoClient; +import org.xbmc.api.info.SystemInfo; +import org.xbmc.api.object.Host; +import org.xbmc.eventclient.EventClient; +import org.xbmc.httpapi.HttpApi; +import org.xbmc.httpapi.WifiStateException; +import org.xbmc.jsonrpc.JsonRpc; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class ClientFactory { + + public static final int MIN_JSONRPC_REV = 27770; + public static final int MICROHTTPD_REV = 27770; + public static final int THUMB_TO_VFS_REV = 29743; + public static final int API_TYPE_UNSET = 0; + public static final int API_TYPE_HTTPIAPI = 1; + public static final int API_TYPE_JSONRPC = 2; + private static int sApiType = API_TYPE_JSONRPC; + private static final String TAG = "ClientFactory"; + private static final String NAME = "Android XBMC Remote"; + public static int XBMC_REV = -1; + private static HttpApi sHttpClient; + private static JsonRpc sJsonClient; + private static EventClient sEventClient; + + public static IInfoClient getInfoClient(INotifiableManager manager, Context context) throws WifiStateException { + assertWifiState(context); + probeQueryApiType(manager); + switch (sApiType) { + case API_TYPE_JSONRPC: + return createJsonClient(manager).info; + case API_TYPE_UNSET: + case API_TYPE_HTTPIAPI: + default: + return createHttpClient(manager).info; + } + } + + public static IControlClient getControlClient(INotifiableManager manager, + Context context) throws WifiStateException { + assertWifiState(context); + probeQueryApiType(manager); + switch (sApiType) { + case API_TYPE_JSONRPC: + return createJsonClient(manager).control; + case API_TYPE_UNSET: + case API_TYPE_HTTPIAPI: + default: + return createHttpClient(manager).control; + } + } + + public static IVideoClient getVideoClient(INotifiableManager manager, Context context) throws WifiStateException { + assertWifiState(context); + probeQueryApiType(manager); + switch (sApiType) { + case API_TYPE_JSONRPC: + return createJsonClient(manager).video; + case API_TYPE_UNSET: + case API_TYPE_HTTPIAPI: + default: + return createHttpClient(manager).video; + } + } + + public static IMusicClient getMusicClient(INotifiableManager manager, Context context) throws WifiStateException { + assertWifiState(context); + probeQueryApiType(manager); + switch (sApiType) { + case API_TYPE_JSONRPC: + return createJsonClient(manager).music; + case API_TYPE_UNSET: + case API_TYPE_HTTPIAPI: + default: + return createHttpClient(manager).music; + } + } + + public static ITvShowClient getTvShowClient(INotifiableManager manager, + Context context) throws WifiStateException { + assertWifiState(context); + probeQueryApiType(manager); + switch (sApiType) { + case API_TYPE_JSONRPC: + return createJsonClient(manager).shows; + case API_TYPE_UNSET: + case API_TYPE_HTTPIAPI: + default: + return createHttpClient(manager).shows; + } + } + + private static void assertWifiState(Context context) throws WifiStateException { + if (context != null && HostFactory.host != null && HostFactory.host.wifi_only) { + final int state = WifiHelper.getInstance(context).getWifiState(); + if (state != WifiHelper.WIFI_STATE_CONNECTED) { + throw new WifiStateException(state); + } + } + } + + public static IEventClient getEventClient(INotifiableManager manager) { + return createEventClient(manager); + } + + /** + * Resets the client so it has to re-read the settings and recreate the instance. + * + * @param host New host settings, can be null. + */ + public static void resetClient(Host host) { + //sApiType = API_TYPE_UNSET; + if (sHttpClient != null) { + sHttpClient.setHost(host); + } else if (sJsonClient != null) { + sJsonClient.setHost(host); + } else { + Log.w(TAG, "Not updating http client's host because no instance is set yet."); + } + Log.i(TAG, "Resetting client to " + (host == null ? "" : host.addr)); + if (sEventClient != null) { + try { + if (host != null) { + InetAddress addr = Inet4Address.getByName(host.addr); + sEventClient.setHost(addr, host.esPort > 0 ? host.esPort : Host.DEFAULT_EVENTSERVER_PORT); + } else { + sEventClient.setHost(null, 0); + } + } catch (UnknownHostException e) { + Log.e(TAG, "Unknown host: " + (host == null ? "" : host.addr)); + } + } else { + Log.w(TAG, "Not updating event client's host because no instance is set yet."); + } + } + + /** + * Returns an instance of the HTTP Client. Instantiation takes place only + * once, otherwise the first instance is returned. + * + * @param manager Upper layer reference + * @return HTTP client + */ + private static HttpApi createHttpClient(final INotifiableManager manager) { + final Host host = HostFactory.host; + if (sHttpClient == null) { + if (host != null && !host.addr.equals("")) { + sHttpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); + } else { + sHttpClient = new HttpApi(null, -1); + } + // do some init stuff + (new Thread("Init-Connection") { + public void run() { + sHttpClient.control.setResponseFormat(manager); + } + }).start(); + } + return sHttpClient; + } + + /** + * Returns an instance of the JSON-RPC Client. Instantiation takes place only + * once, otherwise the first instance is returned. + * + * @param manager Upper layer reference + * @return JSON-RPC client + */ + private static JsonRpc createJsonClient(final INotifiableManager manager) { + final Host host = HostFactory.host; + if (sJsonClient == null) { + if (host != null && !host.addr.equals("")) { + sJsonClient = new JsonRpc(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); + } else { + sJsonClient = new JsonRpc(null, -1); + } + } + return sJsonClient; + } + + + /** + * Tries to find out which xbmc flavor and which API is running. + * + * @param manager Upper layer reference + */ + private static void probeQueryApiType(final INotifiableManager manager) { + + final Host host = HostFactory.host; + + if (sApiType != API_TYPE_UNSET) { + return; + } + + // try to get version string via http api + final HttpApi httpClient; + if (host != null && !host.addr.equals("")) { + httpClient = new HttpApi(host, host.timeout >= 0 ? host.timeout : Host.DEFAULT_TIMEOUT); + } else { + httpClient = new HttpApi(null, -1); + } + final String version = httpClient.info.getSystemInfo(manager, SystemInfo.SYSTEM_BUILD_VERSION); + Log.i(TAG, "VERSION = " + version); + + // 1. try to match xbmc's version + Pattern pattern = Pattern.compile("r\\d+"); + Matcher matcher = pattern.matcher(version); + if (matcher.find()) { + final int rev = Integer.parseInt(matcher.group().substring(1)); + Log.i(TAG, "Found XBMC at revision " + rev + "!"); + XBMC_REV = rev; + sApiType = rev >= MIN_JSONRPC_REV ? API_TYPE_JSONRPC : API_TYPE_HTTPIAPI; + } else { + // parse git version + pattern = Pattern.compile("Git.([a-f\\d]+)"); + matcher = pattern.matcher(version); + if (matcher.find()) { + final String commit = matcher.group(1); + Log.i(TAG, "Found XBMC at Git commit " + commit + "!"); + + // set to last revision where we used SVN + XBMC_REV = 35744; + sApiType = API_TYPE_JSONRPC; + } + + + // 2. try to match boxee's version + // 3. plex? duh. + + //sApiType = API_TYPE_UNSET; + } + } + + + /** + * Returns an instance of the Event Server Client. Instantiation takes + * place only once, otherwise the first instance is returned. + * + * @param manager Upper layer reference + * @return Client for XBMC's Event Server + */ + private static IEventClient createEventClient(final INotifiableManager manager) { + if (sEventClient == null) { + final Host host = HostFactory.host; + if (host != null) { + try { + final InetAddress addr = Inet4Address.getByName(host.addr); + sEventClient = new EventClient(addr, host.esPort > 0 ? host.esPort : Host + .DEFAULT_EVENTSERVER_PORT, NAME); + Log.i(TAG, "EventClient created on " + addr); + } catch (UnknownHostException e) { + manager.onMessage("EventClient: Cannot parse address \"" + host.addr + "\"."); + Log.e(TAG, "EventClient: Cannot parse address \"" + host.addr + "\"."); + sEventClient = new EventClient(NAME); + } + } else { + manager.onMessage("EventClient: Failed to read host settings."); + Log.e(TAG, "EventClient: Failed to read host settings."); + sEventClient = new EventClient(NAME); + } + } + return sEventClient; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/util/ConnectionFactory.java b/app/src/main/java/org/xbmc/android/util/ConnectionFactory.java similarity index 57% rename from src/org/xbmc/android/util/ConnectionFactory.java rename to app/src/main/java/org/xbmc/android/util/ConnectionFactory.java index e3ea4e95..5238b04d 100644 --- a/src/org/xbmc/android/util/ConnectionFactory.java +++ b/app/src/main/java/org/xbmc/android/util/ConnectionFactory.java @@ -21,154 +21,155 @@ package org.xbmc.android.util; -import org.xbmc.android.remote.business.NowPlayingPollerThread; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Handler; +import org.xbmc.android.remote.business.NowPlayingPollerThread; + /** - * Globally returns the control objects. - * + * Globally returns the control objects. + *

* This class will soon retire once the event client is properly moved to the * data layer */ public class ConnectionFactory { - -// private static Collection sServiceInfo = new HashSet(); + + // private static Collection sServiceInfo = new HashSet(); private static volatile NowPlayingPollerThread sNowPlayingPoller; - + /** * Performs zeroconf lookup for the hostname and XBMC's services. * Stores a static collection of all previously looked up services, * and returns from that cache if it exists. - * + * * @param type The zeroconf connection type * @param host The hostname to lookup * @return {@link ServiceInfo} The details of the first matching host * public static ServiceInfo getZeroconfServiceInfo(String type, String host) { - - // Zeroconf addresses always end with .local. - // So, if it ends just with ".local", add a period to it. - if (host.endsWith(".local")) { - host = host.concat("."); - } - // If it doesn't have the ".local" suffix at all, add it, - // assuming the user typed just the hostname. - if (!host.endsWith(".local.")) { - host = host.concat("local."); - } + // Zeroconf addresses always end with .local. + // So, if it ends just with ".local", add a period to it. + if (host.endsWith(".local")) { + host = host.concat("."); + } - // See if we already looked that specific service and type up - if (!sServiceInfo.isEmpty()) { - for (ServiceInfo si: sServiceInfo) { - if (si.getType() == type && - si.getServer().compareToIgnoreCase(host) == 0) { - return si; - } - } - } + // If it doesn't have the ".local" suffix at all, add it, + // assuming the user typed just the hostname. + if (!host.endsWith(".local.")) { + host = host.concat("local."); + } - // If this is the first lookup, try to find something that matches\ - // the query, and save it in the collection for future use. - ServiceInfo hostInfo = null; - try { - JmDNS jmdns = JmDNS.create(); - int iAttempt = 0; - - while (hostInfo == null && iAttempt < 60) { - ServiceInfo[] infos = jmdns.list(type); - for (int i=0; i < infos.length; i++) { - if (infos[i].getServer().compareToIgnoreCase(host) == 0) { - hostInfo = infos[i]; - break; - } - } - - if (hostInfo == null) { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - Log.e("ConnectionManager", Log.getStackTraceString(e)); - break; - } - iAttempt++; - } - } - } catch (IOException e) { - //e.printStackTrace(); - Log.e("ConnectionManager", Log.getStackTraceString(e)); - } + // See if we already looked that specific service and type up + if (!sServiceInfo.isEmpty()) { + for (ServiceInfo si: sServiceInfo) { + if (si.getType() == type && + si.getServer().compareToIgnoreCase(host) == 0) { + return si; + } + } + } - // Add the host information to the collection, for future reference - sServiceInfo.add(hostInfo); - return hostInfo; + // If this is the first lookup, try to find something that matches\ + // the query, and save it in the collection for future use. + ServiceInfo hostInfo = null; + try { + JmDNS jmdns = JmDNS.create(); + int iAttempt = 0; + + while (hostInfo == null && iAttempt < 60) { + ServiceInfo[] infos = jmdns.list(type); + for (int i=0; i < infos.length; i++) { + if (infos[i].getServer().compareToIgnoreCase(host) == 0) { + hostInfo = infos[i]; + break; + } + } + + if (hostInfo == null) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + Log.e("ConnectionManager", Log.getStackTraceString(e)); + break; + } + iAttempt++; + } + } + } catch (IOException e) { + //e.printStackTrace(); + Log.e("ConnectionManager", Log.getStackTraceString(e)); + } + + // Add the host information to the collection, for future reference + sServiceInfo.add(hostInfo); + return hostInfo; }*/ - + /** * Returns an instance of the NowPlaying Poller . Instantiation takes place only - * once, otherwise the first instance is returned. - * + * once, otherwise the first instance is returned. + *

* Doesnt start the thread - * + * * @param context - * @param mNowPlayingHandler handler which is going to be registered * @return A reference to the NowPlaying Poller */ - + public static synchronized NowPlayingPollerThread getNowPlayingPoller(Context context) { if (sNowPlayingPoller == null) { sNowPlayingPoller = new NowPlayingPollerThread(context); } - if (!sNowPlayingPoller.isAlive()){ + if (!sNowPlayingPoller.isAlive()) { sNowPlayingPoller = new NowPlayingPollerThread(context); } - + return sNowPlayingPoller; - + } - - public static synchronized NowPlayingPollerThread subscribeNowPlayingPollerThread(Context context, - Handler mNowPlayingHandler) { - + + public static synchronized NowPlayingPollerThread subscribeNowPlayingPollerThread(Context context, + Handler mNowPlayingHandler) { + if (sNowPlayingPoller == null) { sNowPlayingPoller = new NowPlayingPollerThread(context); sNowPlayingPoller.subscribe(mNowPlayingHandler); sNowPlayingPoller.start(); } else { } - if (!sNowPlayingPoller.isAlive()){ + if (!sNowPlayingPoller.isAlive()) { sNowPlayingPoller = new NowPlayingPollerThread(context); sNowPlayingPoller.subscribe(mNowPlayingHandler); - sNowPlayingPoller.start(); + sNowPlayingPoller.start(); } else { sNowPlayingPoller.subscribe(mNowPlayingHandler); } - + return sNowPlayingPoller; - + } - + public static synchronized NowPlayingPollerThread unSubscribeNowPlayingPollerThread(Context context, - Handler mNowPlayingHandler, boolean stop) { - if (sNowPlayingPoller != null){ - sNowPlayingPoller.unSubscribe(mNowPlayingHandler); - } + Handler mNowPlayingHandler, + boolean stop) { + if (sNowPlayingPoller != null) { + sNowPlayingPoller.unSubscribe(mNowPlayingHandler); + } return sNowPlayingPoller; - + } - - + + /** * Checks whether the device is able to connect to the network + * * @param context * @return */ public static boolean isNetworkAvailable(Context context) { - ConnectivityManager connMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = connMgr.getActiveNetworkInfo(); return info != null && info.isConnected(); } diff --git a/src/org/xbmc/android/util/Crc32.java b/app/src/main/java/org/xbmc/android/util/Crc32.java similarity index 85% rename from src/org/xbmc/android/util/Crc32.java rename to app/src/main/java/org/xbmc/android/util/Crc32.java index 8e628527..66acb8ba 100644 --- a/src/org/xbmc/android/util/Crc32.java +++ b/app/src/main/java/org/xbmc/android/util/Crc32.java @@ -1,86 +1,87 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.util; - -import java.io.UnsupportedEncodingException; - -/** - * This is basically a transcript from XBMC's Crc32.cpp. It avoids having to - * query for thumb names by the HTTP API. - * - * @author freezy - */ -public class Crc32 { - - public static int compute(byte[] buffer, int crc) { - int count = buffer.length; - while (count-- > 0) { - crc = compute(buffer[buffer.length - count - 1], crc); - } - return crc; - } - - public static int compute(byte value, int crc) { - crc ^= (value << 24); - for (int i = 0; i < 8; i++) { - if ((crc & 0x80000000) != 0) { - crc = (crc << 1) ^ 0x04C11DB7; - } else { - crc <<= 1; - } - } - return crc; - } - - public static int compute(String strValue) { - try { - return compute(strValue.getBytes("UTF-8"), 0xFFFFFFFF); - } catch (UnsupportedEncodingException e) { - return compute(strValue.getBytes(), 0xFFFFFFFF); - } - } - - public static String computeAsHex(String strValue) { - return String.format("%08x", compute(strValue)); - } - - public static String computeAsHexLowerCase(String strValue) { - return String.format("%08x", compute(toXbmcLowerCase(strValue))); - } - - public static String formatAsHexLowerCase(long crc) { - return String.format("%08x", (int)crc).toLowerCase(); - } - - public static int computeLowerCase(String strValue) { - return compute(toXbmcLowerCase(strValue)); - } - private static String toXbmcLowerCase(String strValue) { - char chars[] = strValue.toCharArray(); - for(int i = 0; i < chars.length; i++){ - if(chars[i] >= 65 && chars[i] <= 90) - chars[i] = Character.toLowerCase(chars[i]); - } - return new String(chars); - } - -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.util; + +import java.io.UnsupportedEncodingException; + +/** + * This is basically a transcript from XBMC's Crc32.cpp. It avoids having to + * query for thumb names by the HTTP API. + * + * @author freezy + */ +public class Crc32 { + + public static int compute(byte[] buffer, int crc) { + int count = buffer.length; + while (count-- > 0) { + crc = compute(buffer[buffer.length - count - 1], crc); + } + return crc; + } + + public static int compute(byte value, int crc) { + crc ^= (value << 24); + for (int i = 0; i < 8; i++) { + if ((crc & 0x80000000) != 0) { + crc = (crc << 1) ^ 0x04C11DB7; + } else { + crc <<= 1; + } + } + return crc; + } + + public static int compute(String strValue) { + try { + return compute(strValue.getBytes("UTF-8"), 0xFFFFFFFF); + } catch (UnsupportedEncodingException e) { + return compute(strValue.getBytes(), 0xFFFFFFFF); + } + } + + public static String computeAsHex(String strValue) { + return String.format("%08x", compute(strValue)); + } + + public static String computeAsHexLowerCase(String strValue) { + return String.format("%08x", compute(toXbmcLowerCase(strValue))); + } + + public static String formatAsHexLowerCase(long crc) { + return String.format("%08x", (int) crc).toLowerCase(); + } + + public static int computeLowerCase(String strValue) { + return compute(toXbmcLowerCase(strValue)); + } + + private static String toXbmcLowerCase(String strValue) { + char chars[] = strValue.toCharArray(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] >= 65 && chars[i] <= 90) + chars[i] = Character.toLowerCase(chars[i]); + } + return new String(chars); + } + +} diff --git a/src/org/xbmc/android/util/HostFactory.java b/app/src/main/java/org/xbmc/android/util/HostFactory.java similarity index 88% rename from src/org/xbmc/android/util/HostFactory.java rename to app/src/main/java/org/xbmc/android/util/HostFactory.java index aca96bac..1c908bb5 100644 --- a/src/org/xbmc/android/util/HostFactory.java +++ b/app/src/main/java/org/xbmc/android/util/HostFactory.java @@ -1,280 +1,286 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.util; - -import java.util.ArrayList; - -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; -import org.xbmc.android.remote.business.provider.HostProvider; -import org.xbmc.android.remote.business.provider.HostProvider.Hosts; -import org.xbmc.api.object.Host; - -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.preference.PreferenceManager; -import android.util.Log; - -/** - * Helper class that keeps - * a) a reference to the currently used host - * b) all the code between the provider and the settings stuff - * - * @author Team XBMC - */ -public abstract class HostFactory { - - /** - * The currently used host - */ - public static Host host = null; - - /** - * The setting that remembers which host has been used last - */ - public static final String SETTING_HOST_ID = "setting_host_id"; - public static final String TAG = "HostFactory"; - - /** - * Returns all hosts - * @param activity Reference to activity - * @return List of all hosts - */ - public static ArrayList getHosts(Context context) { - Cursor cur = context.getContentResolver().query(HostProvider.Hosts.CONTENT_URI, - null, // All - null, // Which rows to return (all rows) - null, // Selection arguments (none) - HostProvider.Hosts.NAME + " ASC"); // Put the results in ascending order by name - ArrayList hosts = new ArrayList(); - try { - if (cur.moveToFirst()) { - final int idCol = cur.getColumnIndex(HostProvider.Hosts._ID); - final int nameCol = cur.getColumnIndex(HostProvider.Hosts.NAME); - final int hostCol = cur.getColumnIndex(HostProvider.Hosts.ADDR); - final int portCol = cur.getColumnIndex(HostProvider.Hosts.PORT); - final int userCol = cur.getColumnIndex(HostProvider.Hosts.USER); - final int passCol = cur.getColumnIndex(HostProvider.Hosts.PASS); - final int esPortCol = cur.getColumnIndex(HostProvider.Hosts.ESPORT); - final int timeoutCol = cur.getColumnIndex(HostProvider.Hosts.TIMEOUT); - final int wifiOnlyCol = cur.getColumnIndex(HostProvider.Hosts.WIFI_ONLY); - final int accessPointCol = cur.getColumnIndex(HostProvider.Hosts.ACCESS_POINT); - final int macAddrCol = cur.getColumnIndex(HostProvider.Hosts.MAC_ADDR); - final int wolPortCol = cur.getColumnIndex(HostProvider.Hosts.WOL_PORT); - final int wolWaitCol = cur.getColumnIndex(HostProvider.Hosts.WOL_WAIT); - do { - final Host host = new Host(); - host.id = cur.getInt(idCol); - host.name = cur.getString(nameCol); - host.addr = cur.getString(hostCol); - host.port = cur.getInt(portCol); - host.user = cur.getString(userCol); - host.pass = cur.getString(passCol); - host.esPort = cur.getInt(esPortCol); - host.timeout = cur.getInt(timeoutCol); - host.access_point = cur.getString(accessPointCol); - host.mac_addr = cur.getString(macAddrCol); - host.wifi_only = cur.getInt(wifiOnlyCol)==1; //stored as 1 = true and 0 = false in sqlite - host.wol_port = cur.getInt(wolPortCol); - host.wol_wait = cur.getInt(wolWaitCol); - hosts.add(host); - } while (cur.moveToNext()); - } - } finally { - cur.close(); - } - return hosts; - } - - /** - * Parses a JSON-formatted string into a Host object. - * - * @param str a JSON string - * @return a Host object that represents str, or null if an error occurred - */ - public static Host getHostFromJson(String str) { - try { - JSONObject json = (JSONObject) new JSONTokener(str).nextValue(); - Host host = new Host(); - host.name = json.getString("name"); - host.addr = json.getString("addr"); - host.port = json.getInt("port"); - host.user = json.getString("user"); - host.pass = json.getString("pass"); - host.esPort = json.getInt("esPort"); - host.timeout = json.getInt("timeout"); - host.wifi_only = json.getBoolean("wifi_only"); - host.access_point = json.getString("access_point"); - host.mac_addr = json.getString("mac_addr"); - host.wol_wait = json.getInt("wol_wait"); - host.wol_port = json.getInt("wol_port"); - return host; - } - catch (JSONException e) { - Log.e(TAG, "Error in parseJson", e); - return null; - } - } - - /** - * Adds a host to the database. - * @param context Reference to context - * @param host Host to add - */ - public static void addHost(Context context, Host host) { - ContentValues values = new ContentValues(); - values.put(HostProvider.Hosts.NAME, host.name); - values.put(HostProvider.Hosts.ADDR, host.addr); - values.put(HostProvider.Hosts.PORT, host.port); - values.put(HostProvider.Hosts.USER, host.user); - values.put(HostProvider.Hosts.PASS, host.pass); - values.put(HostProvider.Hosts.ESPORT, host.esPort); - values.put(HostProvider.Hosts.TIMEOUT, host.timeout); - values.put(HostProvider.Hosts.WIFI_ONLY, host.wifi_only?1:0); - values.put(HostProvider.Hosts.MAC_ADDR, host.mac_addr); - values.put(HostProvider.Hosts.ACCESS_POINT, host.access_point); - values.put(HostProvider.Hosts.WOL_PORT, host.wol_port); - values.put(HostProvider.Hosts.WOL_WAIT, host.wol_wait); - context.getContentResolver().insert(HostProvider.Hosts.CONTENT_URI, values); - } - - /** - * Updates a host - * @param context Reference to context - * @param host Host to update - */ - public static void updateHost(Context context, Host host) { - ContentValues values = new ContentValues(); - values.put(HostProvider.Hosts.NAME, host.name); - values.put(HostProvider.Hosts.ADDR, host.addr); - values.put(HostProvider.Hosts.PORT, host.port); - values.put(HostProvider.Hosts.USER, host.user); - values.put(HostProvider.Hosts.PASS, host.pass); - values.put(HostProvider.Hosts.ESPORT, host.esPort); - values.put(HostProvider.Hosts.TIMEOUT, host.timeout); - values.put(HostProvider.Hosts.WIFI_ONLY, host.wifi_only?1:0); - values.put(HostProvider.Hosts.MAC_ADDR, host.mac_addr); - values.put(HostProvider.Hosts.ACCESS_POINT, host.access_point); - values.put(HostProvider.Hosts.WOL_PORT, host.wol_port); - values.put(HostProvider.Hosts.WOL_WAIT, host.wol_wait); - context.getContentResolver().update(HostProvider.Hosts.CONTENT_URI, values, HostProvider.Hosts._ID + "=" + host.id, null); - } - - /** - * Deletes a host. - * @param activity Reference to activity - * @param host Host to delete - * @return - */ - public static void deleteHost(Context context, Host host) { - Uri hostUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, host.id); - context.getContentResolver().delete(hostUri, null, null); - } - - /** - * Saves the host to the preference file. - * @param context - * @param addr - */ - public static void saveHost(Context context, Host h) { - SharedPreferences.Editor ed = PreferenceManager.getDefaultSharedPreferences(context).edit(); - if (h != null) { - ed.putInt(SETTING_HOST_ID, h.id); - } else { - ed.putInt(SETTING_HOST_ID, 0); - } - ed.commit(); - host = h; - ClientFactory.resetClient(h); - } - - /** - * Reads the preferences and returns the currently set host. If there is no - * preference set, return the first host. If there is no host set, return - * null. - * @param activity Reference to current activity - * @return Current host - */ - public static void readHost(Context context) { - int hostId = PreferenceManager.getDefaultSharedPreferences(context).getInt(SETTING_HOST_ID, -1); - if (hostId < 0) { - host = getHost(context); - } else { - host = getHost(context, hostId); - } - Log.i(TAG, "XBMC Host = " + (host == null ? "[host=null]" : host.addr)); - } - - /** - * Returns a host based on its database ID. - * @param activity Reference to activity - * @param id Host database ID - * @return - */ - private static Host getHost(Context context, int id) { - Uri hostUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, id); - Cursor cur = context.getContentResolver().query(hostUri, null, null, null, null); - try { - if (cur.moveToFirst()) { - final Host host = new Host(); - host.id = cur.getInt(cur.getColumnIndex(HostProvider.Hosts._ID)); - host.name = cur.getString(cur.getColumnIndex(HostProvider.Hosts.NAME)); - host.addr = cur.getString(cur.getColumnIndex(HostProvider.Hosts.ADDR)); - host.port = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.PORT)); - host.user = cur.getString(cur.getColumnIndex(HostProvider.Hosts.USER)); - host.pass = cur.getString(cur.getColumnIndex(HostProvider.Hosts.PASS)); - host.esPort = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.ESPORT)); - host.timeout = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.TIMEOUT)); - host.wifi_only = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WIFI_ONLY))==1; - host.access_point = cur.getString(cur.getColumnIndex(HostProvider.Hosts.ACCESS_POINT)); - host.mac_addr = cur.getString(cur.getColumnIndex(HostProvider.Hosts.MAC_ADDR)); - host.wol_port = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WOL_PORT)); - host.wol_wait = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WOL_WAIT)); - return host; - } - } finally { - cur.close(); - } - return null; - } - - /** - * Returns the first host found. This is useful if hosts are defined but - * the settings have been erased and need to be reset to a host. If nothing - * found, return null. - * @param activity Reference to activity - * @return First host found or null if hosts table empty. - */ - private static Host getHost(Context context) { - ArrayList hosts = getHosts(context); - if (hosts.size() > 0) { - return hosts.get(0); - } else { - return null; - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.util; + +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.preference.PreferenceManager; +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONTokener; +import org.xbmc.android.remote.business.provider.HostProvider; +import org.xbmc.android.remote.business.provider.HostProvider.Hosts; +import org.xbmc.api.object.Host; + +import java.util.ArrayList; + +/** + * Helper class that keeps + * a) a reference to the currently used host + * b) all the code between the provider and the settings stuff + * + * @author Team XBMC + */ +public abstract class HostFactory { + + /** + * The setting that remembers which host has been used last + */ + public static final String SETTING_HOST_ID = "setting_host_id"; + public static final String TAG = "HostFactory"; + /** + * The currently used host + */ + public static Host host = null; + + /** + * Returns all hosts + * + * @param context Reference to activity + * @return List of all hosts + */ + public static ArrayList getHosts(Context context) { + Cursor cur = context.getContentResolver().query(HostProvider.Hosts.CONTENT_URI, + null, // All + null, // Which rows to return (all rows) + null, // Selection arguments (none) + HostProvider.Hosts.NAME + " ASC"); // Put the results in ascending order by name + ArrayList hosts = new ArrayList(); + try { + if (cur.moveToFirst()) { + final int idCol = cur.getColumnIndex(HostProvider.Hosts._ID); + final int nameCol = cur.getColumnIndex(HostProvider.Hosts.NAME); + final int hostCol = cur.getColumnIndex(HostProvider.Hosts.ADDR); + final int portCol = cur.getColumnIndex(HostProvider.Hosts.PORT); + final int userCol = cur.getColumnIndex(HostProvider.Hosts.USER); + final int passCol = cur.getColumnIndex(HostProvider.Hosts.PASS); + final int esPortCol = cur.getColumnIndex(HostProvider.Hosts.ESPORT); + final int timeoutCol = cur.getColumnIndex(HostProvider.Hosts.TIMEOUT); + final int wifiOnlyCol = cur.getColumnIndex(HostProvider.Hosts.WIFI_ONLY); + final int accessPointCol = cur.getColumnIndex(HostProvider.Hosts.ACCESS_POINT); + final int macAddrCol = cur.getColumnIndex(HostProvider.Hosts.MAC_ADDR); + final int wolPortCol = cur.getColumnIndex(HostProvider.Hosts.WOL_PORT); + final int wolWaitCol = cur.getColumnIndex(HostProvider.Hosts.WOL_WAIT); + do { + final Host host = new Host(); + host.id = cur.getInt(idCol); + host.name = cur.getString(nameCol); + host.addr = cur.getString(hostCol); + host.port = cur.getInt(portCol); + host.user = cur.getString(userCol); + host.pass = cur.getString(passCol); + host.esPort = cur.getInt(esPortCol); + host.timeout = cur.getInt(timeoutCol); + host.access_point = cur.getString(accessPointCol); + host.mac_addr = cur.getString(macAddrCol); + host.wifi_only = cur.getInt(wifiOnlyCol) == 1; //stored as 1 = true and 0 = false in sqlite + host.wol_port = cur.getInt(wolPortCol); + host.wol_wait = cur.getInt(wolWaitCol); + hosts.add(host); + } while (cur.moveToNext()); + } + } finally { + cur.close(); + } + return hosts; + } + + /** + * Parses a JSON-formatted string into a Host object. + * + * @param str a JSON string + * @return a Host object that represents str, or null if an error occurred + */ + public static Host getHostFromJson(String str) { + try { + JSONObject json = (JSONObject) new JSONTokener(str).nextValue(); + Host host = new Host(); + host.name = json.getString("name"); + host.addr = json.getString("addr"); + host.port = json.getInt("port"); + host.user = json.getString("user"); + host.pass = json.getString("pass"); + host.esPort = json.getInt("esPort"); + host.timeout = json.getInt("timeout"); + host.wifi_only = json.getBoolean("wifi_only"); + host.access_point = json.getString("access_point"); + host.mac_addr = json.getString("mac_addr"); + host.wol_wait = json.getInt("wol_wait"); + host.wol_port = json.getInt("wol_port"); + return host; + } catch (JSONException e) { + Log.e(TAG, "Error in parseJson", e); + return null; + } + } + + /** + * Adds a host to the database. + * + * @param context Reference to context + * @param host Host to add + */ + public static void addHost(Context context, Host host) { + ContentValues values = new ContentValues(); + values.put(HostProvider.Hosts.NAME, host.name); + values.put(HostProvider.Hosts.ADDR, host.addr); + values.put(HostProvider.Hosts.PORT, host.port); + values.put(HostProvider.Hosts.USER, host.user); + values.put(HostProvider.Hosts.PASS, host.pass); + values.put(HostProvider.Hosts.ESPORT, host.esPort); + values.put(HostProvider.Hosts.TIMEOUT, host.timeout); + values.put(HostProvider.Hosts.WIFI_ONLY, host.wifi_only ? 1 : 0); + values.put(HostProvider.Hosts.MAC_ADDR, host.mac_addr); + values.put(HostProvider.Hosts.ACCESS_POINT, host.access_point); + values.put(HostProvider.Hosts.WOL_PORT, host.wol_port); + values.put(HostProvider.Hosts.WOL_WAIT, host.wol_wait); + context.getContentResolver().insert(HostProvider.Hosts.CONTENT_URI, values); + } + + /** + * Updates a host + * + * @param context Reference to context + * @param host Host to update + */ + public static void updateHost(Context context, Host host) { + ContentValues values = new ContentValues(); + values.put(HostProvider.Hosts.NAME, host.name); + values.put(HostProvider.Hosts.ADDR, host.addr); + values.put(HostProvider.Hosts.PORT, host.port); + values.put(HostProvider.Hosts.USER, host.user); + values.put(HostProvider.Hosts.PASS, host.pass); + values.put(HostProvider.Hosts.ESPORT, host.esPort); + values.put(HostProvider.Hosts.TIMEOUT, host.timeout); + values.put(HostProvider.Hosts.WIFI_ONLY, host.wifi_only ? 1 : 0); + values.put(HostProvider.Hosts.MAC_ADDR, host.mac_addr); + values.put(HostProvider.Hosts.ACCESS_POINT, host.access_point); + values.put(HostProvider.Hosts.WOL_PORT, host.wol_port); + values.put(HostProvider.Hosts.WOL_WAIT, host.wol_wait); + context.getContentResolver().update(HostProvider.Hosts.CONTENT_URI, values, + HostProvider.Hosts._ID + "=" + host.id, null); + } + + /** + * Deletes a host. + * + * @param context Reference to activity + * @param host Host to delete + * @return + */ + public static void deleteHost(Context context, Host host) { + Uri hostUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, host.id); + context.getContentResolver().delete(hostUri, null, null); + } + + /** + * Saves the host to the preference file. + * + * @param context + */ + public static void saveHost(Context context, Host h) { + SharedPreferences.Editor ed = PreferenceManager.getDefaultSharedPreferences(context).edit(); + if (h != null) { + ed.putInt(SETTING_HOST_ID, h.id); + } else { + ed.putInt(SETTING_HOST_ID, 0); + } + ed.commit(); + host = h; + ClientFactory.resetClient(h); + } + + /** + * Reads the preferences and returns the currently set host. If there is no + * preference set, return the first host. If there is no host set, return + * null. + * + * @param context Reference to current activity + * @return Current host + */ + public static void readHost(Context context) { + int hostId = PreferenceManager.getDefaultSharedPreferences(context).getInt(SETTING_HOST_ID, -1); + if (hostId < 0) { + host = getHost(context); + } else { + host = getHost(context, hostId); + } + Log.i(TAG, "XBMC Host = " + (host == null ? "[host=null]" : host.addr)); + } + + /** + * Returns a host based on its database ID. + * + * @param context Reference to activity + * @param id Host database ID + * @return + */ + private static Host getHost(Context context, int id) { + Uri hostUri = ContentUris.withAppendedId(Hosts.CONTENT_URI, id); + Cursor cur = context.getContentResolver().query(hostUri, null, null, null, null); + try { + if (cur.moveToFirst()) { + final Host host = new Host(); + host.id = cur.getInt(cur.getColumnIndex(HostProvider.Hosts._ID)); + host.name = cur.getString(cur.getColumnIndex(HostProvider.Hosts.NAME)); + host.addr = cur.getString(cur.getColumnIndex(HostProvider.Hosts.ADDR)); + host.port = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.PORT)); + host.user = cur.getString(cur.getColumnIndex(HostProvider.Hosts.USER)); + host.pass = cur.getString(cur.getColumnIndex(HostProvider.Hosts.PASS)); + host.esPort = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.ESPORT)); + host.timeout = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.TIMEOUT)); + host.wifi_only = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WIFI_ONLY)) == 1; + host.access_point = cur.getString(cur.getColumnIndex(HostProvider.Hosts.ACCESS_POINT)); + host.mac_addr = cur.getString(cur.getColumnIndex(HostProvider.Hosts.MAC_ADDR)); + host.wol_port = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WOL_PORT)); + host.wol_wait = cur.getInt(cur.getColumnIndex(HostProvider.Hosts.WOL_WAIT)); + return host; + } + } finally { + cur.close(); + } + return null; + } + + /** + * Returns the first host found. This is useful if hosts are defined but + * the settings have been erased and need to be reset to a host. If nothing + * found, return null. + * + * @param context Reference to activity + * @return First host found or null if hosts table empty. + */ + private static Host getHost(Context context) { + ArrayList hosts = getHosts(context); + if (hosts.size() > 0) { + return hosts.get(0); + } else { + return null; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/xbmc/android/util/IOUtilities.java b/app/src/main/java/org/xbmc/android/util/IOUtilities.java new file mode 100644 index 00000000..81e36fcf --- /dev/null +++ b/app/src/main/java/org/xbmc/android/util/IOUtilities.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 Romain Guy + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.xbmc.android.util; + +import android.os.Environment; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public final class IOUtilities { + public static final int IO_BUFFER_SIZE = 4 * 1024; + private static final String LOG_TAG = "IOUtilities"; + + public static File getExternalFile(String file) { + return new File(Environment.getExternalStorageDirectory(), file); + } + + /** + * Copy the content of the input stream into the output stream, using a temporary + * byte array buffer whose size is defined by {@link #IO_BUFFER_SIZE}. + * + * @param in The input stream to copy from. + * @param out The output stream to copy to. + * @throws java.io.IOException If any error occurs during the copy. + */ + public static void copy(InputStream in, OutputStream out) throws IOException { + byte[] b = new byte[IO_BUFFER_SIZE]; + int read; + while ((read = in.read(b)) != -1) { + out.write(b, 0, read); + } + } + + /** + * Closes the specified stream. + * + * @param stream The stream to close. + */ + public static void closeStream(Closeable stream) { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + android.util.Log.e(LOG_TAG, "Could not close stream", e); + } + } + } +} diff --git a/src/org/xbmc/android/util/ImportUtilities.java b/app/src/main/java/org/xbmc/android/util/ImportUtilities.java similarity index 50% rename from src/org/xbmc/android/util/ImportUtilities.java rename to app/src/main/java/org/xbmc/android/util/ImportUtilities.java index c8a20edf..60dcdf10 100644 --- a/src/org/xbmc/android/util/ImportUtilities.java +++ b/app/src/main/java/org/xbmc/android/util/ImportUtilities.java @@ -16,44 +16,44 @@ package org.xbmc.android.util; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Environment; +import android.os.StatFs; import org.xbmc.api.object.ICoverArt; import org.xbmc.api.type.MediaType; import org.xbmc.api.type.ThumbSize; import org.xbmc.api.type.ThumbSize.Dimension; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Environment; -import android.os.StatFs; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; public abstract class ImportUtilities { - - private static final String CACHE_DIRECTORY = "xbmc"; - private static final double MIN_FREE_SPACE = 3; - - public static File getCacheDirectory(String type, int size) { - StringBuilder sb = new StringBuilder(CACHE_DIRECTORY); - sb.append(type); - sb.append(ThumbSize.getDir(size)); - return IOUtilities.getExternalFile(sb.toString()); - } - - public static File getCacheFile(String type, int size, String name) { - StringBuilder sb = new StringBuilder(32); - sb.append(CACHE_DIRECTORY); - sb.append(type); - sb.append(ThumbSize.getDir(size)); - sb.append("/"); - sb.append(name); - return IOUtilities.getExternalFile(sb.toString()); - } - - public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) { + + private static final String CACHE_DIRECTORY = "xbmc"; + private static final double MIN_FREE_SPACE = 3; + + public static File getCacheDirectory(String type, int size) { + StringBuilder sb = new StringBuilder(CACHE_DIRECTORY); + sb.append(type); + sb.append(ThumbSize.getDir(size)); + return IOUtilities.getExternalFile(sb.toString()); + } + + public static File getCacheFile(String type, int size, String name) { + StringBuilder sb = new StringBuilder(32); + sb.append(CACHE_DIRECTORY); + sb.append(type); + sb.append(ThumbSize.getDir(size)); + sb.append("/"); + sb.append(name); + return IOUtilities.getExternalFile(sb.toString()); + } + + public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSize) { Bitmap sizeToReturn = null; File cacheDirectory; final int mediaType = cover.getMediaType(); @@ -66,7 +66,7 @@ public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSi continue; } } - + try { cacheDirectory = ensureCache(MediaType.getArtFolder(mediaType), currentThumbSize); } catch (IOException e) { @@ -79,10 +79,11 @@ public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSi final Bitmap source = bitmap; // Centre crop and resize the image - Dimension targetDim = ThumbSize.getTargetDimension(currentThumbSize, mediaType, source.getWidth(), source.getHeight()); - + Dimension targetDim = ThumbSize.getTargetDimension(currentThumbSize, mediaType, source.getWidth(), + source.getHeight()); + double targetAR = targetDim.x / targetDim.y; - double sourceAR = source.getWidth() / source.getHeight(); + double sourceAR = source.getWidth() / source.getHeight(); Bitmap cropped; if (sourceAR > targetAR) { @@ -106,97 +107,102 @@ public static Bitmap addCoverToCache(ICoverArt cover, Bitmap bitmap, int thumbSi resized.compress(Bitmap.CompressFormat.JPEG, 85, new FileOutputStream(coverFile)); if (thumbSize == currentThumbSize) { sizeToReturn = resized; - } + } } catch (FileNotFoundException e) { return null; } finally { IOUtilities.closeStream(out); } } - + return sizeToReturn; } - + public static int calculateSampleSize(BitmapFactory.Options options, Dimension targetDimension) { if (targetDimension.x == 0 || targetDimension.y == 0) { return 1; } - Boolean scaleByHeight = Math.abs(options.outHeight - targetDimension.y) >= Math.abs(options.outWidth - targetDimension.x); + Boolean scaleByHeight = Math.abs(options.outHeight - targetDimension.y) >= Math.abs(options.outWidth - + targetDimension.x); if (options.outHeight * options.outWidth * 2 >= 200 * 200 * 2) { // Load, scaling to smallest power of 2 that'll get it <= desired dimensions - double sampleSize = scaleByHeight ? options.outHeight / targetDimension.y : options.outWidth / targetDimension.x; + double sampleSize = scaleByHeight ? options.outHeight / targetDimension.y : options.outWidth / + targetDimension.x; return (int) Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d))); } else { return 1; } } - - /** - * Returns number of free bytes on the SD card. - * @return Number of free bytes on the SD card. - */ - public static long freeSpace() { - StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); - long blockSize = stat.getBlockSize(); - long availableBlocks = stat.getAvailableBlocks(); - return availableBlocks * blockSize; - } - - /** - * Returns total size of SD card in bytes. - * @return Total size of SD card in bytes. - */ - public static long totalSpace() { - StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); - long blockSize = stat.getBlockSize(); - long totalBlocks = stat.getBlockCount(); - return totalBlocks * blockSize; - } - - public static String assertSdCard() { - if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { - return "Your SD card is not mounted. You'll need it for caching thumbs."; - } - if (freePercentage() < MIN_FREE_SPACE) { - return "You need to have more than " + MIN_FREE_SPACE + "% of free space on your SD card."; - } - return null; - } - - - /** - * Returns free space in percent. - * @return Free space in percent. - */ - public static double freePercentage() { - StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); - long availableBlocks = stat.getAvailableBlocks(); - long totalBlocks = stat.getBlockCount(); - return (double)availableBlocks / (double)totalBlocks * 100; - } - - private static File ensureCache(String type, int size) throws IOException { - File cacheDirectory = getCacheDirectory(type, size); - if (!cacheDirectory.exists()) { - cacheDirectory.mkdirs(); - new File(cacheDirectory, ".nomedia").createNewFile(); - } - return cacheDirectory; - } - - public static void purgeCache() { - final int size[] = ThumbSize.values(); - final int[] mediaTypes = MediaType.getTypes(); - for (int i = 0; i < mediaTypes.length; i++) { - String folder = MediaType.getArtFolder(mediaTypes[i]); - for (int j = 0; j < size.length; j++) { - File cacheDirectory = getCacheDirectory(folder, size[j]); - if (cacheDirectory.exists() && cacheDirectory.isDirectory()) { - for (File file : cacheDirectory.listFiles()) { - file.delete(); - } - } - } - } - } + + /** + * Returns number of free bytes on the SD card. + * + * @return Number of free bytes on the SD card. + */ + public static long freeSpace() { + StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); + long blockSize = stat.getBlockSize(); + long availableBlocks = stat.getAvailableBlocks(); + return availableBlocks * blockSize; + } + + /** + * Returns total size of SD card in bytes. + * + * @return Total size of SD card in bytes. + */ + public static long totalSpace() { + StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); + long blockSize = stat.getBlockSize(); + long totalBlocks = stat.getBlockCount(); + return totalBlocks * blockSize; + } + + public static String assertSdCard() { + if (!android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { + return "Your SD card is not mounted. You'll need it for caching thumbs."; + } + if (freePercentage() < MIN_FREE_SPACE) { + return "You need to have more than " + MIN_FREE_SPACE + "% of free space on your SD card."; + } + return null; + } + + + /** + * Returns free space in percent. + * + * @return Free space in percent. + */ + public static double freePercentage() { + StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath()); + long availableBlocks = stat.getAvailableBlocks(); + long totalBlocks = stat.getBlockCount(); + return (double) availableBlocks / (double) totalBlocks * 100; + } + + private static File ensureCache(String type, int size) throws IOException { + File cacheDirectory = getCacheDirectory(type, size); + if (!cacheDirectory.exists()) { + cacheDirectory.mkdirs(); + new File(cacheDirectory, ".nomedia").createNewFile(); + } + return cacheDirectory; + } + + public static void purgeCache() { + final int size[] = ThumbSize.values(); + final int[] mediaTypes = MediaType.getTypes(); + for (int i = 0; i < mediaTypes.length; i++) { + String folder = MediaType.getArtFolder(mediaTypes[i]); + for (int j = 0; j < size.length; j++) { + File cacheDirectory = getCacheDirectory(folder, size[j]); + if (cacheDirectory.exists() && cacheDirectory.isDirectory()) { + for (File file : cacheDirectory.listFiles()) { + file.delete(); + } + } + } + } + } } diff --git a/app/src/main/java/org/xbmc/android/util/KeyTracker.java b/app/src/main/java/org/xbmc/android/util/KeyTracker.java new file mode 100644 index 00000000..4654cbe2 --- /dev/null +++ b/app/src/main/java/org/xbmc/android/util/KeyTracker.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.xbmc.android.util; + +import android.view.KeyEvent; +import android.view.ViewConfiguration; + +public class KeyTracker { + + private static final int LONG_PRESS_DURATION_MS = + ViewConfiguration.getLongPressTimeout(); + private static final int NOT_A_KEYCODE = -123456; + private int mKeyCode = NOT_A_KEYCODE; + private KeyEvent mEvent; + private long mStartMS; + private State mState; + private OnKeyTracker mTracker; + + public KeyTracker(OnKeyTracker tracker) { + mTracker = tracker; + } + + public boolean doKeyDown(int keyCode, KeyEvent event) { + long now = System.currentTimeMillis(); + Stage stage = null; + + // check if its a new/different key + if (mKeyCode != keyCode || event.getRepeatCount() == 0) { + mKeyCode = keyCode; + mStartMS = now; + stage = Stage.DOWN; + } else if (mState == State.KEEP_TRACKING) { + stage = (now - mStartMS) >= LONG_PRESS_DURATION_MS ? Stage.LONG_REPEAT : Stage.SHORT_REPEAT; + } + + if (stage != null) { + mEvent = event; + callTracker(stage, now); + } + + return mState != State.NOT_TRACKING; + } + + public boolean doKeyUp(int keyCode, KeyEvent event) { + boolean handled = false; + + if (mState == State.KEEP_TRACKING && mKeyCode == keyCode) { + mEvent = event; + callTracker(Stage.UP, System.currentTimeMillis()); + handled = mState != State.NOT_TRACKING; + } + mKeyCode = NOT_A_KEYCODE; + return handled; + } + + private void callTracker(Stage stage, long now) { + mState = mTracker.onKeyTracker(mKeyCode, mEvent, stage, (int) (now - mStartMS)); + } + + public void dump() { + System.out.println(" key=" + mKeyCode + " dur=" + (System.currentTimeMillis() - mStartMS) + + " state=" + mState); + } + + public enum Stage { + DOWN, //!< the key has just been pressed + SHORT_REPEAT, //!< repeated key, but duration is under the long-press threshold + LONG_REPEAT, //!< repeated key, but duration is over the long-press threshold + UP //!< the key is being released + } + + public enum State { + KEEP_TRACKING, //!< return this to continue to track the key + DONE_TRACKING, //!< return this if you handled the key, but need not track it anymore + NOT_TRACKING //!< return this if you will not handle this key + } + + public interface OnKeyTracker { + + /** + * Called whenever there is a key event [down, short/long repeat, up] + * + * @param keyCode The current keyCode (see KeyEvent class) + * @param duration The number of milliseconds since this key was initially pressed + * @return your state after seeing the key. If you return DONE_TRACKING or NOT_TRACKING, + * you will not be called again for the lifetime of this key event. + * @maram stage The state the key press is in [down, short/long repeat, up] + */ + public State onKeyTracker(int keyCode, KeyEvent event, Stage stage, int duration); + } +} + diff --git a/src/org/xbmc/android/util/MacAddressResolver.java b/app/src/main/java/org/xbmc/android/util/MacAddressResolver.java similarity index 89% rename from src/org/xbmc/android/util/MacAddressResolver.java rename to app/src/main/java/org/xbmc/android/util/MacAddressResolver.java index dcb33f0d..e545c813 100644 --- a/src/org/xbmc/android/util/MacAddressResolver.java +++ b/app/src/main/java/org/xbmc/android/util/MacAddressResolver.java @@ -21,33 +21,32 @@ package org.xbmc.android.util; -import java.io.BufferedReader; -import java.io.FileReader; -import java.net.InetAddress; - import android.os.Bundle; import android.os.Handler; import android.os.Message; +import java.io.BufferedReader; +import java.io.FileReader; +import java.net.InetAddress; + /** * Resolve IP addresses to corresponding MAC addresses if possible - * + * * @author Team XBMC */ -public class MacAddressResolver implements Runnable{ - +public class MacAddressResolver implements Runnable { + + public static final String MESSAGE_MAC_ADDRESS = "MAC_ADDRESS"; private String mHost = null; private String mMac = null; private Handler mHandler; - - public static final String MESSAGE_MAC_ADDRESS = "MAC_ADDRESS"; - - public MacAddressResolver(String ipString, Handler handler){ + + public MacAddressResolver(String ipString, Handler handler) { mHost = ipString; mHandler = handler; } - - public void run(){ + + public void run() { mMac = arpResolve(mHost); Bundle bundle = new Bundle(); bundle.putString(MESSAGE_MAC_ADDRESS, mMac); @@ -55,25 +54,25 @@ public void run(){ message.setData(bundle); mHandler.sendMessage(message); } - - private String arpResolve(String host){ + + private String arpResolve(String host) { System.out.println("ARPRESOLVE HOST: " + host); - try{ + try { //Parse it as a proper InetAddress - it might be a hostname. We don't know yet. InetAddress inet = InetAddress.getByName(host); - + //initiate some sort of traffic to ensure we get an arp entry (if we're on same subnet, that is...) inet.isReachable(500); //timeout of 500ms. just to trigger the arp resolution process - + //Get the official string representation of the resolved ip address String ipString = inet.getHostAddress(); BufferedReader br = new BufferedReader(new FileReader("/proc/net/arp")); String line = ""; - while(true){ + while (true) { line = br.readLine(); if (line == null) break; - if(line.startsWith(ipString)){ + if (line.startsWith(ipString)) { br.close(); System.out.println("ARPRESOLVE MAC:\n" + line); return line.split("\\s+")[3]; // 4th word, separated by "whitespace" @@ -81,8 +80,8 @@ private String arpResolve(String host){ } br.close(); return ""; - - }catch(Exception e){ + + } catch (Exception e) { return ""; } diff --git a/app/src/main/java/org/xbmc/android/util/OnLongPressBackKeyTracker.java b/app/src/main/java/org/xbmc/android/util/OnLongPressBackKeyTracker.java new file mode 100644 index 00000000..6a4ad0c8 --- /dev/null +++ b/app/src/main/java/org/xbmc/android/util/OnLongPressBackKeyTracker.java @@ -0,0 +1,38 @@ +package org.xbmc.android.util; + +import android.view.KeyEvent; + +import org.xbmc.android.util.KeyTracker.OnKeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.KeyTracker.State; + +public abstract class OnLongPressBackKeyTracker implements OnKeyTracker { + + public static Stage lastStage = Stage.SHORT_REPEAT; + + public State onKeyTracker(int keyCode, KeyEvent event, Stage stage, + int duration) { + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (stage == KeyTracker.Stage.LONG_REPEAT) { + // here we have the long pressed back button + onLongPressBack(keyCode, event, stage, duration); + lastStage = stage; + return KeyTracker.State.KEEP_TRACKING; + } else if (stage == KeyTracker.Stage.UP) { + if (lastStage == Stage.LONG_REPEAT) { + lastStage = Stage.SHORT_REPEAT; + return KeyTracker.State.DONE_TRACKING; + } + onShortPressBack(keyCode, event, stage, duration); + return KeyTracker.State.NOT_TRACKING; + } + return KeyTracker.State.KEEP_TRACKING; + } + return KeyTracker.State.NOT_TRACKING; + } + + public abstract void onLongPressBack(int keyCode, KeyEvent event, Stage stage, int duration); + + public abstract void onShortPressBack(int keyCode, KeyEvent event, Stage stage, int duration); + +} diff --git a/src/org/xbmc/android/util/PowerDown.java b/app/src/main/java/org/xbmc/android/util/PowerDown.java similarity index 97% rename from src/org/xbmc/android/util/PowerDown.java rename to app/src/main/java/org/xbmc/android/util/PowerDown.java index 234af4bc..ca5b3021 100644 --- a/src/org/xbmc/android/util/PowerDown.java +++ b/app/src/main/java/org/xbmc/android/util/PowerDown.java @@ -21,14 +21,14 @@ package org.xbmc.android.util; -import org.xbmc.android.remote.business.EventClientManager; -import org.xbmc.api.business.IEventClientManager; -import org.xbmc.eventclient.ButtonCodes; - import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; +import org.xbmc.android.remote.business.EventClientManager; +import org.xbmc.api.business.IEventClientManager; +import org.xbmc.eventclient.ButtonCodes; + public class PowerDown { IEventClientManager mEventClientManager; private Activity mActivity; @@ -45,7 +45,8 @@ public void onClick(DialogInterface dialog, int id) { private void Down() { EventClientManager pdEventClientManager = new EventClientManager(); - pdEventClientManager.sendButton("R1", ButtonCodes.REMOTE_POWER, false, true, true, (short) 0, (byte) 0); + pdEventClientManager.sendButton("R1", ButtonCodes.REMOTE_POWER, false, true, true, (short) 0, + (byte) 0); } }).setNegativeButton("No", new DialogInterface.OnClickListener() { diff --git a/src/org/xbmc/android/util/SMSConstants.java b/app/src/main/java/org/xbmc/android/util/SMSConstants.java similarity index 86% rename from src/org/xbmc/android/util/SMSConstants.java rename to app/src/main/java/org/xbmc/android/util/SMSConstants.java index 589134d3..d44d2c01 100644 --- a/src/org/xbmc/android/util/SMSConstants.java +++ b/app/src/main/java/org/xbmc/android/util/SMSConstants.java @@ -1,39 +1,39 @@ -package org.xbmc.android.util; - -import android.net.Uri; - -public class SMSConstants { - - public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox"); - - public static final String ID = "_id"; - public static final int ID_INT = 0; - public static final String THREAD_ID = "thread_id"; - public static final int THREAD_ID_INT = 1; - public static final String ADDRESS = "address"; - public static final int ADDRESS_INT = 2; - public static final String PERSON = "person"; - public static final int PERSON_INT = 3; - public static final String DATE = "date"; - public static final int DATE_INT = 4; - public static final String PROTOCOL = "protocol"; - public static final int PROTOCOL_INT = 5; - public static final String READ = "read"; - public static final int READ_INT = 6; - public static final String STATUS = "status"; - public static final int STATUS_INT = 7; - public static final String TYPE = "type"; - public static final int TYPE_INT = 8; - public static final String REPLY_PATH_PRESENT = "reply_path_present"; - public static final int REPLY_PATH_PRESENT_INT = 9; - public static final String SUBJECT = "subject"; - public static final int SUBJECT_INT = 10; - public static final String BODY = "body"; - public static final int BODY_INT = 11; - public static final String SERVICE_CENTER = "service_center"; - public static final int SERVICE_CENTER_INT = 12; - public static final String[] projection = { - ID, THREAD_ID, ADDRESS, PERSON, DATE, PROTOCOL, READ, STATUS, TYPE, - REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER }; - +package org.xbmc.android.util; + +import android.net.Uri; + +public class SMSConstants { + + public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox"); + + public static final String ID = "_id"; + public static final int ID_INT = 0; + public static final String THREAD_ID = "thread_id"; + public static final int THREAD_ID_INT = 1; + public static final String ADDRESS = "address"; + public static final int ADDRESS_INT = 2; + public static final String PERSON = "person"; + public static final int PERSON_INT = 3; + public static final String DATE = "date"; + public static final int DATE_INT = 4; + public static final String PROTOCOL = "protocol"; + public static final int PROTOCOL_INT = 5; + public static final String READ = "read"; + public static final int READ_INT = 6; + public static final String STATUS = "status"; + public static final int STATUS_INT = 7; + public static final String TYPE = "type"; + public static final int TYPE_INT = 8; + public static final String REPLY_PATH_PRESENT = "reply_path_present"; + public static final int REPLY_PATH_PRESENT_INT = 9; + public static final String SUBJECT = "subject"; + public static final int SUBJECT_INT = 10; + public static final String BODY = "body"; + public static final int BODY_INT = 11; + public static final String SERVICE_CENTER = "service_center"; + public static final String[] projection = { + ID, THREAD_ID, ADDRESS, PERSON, DATE, PROTOCOL, READ, STATUS, TYPE, + REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER}; + public static final int SERVICE_CENTER_INT = 12; + } \ No newline at end of file diff --git a/src/org/xbmc/android/util/SmsMmsMessage.java b/app/src/main/java/org/xbmc/android/util/SmsMmsMessage.java similarity index 92% rename from src/org/xbmc/android/util/SmsMmsMessage.java rename to app/src/main/java/org/xbmc/android/util/SmsMmsMessage.java index 933a1f09..055cb122 100644 --- a/src/org/xbmc/android/util/SmsMmsMessage.java +++ b/app/src/main/java/org/xbmc/android/util/SmsMmsMessage.java @@ -1,419 +1,418 @@ -package org.xbmc.android.util; - -import java.io.ByteArrayInputStream; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.Bundle; -import android.telephony.PhoneNumberUtils; -import android.telephony.gsm.SmsMessage; -import android.text.format.DateUtils; - -/** - * TODO Once we move to 1.6+, waste the deprecated code. - */ -@SuppressWarnings("deprecation") -public class SmsMmsMessage { - - private static final String PREFIX = "net.everythingandroid.smspopup."; - private static final String EXTRAS_FROM_ADDRESS = PREFIX + "EXTRAS_FROM_ADDRESS"; - private static final String EXTRAS_MESSAGE_BODY = PREFIX + "EXTRAS_MESSAGE_BODY"; - private static final String EXTRAS_TIMESTAMP = PREFIX + "EXTRAS_TIMESTAMP"; - private static final String EXTRAS_UNREAD_COUNT = PREFIX + "EXTRAS_UNREAD_COUNT"; - private static final String EXTRAS_THREAD_ID = PREFIX + "EXTRAS_THREAD_ID"; - private static final String EXTRAS_CONTACT_ID = PREFIX + "EXTRAS_CONTACT_ID"; - private static final String EXTRAS_CONTACT_NAME = PREFIX + "EXTRAS_CONTACT_NAME"; - private static final String EXTRAS_CONTACT_PHOTO = PREFIX + "EXTRAS_CONTACT_PHOTO"; - private static final String EXTRAS_MESSAGE_TYPE = PREFIX + "EXTRAS_MESSAGE_TYPE"; - private static final String EXTRAS_MESSAGE_ID = PREFIX + "EXTRAS_MESSAGE_ID"; - public static final String EXTRAS_NOTIFY = PREFIX + "EXTRAS_NOTIFY"; - public static final String EXTRAS_REMINDER_COUNT = PREFIX + "EXTRAS_REMINDER_COUNT"; - public static final String EXTRAS_REPLYING = PREFIX + "EXTRAS_REPLYING"; - public static final String EXTRAS_QUICKREPLY = PREFIX + "EXTRAS_QUICKREPLY"; - - public static final int MESSAGE_TYPE_SMS = 0; - public static final int MESSAGE_TYPE_MMS = 1; - - private Context mContext; - - final private String mFromAddress; - final private String mMessageBody; - final private long mTimestamp; - final private int mUnreadCount; - final private long mThreadId; - private String mContactId; - private String mContactName; - final private byte[] mContactPhoto; - final private int mMessageType; - - private boolean mNotify = true; - private int mReminderCount = 0; - private long mMessageId = 0; - - /** - * Construct SmsMmsMessage with minimal information - this is useful for - * when a raw SMS comes in which just contains address, body and timestamp. - * We must then look in the database for the rest of the information - */ - public SmsMmsMessage(Context _context, String _fromAddress, String _messageBody, long _timestamp, int _messageType) { - - mContext = _context; - mFromAddress = _fromAddress; - mMessageBody = _messageBody == null ? "" : _messageBody; - mTimestamp = _timestamp; - mMessageType = _messageType; - - mContactId = SmsPopupUtils.getPersonIdFromPhoneNumber(mContext, mFromAddress); - mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); - mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); - - mUnreadCount = SmsPopupUtils.getUnreadMessagesCount(mContext, mTimestamp); - mThreadId = SmsPopupUtils.getThreadIdFromAddress(mContext, mFromAddress); - - setMessageId(); - - if (mContactName == null) { - mContactName = mContext.getString(android.R.string.unknownName); - } - } - - /** - * Construct SmsMmsMessage for getMmsDetails() - info fetched from the MMS - * database table - */ - public SmsMmsMessage(Context _context, String _fromAddress, - String _messageBody, long _timestamp, long _threadId, - int _unreadCount, int _messageType) { - - mContext = _context; - mFromAddress = _fromAddress; - mMessageBody = _messageBody == null ? "" : _messageBody;; - mTimestamp = _timestamp; - mMessageType = _messageType; - - // TODO: I think contactId can come the MMS table, this would save - // this database lookup - mContactId = SmsPopupUtils.getPersonIdFromPhoneNumber(mContext, mFromAddress); - - mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); - mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); - - mUnreadCount = _unreadCount; - mThreadId = _threadId; - - setMessageId(); - - if (mContactName == null) { - mContactName = mContext.getString(android.R.string.unknownName); - } - } - - /** - * Construct SmsMmsMessage for getSmsDetails() - info fetched from the SMS - * database table - */ - public SmsMmsMessage(Context _context, String _fromAddress, - String _contactId, String _messageBody, long _timestamp, - long _threadId, int _unreadCount, long _messageId, int _messageType) { - mContext = _context; - mFromAddress = _fromAddress; - mMessageBody = _messageBody == null ? "" : _messageBody;; - mTimestamp = _timestamp; - mMessageType = _messageType; - mContactId = _contactId; - - if ("0".equals(mContactId)) - mContactId = null; - - mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); - mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); - - mUnreadCount = _unreadCount; - mThreadId = _threadId; - - mMessageId = _messageId; - - if (mContactName == null) { - mContactName = mContext.getString(android.R.string.unknownName); - } - } - - /** - * Construct SmsMmsMessage from an extras bundle - */ - public SmsMmsMessage(Context _context, Bundle b) { - mContext = _context; - mFromAddress = b.getString(EXTRAS_FROM_ADDRESS); - mMessageBody = b.getString(EXTRAS_MESSAGE_BODY) == null ? "" : b.getString(EXTRAS_MESSAGE_BODY); - mTimestamp = b.getLong(EXTRAS_TIMESTAMP); - mContactId = b.getString(EXTRAS_CONTACT_ID); - mContactName = b.getString(EXTRAS_CONTACT_NAME); - mContactPhoto = b.getByteArray(EXTRAS_CONTACT_PHOTO); - mUnreadCount = b.getInt(EXTRAS_UNREAD_COUNT, 1); - mThreadId = b.getLong(EXTRAS_THREAD_ID, 0); - mMessageType = b.getInt(EXTRAS_MESSAGE_TYPE, MESSAGE_TYPE_SMS); - mNotify = b.getBoolean(EXTRAS_NOTIFY, false); - mReminderCount = b.getInt(EXTRAS_REMINDER_COUNT, 0); - mMessageId = b.getLong(EXTRAS_MESSAGE_ID, 0); - } - - /** - * Construct SmsMmsMessage by specifying all data, only used for testing the - * notification from the preferences screen - */ - public SmsMmsMessage(Context _context, String _fromAddress, - String _messageBody, long _timestamp, String _contactId, - String _contactName, byte[] _contactPhoto, int _unreadCount, - long _threadId, int _messageType) { - mContext = _context; - mFromAddress = _fromAddress; - mMessageBody = _messageBody == null ? "" : _messageBody; - mTimestamp = _timestamp; - mContactId = _contactId; - mContactName = _contactName; - mContactPhoto = _contactPhoto; - mUnreadCount = _unreadCount; - mThreadId = _threadId; - mMessageType = _messageType; - } - - /** - * Convert all SmsMmsMessage data to an extras bundle to send via an intent - */ - public Bundle toBundle() { - Bundle b = new Bundle(); - b.putString(EXTRAS_FROM_ADDRESS, mFromAddress); - b.putString(EXTRAS_MESSAGE_BODY, mMessageBody); - b.putLong(EXTRAS_TIMESTAMP, mTimestamp); - b.putString(EXTRAS_CONTACT_ID, mContactId); - b.putString(EXTRAS_CONTACT_NAME, mContactName); - b.putByteArray(EXTRAS_CONTACT_PHOTO, mContactPhoto); - b.putInt(EXTRAS_UNREAD_COUNT, mUnreadCount); - b.putLong(EXTRAS_THREAD_ID, mThreadId); - b.putInt(EXTRAS_MESSAGE_TYPE, mMessageType); - b.putBoolean(EXTRAS_NOTIFY, mNotify); - b.putInt(EXTRAS_REMINDER_COUNT, mReminderCount); - b.putLong(EXTRAS_MESSAGE_ID, mMessageId); - return b; - } - - public static SmsMmsMessage getSmsfromPDUs(Context context, Object[] pdus) { - SmsMessage[] msgs = new SmsMessage[pdus.length]; - String from; - StringBuilder body = new StringBuilder(); - long timestamp; - int msgtype = MESSAGE_TYPE_SMS; - // public SmsMmsMessage(Context _context, String _fromAddress, String - // _messageBody, - // long _timestamp, int _messageType) - for (int i = 0; i < msgs.length; i++) { - msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); - } - SmsMessage firstMessage = msgs[0]; - for (SmsMessage currentMessage : msgs) { - if (currentMessage.getDisplayOriginatingAddress().equals(firstMessage.getDisplayOriginatingAddress())) { - body.append(currentMessage.getDisplayMessageBody()); - } - } - timestamp = firstMessage.getTimestampMillis(); - from = firstMessage.getDisplayOriginatingAddress(); - return new SmsMmsMessage(context, from, body.toString(), timestamp, msgtype); - } - - public Bitmap getContactPhoto() { - if (mContactPhoto == null) - return null; - return BitmapFactory.decodeStream(new ByteArrayInputStream(mContactPhoto)); - } - - public int getUnreadCount() { - return mUnreadCount; - } - - public long getTimestamp() { - return mTimestamp; - } - - public CharSequence getFormattedTimestamp() { - /* - * No need for my own format function now, the 1.5 SDK has this built in - * (this will detect the system settings and return the correct format) - */ - // return SMSPopupUtils.formatTimestamp(context, timestamp); - return DateUtils.formatDateTime(mContext, mTimestamp, DateUtils.FORMAT_SHOW_TIME); - } - - public String getContactName() { - if (mContactName == null) { - mContactName = mContext.getString(android.R.string.unknownName); - } - return mContactName; - } - - public String getMessageBody() { - return mMessageBody; - } - - public long getThreadId() { - return mThreadId; - } - - public int getMessageType() { - return mMessageType; - } - - public boolean getNotify() { - return mNotify; - } - - public int getReminderCount() { - return mReminderCount; - } - - public void updateReminderCount(int count) { - mReminderCount = count; - } - - public void incrementReminderCount() { - mReminderCount++; - } - - public void setMessageId() { - mMessageId = SmsPopupUtils.findMessageId(mContext, mThreadId, mTimestamp, mMessageType); - } - - public long getMessageId() { - if (mMessageId == 0) { - setMessageId(); - } - return mMessageId; - } - - public String getContactId() { - return mContactId; - } - - // public boolean equals(SmsMmsMessage compareMessage) { - // boolean equals = false; - // if (PhoneNumberUtils.compare(this.fromAddress, - // compareMessage.fromAddress) && - // this.compareTimeStamp(compareMessage.timestamp) && - // this.messageType == compareMessage.messageType) { - // equals = true; - // } - // return equals; - // } - - /** - * Check if this message is sufficiently the same as the provided parameters - */ - public boolean equals(String fromAddress, long timestamp, - long timestamp_provider, String body) { - boolean equals = false; - - if (PhoneNumberUtils.compare(this.mFromAddress, fromAddress) - && this.compareTimeStamp(timestamp, timestamp_provider) - && this.compareBody(body)) { - equals = true; - } - return equals; - } - - // private boolean compareTimeStamp(long compareTimestamp) { - // return compareTimeStamp(compareTimestamp, 0); - // } - - /* - * Compares the timestamps of a message, this is super hacky because the way - * which builds of Android store SMS timestamps changed in the cupcake - * branch - pre-cupcake it stored the timestamp provided by the telecom - * provider; post-cupcake it stored the system timestamp. Unfortunately this - * means we need to use 2 different ways to determine if the received - * message timestamp is sufficiently equal to the database timestamp :( - */ - private boolean compareTimeStamp(long compareTimestamp, long providerTimestamp) { - - final int MESSAGE_COMPARE_TIME_BUFFER = 2000; - // final int buildVersion = Integer.valueOf(Build.VERSION.INCREMENTAL); - - /* - * On March 28th, 2009 - these are the latest builds that I could find: - * 128600 TMI-RC9 (Tmobile EU) 126986 PLAT-RC33 (Tmobile US) 129975 - * Emulator (from Android 1.1 SDK r1) Hopefully anything later will have - * the updated SMS code that uses the system timestamp rather than the - * SMS timestamp - */ - // final int LATEST_BUILD = 129975; - // boolean PRE_CUPCAKE = false; - // if (buildVersion <= LATEST_BUILD) { - // PRE_CUPCAKE = true; - // } - // - // Log.v("DB timestamp = " + timestamp); - // Log.v("Provider timestamp = " + providerTimestamp); - // Log.v("System timestamp = " + compareTimestamp); - - /* - * If pre-cupcake we can just do a direct comparison as the Mms app - * stores the timestamp from the telecom provider (in the sms pdu) - */ - // if (PRE_CUPCAKE) { - // Log.v("Build is pre-cupcake ("+buildVersion+"), doing direct SMS timestamp comparison"); - // Log.v("DB timestamp = " + timestamp); - // Log.v("Intent timestamp = " + providerTimestamp); - if (mTimestamp == providerTimestamp) { - // Log.v("SMS Compare: compareTimestamp() - intent timestamp = provider timestamp"); - return true; - } // else { - // return false; - // } - // } - - /* - * If post-cupcake, the system app stores a system timestamp - the only - * problem is we have no way of knowing the exact time the system app - * used. So what we'll do is compare against our own system timestamp - * and add a buffer in. This is an awful way of doing this, but I don't - * see any other way around it :( - */ - // Log.v("Build is post-cupcake ("+buildVersion+"), doing approx. SMS timestamp comparison"); - // Log.v("DB timestamp = " + timestamp); - // Log.v("Intent timestamp = " + compareTimestamp); - - if (mTimestamp < (compareTimestamp + MESSAGE_COMPARE_TIME_BUFFER) - && mTimestamp > (compareTimestamp - MESSAGE_COMPARE_TIME_BUFFER)) { - // Log.v("SMS Compare: compareTimestamp() - timestamp is approx. the same"); - return true; - } - // Log.v("SMS Compare: compareTimestamp() - return false"); - return false; - } - - /* - * Compare message body - */ - private boolean compareBody(String compareBody) { - if (compareBody != null) { - if (mMessageBody.length() != compareBody.length()) { - // Log.v("SMS Compare: compareBody() - length is different"); - return false; - } - - if (mMessageBody.equals(compareBody)) { - // Log.v("SMS Compare: compareBody() - messageBody is the same"); - return true; - } - } - // Log.v("SMS Compare: compareBody() - return false"); - return false; - } - - public boolean replyToMessage(String quickreply) { - // SmsMessageSender sender = - // new SmsMessageSender(context, new String[] {fromAddress}, quickreply, - // threadId); - // return sender.sendMessage(); - return false; - } -} +package org.xbmc.android.util; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.telephony.PhoneNumberUtils; +import android.telephony.gsm.SmsMessage; +import android.text.format.DateUtils; + +import java.io.ByteArrayInputStream; + +/** + * TODO Once we move to 1.6+, waste the deprecated code. + */ +@SuppressWarnings("deprecation") +public class SmsMmsMessage { + + public static final int MESSAGE_TYPE_SMS = 0; + public static final int MESSAGE_TYPE_MMS = 1; + private static final String PREFIX = "net.everythingandroid.smspopup."; + private static final String EXTRAS_FROM_ADDRESS = PREFIX + "EXTRAS_FROM_ADDRESS"; + private static final String EXTRAS_MESSAGE_BODY = PREFIX + "EXTRAS_MESSAGE_BODY"; + private static final String EXTRAS_TIMESTAMP = PREFIX + "EXTRAS_TIMESTAMP"; + private static final String EXTRAS_UNREAD_COUNT = PREFIX + "EXTRAS_UNREAD_COUNT"; + private static final String EXTRAS_THREAD_ID = PREFIX + "EXTRAS_THREAD_ID"; + private static final String EXTRAS_CONTACT_ID = PREFIX + "EXTRAS_CONTACT_ID"; + private static final String EXTRAS_CONTACT_NAME = PREFIX + "EXTRAS_CONTACT_NAME"; + private static final String EXTRAS_CONTACT_PHOTO = PREFIX + "EXTRAS_CONTACT_PHOTO"; + private static final String EXTRAS_MESSAGE_TYPE = PREFIX + "EXTRAS_MESSAGE_TYPE"; + private static final String EXTRAS_MESSAGE_ID = PREFIX + "EXTRAS_MESSAGE_ID"; + public static final String EXTRAS_NOTIFY = PREFIX + "EXTRAS_NOTIFY"; + public static final String EXTRAS_REMINDER_COUNT = PREFIX + "EXTRAS_REMINDER_COUNT"; + public static final String EXTRAS_REPLYING = PREFIX + "EXTRAS_REPLYING"; + public static final String EXTRAS_QUICKREPLY = PREFIX + "EXTRAS_QUICKREPLY"; + final private String mFromAddress; + final private String mMessageBody; + final private long mTimestamp; + final private int mUnreadCount; + final private long mThreadId; + final private byte[] mContactPhoto; + final private int mMessageType; + private Context mContext; + private String mContactId; + private String mContactName; + private boolean mNotify = true; + private int mReminderCount = 0; + private long mMessageId = 0; + + /** + * Construct SmsMmsMessage with minimal information - this is useful for + * when a raw SMS comes in which just contains address, body and timestamp. + * We must then look in the database for the rest of the information + */ + public SmsMmsMessage(Context _context, String _fromAddress, String _messageBody, long _timestamp, + int _messageType) { + + mContext = _context; + mFromAddress = _fromAddress; + mMessageBody = _messageBody == null ? "" : _messageBody; + mTimestamp = _timestamp; + mMessageType = _messageType; + + mContactId = SmsPopupUtils.getPersonIdFromPhoneNumber(mContext, mFromAddress); + mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); + mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); + + mUnreadCount = SmsPopupUtils.getUnreadMessagesCount(mContext, mTimestamp); + mThreadId = SmsPopupUtils.getThreadIdFromAddress(mContext, mFromAddress); + + setMessageId(); + + if (mContactName == null) { + mContactName = mContext.getString(android.R.string.unknownName); + } + } + + /** + * Construct SmsMmsMessage for getMmsDetails() - info fetched from the MMS + * database table + */ + public SmsMmsMessage(Context _context, String _fromAddress, + String _messageBody, long _timestamp, long _threadId, + int _unreadCount, int _messageType) { + + mContext = _context; + mFromAddress = _fromAddress; + mMessageBody = _messageBody == null ? "" : _messageBody; + ; + mTimestamp = _timestamp; + mMessageType = _messageType; + + // TODO: I think contactId can come the MMS table, this would save + // this database lookup + mContactId = SmsPopupUtils.getPersonIdFromPhoneNumber(mContext, mFromAddress); + + mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); + mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); + + mUnreadCount = _unreadCount; + mThreadId = _threadId; + + setMessageId(); + + if (mContactName == null) { + mContactName = mContext.getString(android.R.string.unknownName); + } + } + + /** + * Construct SmsMmsMessage for getSmsDetails() - info fetched from the SMS + * database table + */ + public SmsMmsMessage(Context _context, String _fromAddress, + String _contactId, String _messageBody, long _timestamp, + long _threadId, int _unreadCount, long _messageId, int _messageType) { + mContext = _context; + mFromAddress = _fromAddress; + mMessageBody = _messageBody == null ? "" : _messageBody; + ; + mTimestamp = _timestamp; + mMessageType = _messageType; + mContactId = _contactId; + + if ("0".equals(mContactId)) + mContactId = null; + + mContactName = SmsPopupUtils.getPersonName(mContext, mContactId, mFromAddress); + mContactPhoto = SmsPopupUtils.getPersonPhoto(mContext, mContactId); + + mUnreadCount = _unreadCount; + mThreadId = _threadId; + + mMessageId = _messageId; + + if (mContactName == null) { + mContactName = mContext.getString(android.R.string.unknownName); + } + } + + /** + * Construct SmsMmsMessage from an extras bundle + */ + public SmsMmsMessage(Context _context, Bundle b) { + mContext = _context; + mFromAddress = b.getString(EXTRAS_FROM_ADDRESS); + mMessageBody = b.getString(EXTRAS_MESSAGE_BODY) == null ? "" : b.getString(EXTRAS_MESSAGE_BODY); + mTimestamp = b.getLong(EXTRAS_TIMESTAMP); + mContactId = b.getString(EXTRAS_CONTACT_ID); + mContactName = b.getString(EXTRAS_CONTACT_NAME); + mContactPhoto = b.getByteArray(EXTRAS_CONTACT_PHOTO); + mUnreadCount = b.getInt(EXTRAS_UNREAD_COUNT, 1); + mThreadId = b.getLong(EXTRAS_THREAD_ID, 0); + mMessageType = b.getInt(EXTRAS_MESSAGE_TYPE, MESSAGE_TYPE_SMS); + mNotify = b.getBoolean(EXTRAS_NOTIFY, false); + mReminderCount = b.getInt(EXTRAS_REMINDER_COUNT, 0); + mMessageId = b.getLong(EXTRAS_MESSAGE_ID, 0); + } + + /** + * Construct SmsMmsMessage by specifying all data, only used for testing the + * notification from the preferences screen + */ + public SmsMmsMessage(Context _context, String _fromAddress, + String _messageBody, long _timestamp, String _contactId, + String _contactName, byte[] _contactPhoto, int _unreadCount, + long _threadId, int _messageType) { + mContext = _context; + mFromAddress = _fromAddress; + mMessageBody = _messageBody == null ? "" : _messageBody; + mTimestamp = _timestamp; + mContactId = _contactId; + mContactName = _contactName; + mContactPhoto = _contactPhoto; + mUnreadCount = _unreadCount; + mThreadId = _threadId; + mMessageType = _messageType; + } + + public static SmsMmsMessage getSmsfromPDUs(Context context, Object[] pdus) { + SmsMessage[] msgs = new SmsMessage[pdus.length]; + String from; + StringBuilder body = new StringBuilder(); + long timestamp; + int msgtype = MESSAGE_TYPE_SMS; + // public SmsMmsMessage(Context _context, String _fromAddress, String + // _messageBody, + // long _timestamp, int _messageType) + for (int i = 0; i < msgs.length; i++) { + msgs[i] = SmsMessage.createFromPdu((byte[]) pdus[i]); + } + SmsMessage firstMessage = msgs[0]; + for (SmsMessage currentMessage : msgs) { + if (currentMessage.getDisplayOriginatingAddress().equals(firstMessage.getDisplayOriginatingAddress())) { + body.append(currentMessage.getDisplayMessageBody()); + } + } + timestamp = firstMessage.getTimestampMillis(); + from = firstMessage.getDisplayOriginatingAddress(); + return new SmsMmsMessage(context, from, body.toString(), timestamp, msgtype); + } + + /** + * Convert all SmsMmsMessage data to an extras bundle to send via an intent + */ + public Bundle toBundle() { + Bundle b = new Bundle(); + b.putString(EXTRAS_FROM_ADDRESS, mFromAddress); + b.putString(EXTRAS_MESSAGE_BODY, mMessageBody); + b.putLong(EXTRAS_TIMESTAMP, mTimestamp); + b.putString(EXTRAS_CONTACT_ID, mContactId); + b.putString(EXTRAS_CONTACT_NAME, mContactName); + b.putByteArray(EXTRAS_CONTACT_PHOTO, mContactPhoto); + b.putInt(EXTRAS_UNREAD_COUNT, mUnreadCount); + b.putLong(EXTRAS_THREAD_ID, mThreadId); + b.putInt(EXTRAS_MESSAGE_TYPE, mMessageType); + b.putBoolean(EXTRAS_NOTIFY, mNotify); + b.putInt(EXTRAS_REMINDER_COUNT, mReminderCount); + b.putLong(EXTRAS_MESSAGE_ID, mMessageId); + return b; + } + + public Bitmap getContactPhoto() { + if (mContactPhoto == null) + return null; + return BitmapFactory.decodeStream(new ByteArrayInputStream(mContactPhoto)); + } + + public int getUnreadCount() { + return mUnreadCount; + } + + public long getTimestamp() { + return mTimestamp; + } + + public CharSequence getFormattedTimestamp() { + /* + * No need for my own format function now, the 1.5 SDK has this built in + * (this will detect the system settings and return the correct format) + */ + // return SMSPopupUtils.formatTimestamp(context, timestamp); + return DateUtils.formatDateTime(mContext, mTimestamp, DateUtils.FORMAT_SHOW_TIME); + } + + public String getContactName() { + if (mContactName == null) { + mContactName = mContext.getString(android.R.string.unknownName); + } + return mContactName; + } + + public String getMessageBody() { + return mMessageBody; + } + + public long getThreadId() { + return mThreadId; + } + + public int getMessageType() { + return mMessageType; + } + + public boolean getNotify() { + return mNotify; + } + + public int getReminderCount() { + return mReminderCount; + } + + public void updateReminderCount(int count) { + mReminderCount = count; + } + + public void incrementReminderCount() { + mReminderCount++; + } + + public void setMessageId() { + mMessageId = SmsPopupUtils.findMessageId(mContext, mThreadId, mTimestamp, mMessageType); + } + + public long getMessageId() { + if (mMessageId == 0) { + setMessageId(); + } + return mMessageId; + } + + public String getContactId() { + return mContactId; + } + + // public boolean equals(SmsMmsMessage compareMessage) { + // boolean equals = false; + // if (PhoneNumberUtils.compare(this.fromAddress, + // compareMessage.fromAddress) && + // this.compareTimeStamp(compareMessage.timestamp) && + // this.messageType == compareMessage.messageType) { + // equals = true; + // } + // return equals; + // } + + /** + * Check if this message is sufficiently the same as the provided parameters + */ + public boolean equals(String fromAddress, long timestamp, + long timestamp_provider, String body) { + boolean equals = false; + + if (PhoneNumberUtils.compare(this.mFromAddress, fromAddress) + && this.compareTimeStamp(timestamp, timestamp_provider) + && this.compareBody(body)) { + equals = true; + } + return equals; + } + + // private boolean compareTimeStamp(long compareTimestamp) { + // return compareTimeStamp(compareTimestamp, 0); + // } + + /* + * Compares the timestamps of a message, this is super hacky because the way + * which builds of Android store SMS timestamps changed in the cupcake + * branch - pre-cupcake it stored the timestamp provided by the telecom + * provider; post-cupcake it stored the system timestamp. Unfortunately this + * means we need to use 2 different ways to determine if the received + * message timestamp is sufficiently equal to the database timestamp :( + */ + private boolean compareTimeStamp(long compareTimestamp, long providerTimestamp) { + + final int MESSAGE_COMPARE_TIME_BUFFER = 2000; + // final int buildVersion = Integer.valueOf(Build.VERSION.INCREMENTAL); + + /* + * On March 28th, 2009 - these are the latest builds that I could find: + * 128600 TMI-RC9 (Tmobile EU) 126986 PLAT-RC33 (Tmobile US) 129975 + * Emulator (from Android 1.1 SDK r1) Hopefully anything later will have + * the updated SMS code that uses the system timestamp rather than the + * SMS timestamp + */ + // final int LATEST_BUILD = 129975; + // boolean PRE_CUPCAKE = false; + // if (buildVersion <= LATEST_BUILD) { + // PRE_CUPCAKE = true; + // } + // + // Log.v("DB timestamp = " + timestamp); + // Log.v("Provider timestamp = " + providerTimestamp); + // Log.v("System timestamp = " + compareTimestamp); + + /* + * If pre-cupcake we can just do a direct comparison as the Mms app + * stores the timestamp from the telecom provider (in the sms pdu) + */ + // if (PRE_CUPCAKE) { + // Log.v("Build is pre-cupcake ("+buildVersion+"), doing direct SMS timestamp comparison"); + // Log.v("DB timestamp = " + timestamp); + // Log.v("Intent timestamp = " + providerTimestamp); + if (mTimestamp == providerTimestamp) { + // Log.v("SMS Compare: compareTimestamp() - intent timestamp = provider timestamp"); + return true; + } // else { + // return false; + // } + // } + + /* + * If post-cupcake, the system app stores a system timestamp - the only + * problem is we have no way of knowing the exact time the system app + * used. So what we'll do is compare against our own system timestamp + * and add a buffer in. This is an awful way of doing this, but I don't + * see any other way around it :( + */ + // Log.v("Build is post-cupcake ("+buildVersion+"), doing approx. SMS timestamp comparison"); + // Log.v("DB timestamp = " + timestamp); + // Log.v("Intent timestamp = " + compareTimestamp); + + if (mTimestamp < (compareTimestamp + MESSAGE_COMPARE_TIME_BUFFER) + && mTimestamp > (compareTimestamp - MESSAGE_COMPARE_TIME_BUFFER)) { + // Log.v("SMS Compare: compareTimestamp() - timestamp is approx. the same"); + return true; + } + // Log.v("SMS Compare: compareTimestamp() - return false"); + return false; + } + + /* + * Compare message body + */ + private boolean compareBody(String compareBody) { + if (compareBody != null) { + if (mMessageBody.length() != compareBody.length()) { + // Log.v("SMS Compare: compareBody() - length is different"); + return false; + } + + if (mMessageBody.equals(compareBody)) { + // Log.v("SMS Compare: compareBody() - messageBody is the same"); + return true; + } + } + // Log.v("SMS Compare: compareBody() - return false"); + return false; + } + + public boolean replyToMessage(String quickreply) { + // SmsMessageSender sender = + // new SmsMessageSender(context, new String[] {fromAddress}, quickreply, + // threadId); + // return sender.sendMessage(); + return false; + } +} diff --git a/src/org/xbmc/android/util/SmsPopupUtils.java b/app/src/main/java/org/xbmc/android/util/SmsPopupUtils.java similarity index 85% rename from src/org/xbmc/android/util/SmsPopupUtils.java rename to app/src/main/java/org/xbmc/android/util/SmsPopupUtils.java index 65d84240..085389fd 100644 --- a/src/org/xbmc/android/util/SmsPopupUtils.java +++ b/app/src/main/java/org/xbmc/android/util/SmsPopupUtils.java @@ -1,1024 +1,1018 @@ -package org.xbmc.android.util; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningTaskInfo; -import android.content.ComponentName; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.media.AudioManager; -import android.net.Uri; -import android.os.Build; -import android.preference.PreferenceManager; -import android.provider.Contacts; -import android.provider.Contacts.PeopleColumns; -import android.provider.Contacts.PhotosColumns; -import android.telephony.PhoneNumberUtils; -import android.telephony.TelephonyManager; -import android.telephony.gsm.SmsMessage; -import android.text.TextUtils; - -/** - * TODO Once we move to 1.6+, waste the deprecated code. - */ -@SuppressWarnings("deprecation") -public class SmsPopupUtils { - // Content URIs for SMS app, these may change in future SDK - - public static final Uri MMS_SMS_CONTENT_URI = Uri.parse("content://mms-sms/"); - public static final Uri THREAD_ID_CONTENT_URI = Uri.withAppendedPath(MMS_SMS_CONTENT_URI, "threadID"); - public static final Uri CONVERSATION_CONTENT_URI = Uri.withAppendedPath(MMS_SMS_CONTENT_URI, "conversations"); - - public static final Uri SMS_CONTENT_URI = Uri.parse("content://sms"); - public static final Uri SMS_INBOX_CONTENT_URI = Uri.withAppendedPath(SMS_CONTENT_URI, "inbox"); - - public static final Uri MMS_CONTENT_URI = Uri.parse("content://mms"); - public static final Uri MMS_INBOX_CONTENT_URI = Uri.withAppendedPath(MMS_CONTENT_URI, "inbox"); - - public static final String SMS_ID = "_id"; - public static final String SMS_TO_URI = "smsto:/"; - public static final String SMS_MIME_TYPE = "vnd.android-dir/mms-sms"; - - public static final int READ_THREAD = 1; - public static final int MESSAGE_TYPE_SMS = 1; - public static final int MESSAGE_TYPE_MMS = 2; - - private static final String AUTHOR_CONTACT_INFO = "Adam K "; - - /** - * Looks up a contacts display name by contact id - if not found, the - * address (phone number) will be formatted and returned instead. - */ - public static String getPersonName(Context context, String id, String address) { - if (id == null) { - if (address != null) { - // Log.v("Contact not found, formatting number"); - return PhoneNumberUtils.formatNumber(address); - } else { - return null; - } - } - - Cursor cursor = context.getContentResolver().query(Uri.withAppendedPath(Contacts.People.CONTENT_URI, id), - new String[] { PeopleColumns.DISPLAY_NAME }, null, null, null); - if (cursor != null) { - try { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - String name = cursor.getString(0); - // Log.v("Contact Display Name: " + name); - return name; - } - } finally { - cursor.close(); - } - } - - if (address != null) { - // Log.v("Contact not found, formatting number"); - return PhoneNumberUtils.formatNumber(address); - } - return null; - } - - /** - * Looks up a contacts id, given their address (phone number in this case). - * Returns null if not found - */ - public static String getPersonIdFromPhoneNumber(Context context, String address) { - if (address == null) - return null; - - Cursor cursor = context.getContentResolver().query( - Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, address), - new String[] { Contacts.Phones.PERSON_ID }, null, null, null); - if (cursor != null) { - try { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - Long id = Long.valueOf(cursor.getLong(0)); - // Log.v("Found person: " + id); - return (String.valueOf(id)); - } - } finally { - cursor.close(); - } - } - return null; - } - - /** - * Looks up a contats photo by their contact id, returns a byte array that - * represents their photo (or null if not found) - */ - public static byte[] getPersonPhoto(Context context, String id) { - if (id == null) - return null; - - if ("0".equals(id)) - return null; - - byte photo[] = null; - - // TODO: switch to API method: - // Contacts.People.loadContactPhoto(arg0, arg1, arg2, arg3) - - Cursor cursor = context.getContentResolver().query(Uri.withAppendedPath(Contacts.Photos.CONTENT_URI, id), - new String[] { PhotosColumns.DATA }, null, null, null); - if (cursor != null) { - try { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - photo = cursor.getBlob(0); - if (photo != null) { - return photo; - } - } - } finally { - cursor.close(); - } - } - return photo; - } - - /** - * Tries to locate the message thread id given the address (phone or email) - * of the message sender - */ - public static long getThreadIdFromAddress(Context context, String address) { - if (address == null) - return 0; - - String THREAD_RECIPIENT_QUERY = "recipient"; - - Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon(); - uriBuilder.appendQueryParameter(THREAD_RECIPIENT_QUERY, address); - - long threadId = 0; - - Cursor cursor = context.getContentResolver().query(uriBuilder.build(), new String[] { SMS_ID }, null, null, - null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - threadId = cursor.getLong(0); - } - } finally { - cursor.close(); - } - } - return threadId; - } - - /** - * Marks a specific message as read - */ - public static void setMessageRead(Context context, long messageId, int messageType) { - // SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); - // boolean markRead = myPrefs.getBoolean( - // context.getString(R.string.pref_markread_key), - // Boolean.valueOf(context.getString(R.string.pref_markread_default))); - boolean markRead = false; - - if (!markRead) - return; - - if (messageId > 0) { - ContentValues values = new ContentValues(1); - values.put("read", READ_THREAD); - - Uri messageUri; - - if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { - messageUri = Uri.withAppendedPath(MMS_CONTENT_URI, String.valueOf(messageId)); - } else if (SmsMmsMessage.MESSAGE_TYPE_SMS == messageType) { - messageUri = Uri.withAppendedPath(SMS_CONTENT_URI, String.valueOf(messageId)); - } else { - return; - } - - // Log.v("messageUri for marking message read: " + - // messageUri.toString()); - - ContentResolver cr = context.getContentResolver(); -// int result = 0; - try { -// result = cr.update(messageUri, values, null, null); - cr.update(messageUri, values, null, null); - } catch (Exception e) { - // Log.v("error marking message read"); - } - // Log.v("message id " + messageId + " marked as read, result = " + - // result); - } - } - - /** - * Marks a specific message thread as read - all messages in the thread will - * be marked read - */ - public static void setThreadRead(Context context, long threadId) { - //SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); - // boolean markRead = myPrefs.getBoolean( - // context.getString(R.string.pref_markread_key), - // Boolean.valueOf(context.getString(R.string.pref_markread_default))); - boolean markRead = false; - - if (!markRead) - return; - - if (threadId > 0) { - ContentValues values = new ContentValues(1); - values.put("read", READ_THREAD); - - ContentResolver cr = context.getContentResolver(); -// int result = 0; - try { -// result = cr.update(ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), values, null, null); - cr.update(ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), values, null, null); - } catch (Exception e) { - // Log.v("error marking thread read"); - } - // Log.v("thread id " + threadId + " marked as read, result = " + - // result); - } - } - - /** - * Tries to locate the message id (from the system database), given the - * message thread id, the timestamp of the message and the type of message - * (sms/mms) - */ - public static long findMessageId(Context context, long threadId, long _timestamp, int messageType) { - long id = 0; - long timestamp = _timestamp; - if (threadId > 0) { - // Log.v("Trying to find message ID"); - // It seems MMS timestamps are stored in a seconds, whereas SMS - // timestamps are in millis - if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { - timestamp = _timestamp / 1000; - // //Log.v("adjusted timestmap for MMS (" + _timestamp + " -> " - // + timestamp + ")"); - } - - Cursor cursor = context.getContentResolver().query( - ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), - new String[] { "_id", "date", "thread_id" }, - // "thread_id=" + threadId + " and " + "date=" + timestamp, - "date=" + timestamp, null, "date desc"); - - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - id = cursor.getLong(0); - // Log.v("Message id found = " + id); - } - } finally { - cursor.close(); - } - } - } - return id; - } - - /** - * Tries to delete a message from the system database, given the thread id, - * the timestamp of the message and the message type (sms/mms). - */ - public static void deleteMessage(Context context, long messageId, long threadId, int messageType) { - - if (messageId > 0) { - // Log.v("id of message to delete is " + messageId); - Uri deleteUri; - - if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { - deleteUri = Uri.withAppendedPath(MMS_CONTENT_URI, String.valueOf(messageId)); - } else if (SmsMmsMessage.MESSAGE_TYPE_SMS == messageType) { - deleteUri = Uri.withAppendedPath(SMS_CONTENT_URI, String.valueOf(messageId)); - } else { - return; - } - int count = context.getContentResolver().delete(deleteUri, null, null); - // Log.v("Messages deleted: " + count); - if (count == 1) { - // TODO: should only set the thread read if there are no more - // unread - // messages - setThreadRead(context, threadId); - } - } - } - - /** - * - */ - public static Intent getSmsIntent() { - Intent conversations = new Intent(Intent.ACTION_MAIN); - // conversations.addCategory(Intent.CATEGORY_DEFAULT); - conversations.setType(SMS_MIME_TYPE); - // should I be using FLAG_ACTIVITY_RESET_TASK_IF_NEEDED?? - int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP; - conversations.setFlags(flags); - - return conversations; - } - - /** - * - */ - public static Intent getSmsToIntentFromThreadId(Context context, long threadId) { - Intent popup = new Intent(Intent.ACTION_VIEW); - // should I be using FLAG_ACTIVITY_RESET_TASK_IF_NEEDED?? - int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP; - popup.setFlags(flags); - if (threadId > 0) { - // //Log.v("^^Found threadId (" + threadId + - // "), sending to Sms intent"); - popup.setData(Uri.withAppendedPath(THREAD_ID_CONTENT_URI, String.valueOf(threadId))); - } else { - return getSmsIntent(); - } - return popup; - } - - /** - * - */ - public static void launchEmailToIntent(Context context, String subject, boolean includeDebug) { - Intent msg = new Intent(Intent.ACTION_SEND); - String[] recipients = { AUTHOR_CONTACT_INFO }; - - String body = ""; - - if (includeDebug) { - body = "\n\n----------\nSysinfo - " + Build.FINGERPRINT + "\n" + "Model: " + Build.MODEL + "\n\n"; - - // Array of preference keys to include in email - String[] pref_keys = { - // context.getString(R.string.pref_enabled_key), - // context.getString(R.string.pref_timeout_key), - // context.getString(R.string.pref_privacy_key), - // context.getString(R.string.pref_dimscreen_key), - // context.getString(R.string.pref_markread_key), - // context.getString(R.string.pref_onlyShowOnKeyguard_key), - // context.getString(R.string.pref_show_delete_button_key), - // context.getString(R.string.pref_blur_key), - // context.getString(R.string.pref_notif_enabled_key), - // context.getString(R.string.pref_notif_sound_key), - // context.getString(R.string.pref_vibrate_key), - // context.getString(R.string.pref_vibrate_pattern_key), - // context.getString(R.string.pref_vibrate_pattern_custom_key), - // context.getString(R.string.pref_flashled_key), - // context.getString(R.string.pref_flashled_color_key), - // context.getString(R.string.pref_notif_repeat_key), - // context.getString(R.string.pref_notif_repeat_times_key), - // context.getString(R.string.pref_notif_repeat_interval_key), - }; - - SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); - Map m = myPrefs.getAll(); - - body += subject + " config -\n"; - for (int i = 0; i < pref_keys.length; i++) { - try { - body += pref_keys[i] + ": " + String.valueOf(m.get(pref_keys[i])) + "\n"; - } catch (NullPointerException e) { - // Nothing to do here - } - } - - // Add locale info - body += "locale: " + context.getResources().getConfiguration().locale.getDisplayName() + "\n"; - - // Add audio info - AudioManager AM = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); - - String audioMode = "audio_mode: "; - switch (AM.getMode()) { - case AudioManager.MODE_NORMAL: - audioMode += "MODE_NORMAL"; - break; - case AudioManager.MODE_IN_CALL: - audioMode += "MODE_IN_CALL"; - break; - case AudioManager.MODE_RINGTONE: - audioMode += "MODE_RINGTONE"; - break; - default: - audioMode += "MODE is UNKNOWN"; - break; - } - body += audioMode + "\n"; - - String audioRouting = "audio_routing: "; - switch (AM.getRouting(AudioManager.MODE_NORMAL)) { - case AudioManager.ROUTE_SPEAKER: - audioRouting += "ROUTE_SPEAKER"; - break; - case AudioManager.ROUTE_BLUETOOTH: - audioRouting += "ROUTE_BLUETOOTH"; - break; - case AudioManager.ROUTE_HEADSET: - audioRouting += "ROUTE_HEADSET"; - break; - default: - audioRouting += "ROUTE is UNKNOWN"; - break; - } - body += audioRouting + "\n"; - - TelephonyManager TM = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - String callState = "call state: "; - switch (TM.getCallState()) { - case TelephonyManager.CALL_STATE_IDLE: - callState += "CALL_STATE_IDLE"; - break; - case TelephonyManager.CALL_STATE_OFFHOOK: - callState += "CALL_STATE_OFFHOOK"; - break; - case TelephonyManager.CALL_STATE_RINGING: - callState += "CALL_STATE_RINGING"; - break; - default: - callState += "CALL_STATE is UNKNOWN"; - break; - } - body += callState + "\n"; - - } - - msg.putExtra(Intent.EXTRA_EMAIL, recipients); - msg.putExtra(Intent.EXTRA_SUBJECT, subject); - msg.putExtra(Intent.EXTRA_TEXT, body); - - msg.setType("message/rfc822"); - context.startActivity(Intent.createChooser(msg, "Send E-mail")); - } - - public static int getUnreadMessagesCount(Context context, long timestamp) { - int unreadSms = getUnreadSmsCount(context, timestamp); - int unreadMms = getUnreadMmsCount(context); - return (unreadSms + unreadMms); - } - - public static int getUnreadMessagesCount(Context context) { - return getUnreadMessagesCount(context, 0); - // int unreadSms = getUnreadSmsCount(context); - // int unreadMms = getUnreadMmsCount(context); - // return (unreadSms + unreadMms); - } - - public static SmsMmsMessage getSmsDetailsById(Context context, int id) { - // public SmsMmsMessage(Context _context, String _fromAddress, String - // _contactId, - // String _messageBody, long _timestamp, long _threadId, - // int _unreadCount, long _messageId, int _messageType) - SmsMmsMessage msg = null; - String SORT_ORDER = "date DESC"; - String WHERE_CONDITION = "_id=" + id; - Cursor cursor = context.getContentResolver().query( - SMS_INBOX_CONTENT_URI, - new String[] { SMSConstants.ID, SMSConstants.THREAD_ID, SMSConstants.ADDRESS, SMSConstants.PERSON, - SMSConstants.DATE, SMSConstants.BODY }, WHERE_CONDITION, null, SORT_ORDER); - if (cursor != null && cursor.moveToFirst()) { - try { - - long messageId = cursor.getLong(0); - long threadId = cursor.getLong(1); - String address = cursor.getString(2); - long contactId = cursor.getLong(3); - String contactId_string = String.valueOf(contactId); - long timestamp = cursor.getLong(4); - - String body = cursor.getString(5); - - msg = new SmsMmsMessage(context, address, contactId_string, body, timestamp, threadId, 0, // TODO - // evaluate - // the - // real - // unread - // count. - // currently - // not - // needed - messageId, SmsMmsMessage.MESSAGE_TYPE_SMS); - } finally { - cursor.close(); - } - } - return msg; - } - - public static int getSmsInboxCount(Context context) { - - int count = 0; - - Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[] { SMS_ID }, null, null, - null); - - if (cursor != null) { - try { - count = cursor.getCount(); - } finally { - cursor.close(); - } - } - return count; - } - - public static int[] getSmsIdsFromInbox(Context context) { - int[] ids = null; - - Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[] { SMS_ID }, null, null, - null); - if (cursor != null && cursor.moveToFirst()) { - try { - ids = new int[cursor.getCount()]; - int i = 0; - do { - ids[i++] = cursor.getInt(0); - } while (cursor.moveToNext()); - } finally { - cursor.close(); - } - } - - return ids; - } - - public static SmsMmsMessage getLastSmsFromInbox(Context context) { - return getSmsDetailsById(context, getSmsIdsFromInbox(context)[0]); - } - - public static int getUnreadSmsCount(Context context) { - return getUnreadSmsCount(context, 0); - // String SMS_READ_COLUMN = "read"; - // String UNREAD_CONDITION = SMS_READ_COLUMN + "=0"; - // - // int count = 0; - // - // Cursor cursor = context.getContentResolver().query( - // SMS_INBOX_CONTENT_URI, - // new String[] { SMS_ID }, - // UNREAD_CONDITION, null, null); - // - // if (cursor != null) { - // try { - // count = cursor.getCount(); - // } finally { - // cursor.close(); - // } - // } - // //Log.v("sms unread count = " + count); - // return count; - } - - public static int getUnreadSmsCount(Context context, long timestamp) { - String SMS_READ_COLUMN = "read"; - String UNREAD_CONDITION = SMS_READ_COLUMN + "=0"; - - if (timestamp > 0) { - // Log.v("getUnreadSmsCount(), timestamp = " + timestamp); - UNREAD_CONDITION += " and date<" + String.valueOf(timestamp); - } - - int count = 0; - - Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[] { SMS_ID }, - UNREAD_CONDITION, null, null); - - if (cursor != null) { - try { - count = cursor.getCount(); - } finally { - cursor.close(); - } - } - - // We ignored the latest incoming message so add one to the total count - if (timestamp > 0) { - // Log.v("adding 1 to unread, previous count was " + count); - count += 1; - } - - // Log.v("sms unread count = " + count); - return count; - } - - public static int getUnreadMmsCount(Context context) { - - String MMS_READ_COLUMN = "read"; - String UNREAD_CONDITION = MMS_READ_COLUMN + "=0"; - - int count = 0; - - Cursor cursor = context.getContentResolver().query(MMS_INBOX_CONTENT_URI, new String[] { SMS_ID }, - UNREAD_CONDITION, null, null); - - if (cursor != null) { - try { - count = cursor.getCount(); - } finally { - cursor.close(); - } - } - // Log.v("mms unread count = " + count); - return count; - } - - /* - * - */ - public static SmsMmsMessage getSmsDetails(Context context, long ignoreThreadId, boolean unreadOnly) { - - String SMS_READ_COLUMN = "read"; - String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null; - String SORT_ORDER = "date DESC"; - int count = 0; - - // //Log.v(WHERE_CONDITION); - - if (ignoreThreadId > 0) { - // //Log.v("Ignoring sms threadId = " + ignoreThreadId); - WHERE_CONDITION += " AND thread_id != " + ignoreThreadId; - } - - Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, - new String[] { "_id", "thread_id", "address", "person", "date", "body" }, WHERE_CONDITION, null, - SORT_ORDER); - - if (cursor != null) { - try { - count = cursor.getCount(); - if (count > 0) { - cursor.moveToFirst(); - - // String[] columns = cursor.getColumnNames(); - // for (int i=0; i 0) { - // //Log.v("Ignoring mms threadId = " + ignoreThreadId); - UNREAD_CONDITION += " AND thread_id != " + ignoreThreadId; - } - - Cursor cursor = context.getContentResolver().query(MMS_INBOX_CONTENT_URI, - // new String[] { "m_id", "\"from\"", "sub", "d_tm", "thread_id" }, - new String[] { "_id", "thread_id", "date", "sub", "sub_cs" }, UNREAD_CONDITION, null, SORT_ORDER); - - if (cursor != null) { - try { - count = cursor.getCount(); - if (count > 0) { - cursor.moveToFirst(); - // String[] columns = cursor.getColumnNames(); - // for (int i=0; i\"]+)\\s*<([^<>]+)>\\s*"); - - public static final Pattern QUOTED_STRING_PATTERN = Pattern.compile("\\s*\"([^\"]*)\"\\s*"); - - private static String getEmailDisplayName(String displayString) { - Matcher match = QUOTED_STRING_PATTERN.matcher(displayString); - if (match.matches()) { - return match.group(1); - } - - return displayString; - } - - private static String getDisplayName(Context context, String email) { - Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(email); - if (match.matches()) { - // email has display name, return that - return getEmailDisplayName(match.group(1)); - } - - // otherwise let's check the contacts list for a user with this email - Cursor cursor = context.getContentResolver().query(Contacts.ContactMethods.CONTENT_EMAIL_URI, - new String[] { Contacts.ContactMethods.NAME }, Contacts.ContactMethods.DATA + " = \'" + email + "\'", - null, null); - - if (cursor != null) { - try { - int columnIndex = cursor.getColumnIndexOrThrow(Contacts.ContactMethods.NAME); - while (cursor.moveToNext()) { - String name = cursor.getString(columnIndex); - if (!TextUtils.isEmpty(name)) { - return name; - } - } - } finally { - cursor.close(); - } - } - return email; - } - - /* - * Get the most recent unread message, returning in a SmsMmsMessage which is - * suitable for updating the notification. Optional param is the message - * object: we can pull out the thread id of this message in the case the - * user is "replying" to the message and we should ignore all messages in - * the thread when working out what to display in the notification bar (as - * these messages will soon be marked read but we can't be sure when the - * messaging app will actually start). - */ - public static SmsMmsMessage getRecentMessage(Context context, SmsMmsMessage ignoreMessage) { - long ignoreThreadId = 0; - - if (ignoreMessage != null) { - ignoreThreadId = ignoreMessage.getThreadId(); - } - - SmsMmsMessage smsMessage = getSmsDetails(context, ignoreThreadId); - SmsMmsMessage mmsMessage = getMmsDetails(context, ignoreThreadId); - - if (mmsMessage == null && smsMessage != null) { - return smsMessage; - } - - if (mmsMessage != null && smsMessage == null) { - return mmsMessage; - } - - if (mmsMessage != null && smsMessage != null) { - if (mmsMessage.getTimestamp() < smsMessage.getTimestamp()) { - return mmsMessage; - } - return smsMessage; - } - - return null; - } - - public static SmsMmsMessage getRecentMessage(Context context) { - return getRecentMessage(context, null); - } - - /** - * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a - * {@link #DATA_SMS_RECEIVED_ACTION} intent. - * - * @param intent - * the intent to read from - * @return an array of SmsMessages for the PDUs - */ - public static final SmsMessage[] getMessagesFromIntent(Intent intent) { - Object[] messages = (Object[]) intent.getSerializableExtra("pdus"); - if (messages == null) { - return null; - } - if (messages.length == 0) { - return null; - } - - byte[][] pduObjs = new byte[messages.length][]; - - for (int i = 0; i < messages.length; i++) { - pduObjs[i] = (byte[]) messages[i]; - } - byte[][] pdus = new byte[pduObjs.length][]; - int pduCount = pdus.length; - SmsMessage[] msgs = new SmsMessage[pduCount]; - for (int i = 0; i < pduCount; i++) { - pdus[i] = pduObjs[i]; - msgs[i] = SmsMessage.createFromPdu(pdus[i]); - } - return msgs; - } - - /** - * This function will see if the most recent activity was the system - * messaging app so we can suppress the popup as the user is likely already - * viewing messages or composing a new message - */ - public static final boolean inMessagingApp(Context context) { - // TODO: move these to static strings somewhere - final String PACKAGE_NAME = "com.android.mms"; - // final String COMPOSE_CLASS_NAME = - // "com.android.mms.ui.ComposeMessageActivity"; - final String CONVO_CLASS_NAME = "com.android.mms.ui.ConversationList"; - - ActivityManager mAM = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - - List mRunningTaskList = mAM.getRunningTasks(1); - Iterator mIterator = mRunningTaskList.iterator(); - if (mIterator.hasNext()) { - RunningTaskInfo mRunningTask = mIterator.next(); - if (mRunningTask != null) { - ComponentName runningTaskComponent = mRunningTask.baseActivity; - - // //Log.v("baseActivity = " + - // mRunningTask.baseActivity.toString()); - // //Log.v("topActivity = " + - // mRunningTask.topActivity.toString()); - - if (PACKAGE_NAME.equals(runningTaskComponent.getPackageName()) - && CONVO_CLASS_NAME.equals(runningTaskComponent.getClassName())) { - // Log.v("User in messaging app - from running task"); - return true; - } - } - } - - /* - * List mActivityList = mAM.getRecentTasks(1, 0); - * Iterator mIterator = mActivityList.iterator(); - * - * if (mIterator.hasNext()) { RecentTaskInfo mRecentTask = - * (RecentTaskInfo) mIterator.next(); Intent recentTaskIntent = - * mRecentTask.baseIntent; - * - * if (recentTaskIntent != null) { ComponentName recentTaskComponentName - * = recentTaskIntent.getComponent(); if (recentTaskComponentName != - * null) { String recentTaskClassName = - * recentTaskComponentName.getClassName(); if - * (PACKAGE_NAME.equals(recentTaskComponentName.getPackageName()) && - * (COMPOSE_CLASS_NAME.equals(recentTaskClassName) || - * CONVO_CLASS_NAME.equals(recentTaskClassName))) { - * //Log.v("User in messaging app"); return true; } } } } - */ - - /* - * These appear to be the 2 main intents that mean the user is using the - * messaging app - * - * action "android.intent.action.MAIN" data null class - * "com.android.mms.ui.ConversationList" package "com.android.mms" - * - * action "android.intent.action.VIEW" data - * "content://mms-sms/threadID/3" class - * "com.android.mms.ui.ComposeMessageActivity" package "com.android.mms" - */ - - return false; - } - - /** - * Enables or disables the main SMS receiver - */ - public static void enableSMSPopup(Context context, boolean enable) { - // PackageManager pm = context.getPackageManager(); - // ComponentName cn = new ComponentName(context, SmsReceiver.class); - // - // // Update preference so it reflects in the preference activity - // SharedPreferences myPrefs = - // PreferenceManager.getDefaultSharedPreferences(context); - // SharedPreferences.Editor settings = myPrefs.edit(); - // settings.putBoolean(context.getString(R.string.pref_enabled_key), - // enable); - // settings.commit(); - // - // if (enable) { - // //Log.v("SMSPopup receiver is enabled"); - // pm.setComponentEnabledSetting(cn, - // PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, - // PackageManager.DONT_KILL_APP); - // - // // Send a broadcast to disable other SMS Popup apps - // disableOtherSMSPopup(context); - // - // } else { - // //Log.v("SMSPopup receiver is disabled"); - // pm.setComponentEnabledSetting(cn, - // PackageManager.COMPONENT_ENABLED_STATE_DISABLED, - // PackageManager.DONT_KILL_APP); - // } - } - - public static void disableOtherSMSPopup(Context context) { - // Send a broadcast to disable SMS Popup Pro - // Intent i = new Intent(ExternalEventReceiver.ACTION_SMSPOPUP_DISABLE); - // i.setClassName("net.everythingandroid.smspopuppro", - // "net.everythingandroid.smspopuppro.ExternalEventReceiver"); - // context.sendBroadcast(i); - } -} +package org.xbmc.android.util; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningTaskInfo; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Build; +import android.preference.PreferenceManager; +import android.provider.Contacts; +import android.provider.Contacts.PeopleColumns; +import android.provider.Contacts.PhotosColumns; +import android.telephony.PhoneNumberUtils; +import android.telephony.TelephonyManager; +import android.telephony.gsm.SmsMessage; +import android.text.TextUtils; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * TODO Once we move to 1.6+, waste the deprecated code. + */ +@SuppressWarnings("deprecation") +public class SmsPopupUtils { + // Content URIs for SMS app, these may change in future SDK + + public static final Uri MMS_SMS_CONTENT_URI = Uri.parse("content://mms-sms/"); + public static final Uri THREAD_ID_CONTENT_URI = Uri.withAppendedPath(MMS_SMS_CONTENT_URI, "threadID"); + public static final Uri CONVERSATION_CONTENT_URI = Uri.withAppendedPath(MMS_SMS_CONTENT_URI, "conversations"); + + public static final Uri SMS_CONTENT_URI = Uri.parse("content://sms"); + public static final Uri SMS_INBOX_CONTENT_URI = Uri.withAppendedPath(SMS_CONTENT_URI, "inbox"); + + public static final Uri MMS_CONTENT_URI = Uri.parse("content://mms"); + public static final Uri MMS_INBOX_CONTENT_URI = Uri.withAppendedPath(MMS_CONTENT_URI, "inbox"); + + public static final String SMS_ID = "_id"; + public static final String SMS_TO_URI = "smsto:/"; + public static final String SMS_MIME_TYPE = "vnd.android-dir/mms-sms"; + + public static final int READ_THREAD = 1; + public static final int MESSAGE_TYPE_SMS = 1; + public static final int MESSAGE_TYPE_MMS = 2; + public static final Pattern NAME_ADDR_EMAIL_PATTERN = Pattern + .compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*"); + public static final Pattern QUOTED_STRING_PATTERN = Pattern.compile("\\s*\"([^\"]*)\"\\s*"); + private static final String AUTHOR_CONTACT_INFO = "Adam K "; + + /** + * Looks up a contacts display name by contact id - if not found, the + * address (phone number) will be formatted and returned instead. + */ + public static String getPersonName(Context context, String id, String address) { + if (id == null) { + if (address != null) { + // Log.v("Contact not found, formatting number"); + return PhoneNumberUtils.formatNumber(address); + } else { + return null; + } + } + + Cursor cursor = context.getContentResolver().query(Uri.withAppendedPath(Contacts.People.CONTENT_URI, id), + new String[]{PeopleColumns.DISPLAY_NAME}, null, null, null); + if (cursor != null) { + try { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + String name = cursor.getString(0); + // Log.v("Contact Display Name: " + name); + return name; + } + } finally { + cursor.close(); + } + } + + if (address != null) { + // Log.v("Contact not found, formatting number"); + return PhoneNumberUtils.formatNumber(address); + } + return null; + } + + /** + * Looks up a contacts id, given their address (phone number in this case). + * Returns null if not found + */ + public static String getPersonIdFromPhoneNumber(Context context, String address) { + if (address == null) + return null; + + Cursor cursor = context.getContentResolver().query( + Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, address), + new String[]{Contacts.Phones.PERSON_ID}, null, null, null); + if (cursor != null) { + try { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + Long id = Long.valueOf(cursor.getLong(0)); + // Log.v("Found person: " + id); + return (String.valueOf(id)); + } + } finally { + cursor.close(); + } + } + return null; + } + + /** + * Looks up a contats photo by their contact id, returns a byte array that + * represents their photo (or null if not found) + */ + public static byte[] getPersonPhoto(Context context, String id) { + if (id == null) + return null; + + if ("0".equals(id)) + return null; + + byte photo[] = null; + + // TODO: switch to API method: + // Contacts.People.loadContactPhoto(arg0, arg1, arg2, arg3) + + Cursor cursor = context.getContentResolver().query(Uri.withAppendedPath(Contacts.Photos.CONTENT_URI, id), + new String[]{PhotosColumns.DATA}, null, null, null); + if (cursor != null) { + try { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + photo = cursor.getBlob(0); + if (photo != null) { + return photo; + } + } + } finally { + cursor.close(); + } + } + return photo; + } + + /** + * Tries to locate the message thread id given the address (phone or email) + * of the message sender + */ + public static long getThreadIdFromAddress(Context context, String address) { + if (address == null) + return 0; + + String THREAD_RECIPIENT_QUERY = "recipient"; + + Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon(); + uriBuilder.appendQueryParameter(THREAD_RECIPIENT_QUERY, address); + + long threadId = 0; + + Cursor cursor = context.getContentResolver().query(uriBuilder.build(), new String[]{SMS_ID}, null, null, + null); + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + threadId = cursor.getLong(0); + } + } finally { + cursor.close(); + } + } + return threadId; + } + + /** + * Marks a specific message as read + */ + public static void setMessageRead(Context context, long messageId, int messageType) { + // SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); + // boolean markRead = myPrefs.getBoolean( + // context.getString(R.string.pref_markread_key), + // Boolean.valueOf(context.getString(R.string.pref_markread_default))); + boolean markRead = false; + + if (!markRead) + return; + + if (messageId > 0) { + ContentValues values = new ContentValues(1); + values.put("read", READ_THREAD); + + Uri messageUri; + + if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { + messageUri = Uri.withAppendedPath(MMS_CONTENT_URI, String.valueOf(messageId)); + } else if (SmsMmsMessage.MESSAGE_TYPE_SMS == messageType) { + messageUri = Uri.withAppendedPath(SMS_CONTENT_URI, String.valueOf(messageId)); + } else { + return; + } + + // Log.v("messageUri for marking message read: " + + // messageUri.toString()); + + ContentResolver cr = context.getContentResolver(); +// int result = 0; + try { +// result = cr.update(messageUri, values, null, null); + cr.update(messageUri, values, null, null); + } catch (Exception e) { + // Log.v("error marking message read"); + } + // Log.v("message id " + messageId + " marked as read, result = " + + // result); + } + } + + /** + * Marks a specific message thread as read - all messages in the thread will + * be marked read + */ + public static void setThreadRead(Context context, long threadId) { + //SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); + // boolean markRead = myPrefs.getBoolean( + // context.getString(R.string.pref_markread_key), + // Boolean.valueOf(context.getString(R.string.pref_markread_default))); + boolean markRead = false; + + if (!markRead) + return; + + if (threadId > 0) { + ContentValues values = new ContentValues(1); + values.put("read", READ_THREAD); + + ContentResolver cr = context.getContentResolver(); +// int result = 0; + try { +// result = cr.update(ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), values, null, null); + cr.update(ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), values, null, null); + } catch (Exception e) { + // Log.v("error marking thread read"); + } + // Log.v("thread id " + threadId + " marked as read, result = " + + // result); + } + } + + /** + * Tries to locate the message id (from the system database), given the + * message thread id, the timestamp of the message and the type of message + * (sms/mms) + */ + public static long findMessageId(Context context, long threadId, long _timestamp, int messageType) { + long id = 0; + long timestamp = _timestamp; + if (threadId > 0) { + // Log.v("Trying to find message ID"); + // It seems MMS timestamps are stored in a seconds, whereas SMS + // timestamps are in millis + if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { + timestamp = _timestamp / 1000; + // //Log.v("adjusted timestmap for MMS (" + _timestamp + " -> " + // + timestamp + ")"); + } + + Cursor cursor = context.getContentResolver().query( + ContentUris.withAppendedId(CONVERSATION_CONTENT_URI, threadId), + new String[]{"_id", "date", "thread_id"}, + // "thread_id=" + threadId + " and " + "date=" + timestamp, + "date=" + timestamp, null, "date desc"); + + if (cursor != null) { + try { + if (cursor.moveToFirst()) { + id = cursor.getLong(0); + // Log.v("Message id found = " + id); + } + } finally { + cursor.close(); + } + } + } + return id; + } + + /** + * Tries to delete a message from the system database, given the thread id, + * the timestamp of the message and the message type (sms/mms). + */ + public static void deleteMessage(Context context, long messageId, long threadId, int messageType) { + + if (messageId > 0) { + // Log.v("id of message to delete is " + messageId); + Uri deleteUri; + + if (SmsMmsMessage.MESSAGE_TYPE_MMS == messageType) { + deleteUri = Uri.withAppendedPath(MMS_CONTENT_URI, String.valueOf(messageId)); + } else if (SmsMmsMessage.MESSAGE_TYPE_SMS == messageType) { + deleteUri = Uri.withAppendedPath(SMS_CONTENT_URI, String.valueOf(messageId)); + } else { + return; + } + int count = context.getContentResolver().delete(deleteUri, null, null); + // Log.v("Messages deleted: " + count); + if (count == 1) { + // TODO: should only set the thread read if there are no more + // unread + // messages + setThreadRead(context, threadId); + } + } + } + + /** + * + */ + public static Intent getSmsIntent() { + Intent conversations = new Intent(Intent.ACTION_MAIN); + // conversations.addCategory(Intent.CATEGORY_DEFAULT); + conversations.setType(SMS_MIME_TYPE); + // should I be using FLAG_ACTIVITY_RESET_TASK_IF_NEEDED?? + int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP; + conversations.setFlags(flags); + + return conversations; + } + + /** + * + */ + public static Intent getSmsToIntentFromThreadId(Context context, long threadId) { + Intent popup = new Intent(Intent.ACTION_VIEW); + // should I be using FLAG_ACTIVITY_RESET_TASK_IF_NEEDED?? + int flags = Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP; + popup.setFlags(flags); + if (threadId > 0) { + // //Log.v("^^Found threadId (" + threadId + + // "), sending to Sms intent"); + popup.setData(Uri.withAppendedPath(THREAD_ID_CONTENT_URI, String.valueOf(threadId))); + } else { + return getSmsIntent(); + } + return popup; + } + + /** + * + */ + public static void launchEmailToIntent(Context context, String subject, boolean includeDebug) { + Intent msg = new Intent(Intent.ACTION_SEND); + String[] recipients = {AUTHOR_CONTACT_INFO}; + + String body = ""; + + if (includeDebug) { + body = "\n\n----------\nSysinfo - " + Build.FINGERPRINT + "\n" + "Model: " + Build.MODEL + "\n\n"; + + // Array of preference keys to include in email + String[] pref_keys = { + // context.getString(R.string.pref_enabled_key), + // context.getString(R.string.pref_timeout_key), + // context.getString(R.string.pref_privacy_key), + // context.getString(R.string.pref_dimscreen_key), + // context.getString(R.string.pref_markread_key), + // context.getString(R.string.pref_onlyShowOnKeyguard_key), + // context.getString(R.string.pref_show_delete_button_key), + // context.getString(R.string.pref_blur_key), + // context.getString(R.string.pref_notif_enabled_key), + // context.getString(R.string.pref_notif_sound_key), + // context.getString(R.string.pref_vibrate_key), + // context.getString(R.string.pref_vibrate_pattern_key), + // context.getString(R.string.pref_vibrate_pattern_custom_key), + // context.getString(R.string.pref_flashled_key), + // context.getString(R.string.pref_flashled_color_key), + // context.getString(R.string.pref_notif_repeat_key), + // context.getString(R.string.pref_notif_repeat_times_key), + // context.getString(R.string.pref_notif_repeat_interval_key), + }; + + SharedPreferences myPrefs = PreferenceManager.getDefaultSharedPreferences(context); + Map m = myPrefs.getAll(); + + body += subject + " config -\n"; + for (int i = 0; i < pref_keys.length; i++) { + try { + body += pref_keys[i] + ": " + String.valueOf(m.get(pref_keys[i])) + "\n"; + } catch (NullPointerException e) { + // Nothing to do here + } + } + + // Add locale info + body += "locale: " + context.getResources().getConfiguration().locale.getDisplayName() + "\n"; + + // Add audio info + AudioManager AM = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + + String audioMode = "audio_mode: "; + switch (AM.getMode()) { + case AudioManager.MODE_NORMAL: + audioMode += "MODE_NORMAL"; + break; + case AudioManager.MODE_IN_CALL: + audioMode += "MODE_IN_CALL"; + break; + case AudioManager.MODE_RINGTONE: + audioMode += "MODE_RINGTONE"; + break; + default: + audioMode += "MODE is UNKNOWN"; + break; + } + body += audioMode + "\n"; + + String audioRouting = "audio_routing: "; + switch (AM.getRouting(AudioManager.MODE_NORMAL)) { + case AudioManager.ROUTE_SPEAKER: + audioRouting += "ROUTE_SPEAKER"; + break; + case AudioManager.ROUTE_BLUETOOTH: + audioRouting += "ROUTE_BLUETOOTH"; + break; + case AudioManager.ROUTE_HEADSET: + audioRouting += "ROUTE_HEADSET"; + break; + default: + audioRouting += "ROUTE is UNKNOWN"; + break; + } + body += audioRouting + "\n"; + + TelephonyManager TM = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + String callState = "call state: "; + switch (TM.getCallState()) { + case TelephonyManager.CALL_STATE_IDLE: + callState += "CALL_STATE_IDLE"; + break; + case TelephonyManager.CALL_STATE_OFFHOOK: + callState += "CALL_STATE_OFFHOOK"; + break; + case TelephonyManager.CALL_STATE_RINGING: + callState += "CALL_STATE_RINGING"; + break; + default: + callState += "CALL_STATE is UNKNOWN"; + break; + } + body += callState + "\n"; + + } + + msg.putExtra(Intent.EXTRA_EMAIL, recipients); + msg.putExtra(Intent.EXTRA_SUBJECT, subject); + msg.putExtra(Intent.EXTRA_TEXT, body); + + msg.setType("message/rfc822"); + context.startActivity(Intent.createChooser(msg, "Send E-mail")); + } + + public static int getUnreadMessagesCount(Context context, long timestamp) { + int unreadSms = getUnreadSmsCount(context, timestamp); + int unreadMms = getUnreadMmsCount(context); + return (unreadSms + unreadMms); + } + + public static int getUnreadMessagesCount(Context context) { + return getUnreadMessagesCount(context, 0); + // int unreadSms = getUnreadSmsCount(context); + // int unreadMms = getUnreadMmsCount(context); + // return (unreadSms + unreadMms); + } + + public static SmsMmsMessage getSmsDetailsById(Context context, int id) { + // public SmsMmsMessage(Context _context, String _fromAddress, String + // _contactId, + // String _messageBody, long _timestamp, long _threadId, + // int _unreadCount, long _messageId, int _messageType) + SmsMmsMessage msg = null; + String SORT_ORDER = "date DESC"; + String WHERE_CONDITION = "_id=" + id; + Cursor cursor = context.getContentResolver().query( + SMS_INBOX_CONTENT_URI, + new String[]{SMSConstants.ID, SMSConstants.THREAD_ID, SMSConstants.ADDRESS, SMSConstants.PERSON, + SMSConstants.DATE, SMSConstants.BODY}, WHERE_CONDITION, null, SORT_ORDER + ); + if (cursor != null && cursor.moveToFirst()) { + try { + + long messageId = cursor.getLong(0); + long threadId = cursor.getLong(1); + String address = cursor.getString(2); + long contactId = cursor.getLong(3); + String contactId_string = String.valueOf(contactId); + long timestamp = cursor.getLong(4); + + String body = cursor.getString(5); + + msg = new SmsMmsMessage(context, address, contactId_string, body, timestamp, threadId, 0, // TODO + // evaluate + // the + // real + // unread + // count. + // currently + // not + // needed + messageId, SmsMmsMessage.MESSAGE_TYPE_SMS); + } finally { + cursor.close(); + } + } + return msg; + } + + public static int getSmsInboxCount(Context context) { + + int count = 0; + + Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[]{SMS_ID}, null, null, + null); + + if (cursor != null) { + try { + count = cursor.getCount(); + } finally { + cursor.close(); + } + } + return count; + } + + public static int[] getSmsIdsFromInbox(Context context) { + int[] ids = null; + + Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[]{SMS_ID}, null, null, + null); + if (cursor != null && cursor.moveToFirst()) { + try { + ids = new int[cursor.getCount()]; + int i = 0; + do { + ids[i++] = cursor.getInt(0); + } while (cursor.moveToNext()); + } finally { + cursor.close(); + } + } + + return ids; + } + + public static SmsMmsMessage getLastSmsFromInbox(Context context) { + return getSmsDetailsById(context, getSmsIdsFromInbox(context)[0]); + } + + public static int getUnreadSmsCount(Context context) { + return getUnreadSmsCount(context, 0); + // String SMS_READ_COLUMN = "read"; + // String UNREAD_CONDITION = SMS_READ_COLUMN + "=0"; + // + // int count = 0; + // + // Cursor cursor = context.getContentResolver().query( + // SMS_INBOX_CONTENT_URI, + // new String[] { SMS_ID }, + // UNREAD_CONDITION, null, null); + // + // if (cursor != null) { + // try { + // count = cursor.getCount(); + // } finally { + // cursor.close(); + // } + // } + // //Log.v("sms unread count = " + count); + // return count; + } + + public static int getUnreadSmsCount(Context context, long timestamp) { + String SMS_READ_COLUMN = "read"; + String UNREAD_CONDITION = SMS_READ_COLUMN + "=0"; + + if (timestamp > 0) { + // Log.v("getUnreadSmsCount(), timestamp = " + timestamp); + UNREAD_CONDITION += " and date<" + String.valueOf(timestamp); + } + + int count = 0; + + Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, new String[]{SMS_ID}, + UNREAD_CONDITION, null, null); + + if (cursor != null) { + try { + count = cursor.getCount(); + } finally { + cursor.close(); + } + } + + // We ignored the latest incoming message so add one to the total count + if (timestamp > 0) { + // Log.v("adding 1 to unread, previous count was " + count); + count += 1; + } + + // Log.v("sms unread count = " + count); + return count; + } + + public static int getUnreadMmsCount(Context context) { + + String MMS_READ_COLUMN = "read"; + String UNREAD_CONDITION = MMS_READ_COLUMN + "=0"; + + int count = 0; + + Cursor cursor = context.getContentResolver().query(MMS_INBOX_CONTENT_URI, new String[]{SMS_ID}, + UNREAD_CONDITION, null, null); + + if (cursor != null) { + try { + count = cursor.getCount(); + } finally { + cursor.close(); + } + } + // Log.v("mms unread count = " + count); + return count; + } + + /* + * + */ + public static SmsMmsMessage getSmsDetails(Context context, long ignoreThreadId, boolean unreadOnly) { + + String SMS_READ_COLUMN = "read"; + String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null; + String SORT_ORDER = "date DESC"; + int count = 0; + + // //Log.v(WHERE_CONDITION); + + if (ignoreThreadId > 0) { + // //Log.v("Ignoring sms threadId = " + ignoreThreadId); + WHERE_CONDITION += " AND thread_id != " + ignoreThreadId; + } + + Cursor cursor = context.getContentResolver().query(SMS_INBOX_CONTENT_URI, + new String[]{"_id", "thread_id", "address", "person", "date", "body"}, WHERE_CONDITION, null, + SORT_ORDER); + + if (cursor != null) { + try { + count = cursor.getCount(); + if (count > 0) { + cursor.moveToFirst(); + + // String[] columns = cursor.getColumnNames(); + // for (int i=0; i 0) { + // //Log.v("Ignoring mms threadId = " + ignoreThreadId); + UNREAD_CONDITION += " AND thread_id != " + ignoreThreadId; + } + + Cursor cursor = context.getContentResolver().query(MMS_INBOX_CONTENT_URI, + // new String[] { "m_id", "\"from\"", "sub", "d_tm", "thread_id" }, + new String[]{"_id", "thread_id", "date", "sub", "sub_cs"}, UNREAD_CONDITION, null, SORT_ORDER); + + if (cursor != null) { + try { + count = cursor.getCount(); + if (count > 0) { + cursor.moveToFirst(); + // String[] columns = cursor.getColumnNames(); + // for (int i=0; i mRunningTaskList = mAM.getRunningTasks(1); + Iterator mIterator = mRunningTaskList.iterator(); + if (mIterator.hasNext()) { + RunningTaskInfo mRunningTask = mIterator.next(); + if (mRunningTask != null) { + ComponentName runningTaskComponent = mRunningTask.baseActivity; + + // //Log.v("baseActivity = " + + // mRunningTask.baseActivity.toString()); + // //Log.v("topActivity = " + + // mRunningTask.topActivity.toString()); + + if (PACKAGE_NAME.equals(runningTaskComponent.getPackageName()) + && CONVO_CLASS_NAME.equals(runningTaskComponent.getClassName())) { + // Log.v("User in messaging app - from running task"); + return true; + } + } + } + + /* + * List mActivityList = mAM.getRecentTasks(1, 0); + * Iterator mIterator = mActivityList.iterator(); + * + * if (mIterator.hasNext()) { RecentTaskInfo mRecentTask = + * (RecentTaskInfo) mIterator.next(); Intent recentTaskIntent = + * mRecentTask.baseIntent; + * + * if (recentTaskIntent != null) { ComponentName recentTaskComponentName + * = recentTaskIntent.getComponent(); if (recentTaskComponentName != + * null) { String recentTaskClassName = + * recentTaskComponentName.getClassName(); if + * (PACKAGE_NAME.equals(recentTaskComponentName.getPackageName()) && + * (COMPOSE_CLASS_NAME.equals(recentTaskClassName) || + * CONVO_CLASS_NAME.equals(recentTaskClassName))) { + * //Log.v("User in messaging app"); return true; } } } } + */ + + /* + * These appear to be the 2 main intents that mean the user is using the + * messaging app + * + * action "android.intent.action.MAIN" data null class + * "com.android.mms.ui.ConversationList" package "com.android.mms" + * + * action "android.intent.action.VIEW" data + * "content://mms-sms/threadID/3" class + * "com.android.mms.ui.ComposeMessageActivity" package "com.android.mms" + */ + + return false; + } + + /** + * Enables or disables the main SMS receiver + */ + public static void enableSMSPopup(Context context, boolean enable) { + // PackageManager pm = context.getPackageManager(); + // ComponentName cn = new ComponentName(context, SmsReceiver.class); + // + // // Update preference so it reflects in the preference activity + // SharedPreferences myPrefs = + // PreferenceManager.getDefaultSharedPreferences(context); + // SharedPreferences.Editor settings = myPrefs.edit(); + // settings.putBoolean(context.getString(R.string.pref_enabled_key), + // enable); + // settings.commit(); + // + // if (enable) { + // //Log.v("SMSPopup receiver is enabled"); + // pm.setComponentEnabledSetting(cn, + // PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, + // PackageManager.DONT_KILL_APP); + // + // // Send a broadcast to disable other SMS Popup apps + // disableOtherSMSPopup(context); + // + // } else { + // //Log.v("SMSPopup receiver is disabled"); + // pm.setComponentEnabledSetting(cn, + // PackageManager.COMPONENT_ENABLED_STATE_DISABLED, + // PackageManager.DONT_KILL_APP); + // } + } + + public static void disableOtherSMSPopup(Context context) { + // Send a broadcast to disable SMS Popup Pro + // Intent i = new Intent(ExternalEventReceiver.ACTION_SMSPOPUP_DISABLE); + // i.setClassName("net.everythingandroid.smspopuppro", + // "net.everythingandroid.smspopuppro.ExternalEventReceiver"); + // context.sendBroadcast(i); + } +} diff --git a/app/src/main/java/org/xbmc/android/util/WakeOnLan.java b/app/src/main/java/org/xbmc/android/util/WakeOnLan.java new file mode 100644 index 00000000..39da0859 --- /dev/null +++ b/app/src/main/java/org/xbmc/android/util/WakeOnLan.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.util; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; + +/** + * The WoL implementation + * + * @author Team XBMC + */ +public class WakeOnLan { + private static byte[] getMacBytes(String macStr) throws IllegalArgumentException { + byte[] bytes = new byte[6]; + String[] hex = macStr.split("(\\:|\\-)"); + if (hex.length != 6) { + throw new IllegalArgumentException("Invalid MAC address."); + } + try { + for (int i = 0; i < 6; i++) { + bytes[i] = (byte) Integer.parseInt(hex[i], 16); + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Invalid hex digit in MAC address."); + } + return bytes; + } + + public Boolean sendMagicPacket(String macStr, String ipStr, int PORT) { + try { + byte[] macBytes = getMacBytes(macStr); + byte[] bytes = new byte[6 + 16 * macBytes.length]; + for (int i = 0; i < 6; i++) { + bytes[i] = (byte) 0xff; + } + for (int i = 6; i < bytes.length; i += macBytes.length) { + System.arraycopy(macBytes, 0, bytes, i, macBytes.length); + } + + InetAddress address = InetAddress.getByName(ipStr); + DatagramPacket packet = new DatagramPacket(bytes, bytes.length, address, PORT); + DatagramSocket socket = new DatagramSocket(); + socket.send(packet); + socket.close(); + return true; + } catch (Exception e) { + return false; + } + } + + public Boolean sendMagicPacket(String macStr, int PORT) { + return sendMagicPacket(macStr, "255.255.255.255", PORT); + } + + public Boolean sendMagicPacket(String macStr) { + return sendMagicPacket(macStr, "255.255.255.255", 9); + } +} diff --git a/src/org/xbmc/android/util/WifiHelper.java b/app/src/main/java/org/xbmc/android/util/WifiHelper.java similarity index 65% rename from src/org/xbmc/android/util/WifiHelper.java rename to app/src/main/java/org/xbmc/android/util/WifiHelper.java index c7c89d58..91866f8b 100644 --- a/src/org/xbmc/android/util/WifiHelper.java +++ b/app/src/main/java/org/xbmc/android/util/WifiHelper.java @@ -1,9 +1,5 @@ package org.xbmc.android.util; -import java.util.List; - -import org.xbmc.api.object.Host; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -13,8 +9,12 @@ import android.net.wifi.WifiManager.WifiLock; import android.util.Log; +import org.xbmc.api.object.Host; + +import java.util.List; + public class WifiHelper { - + public static final String TAG = "WifiHelper"; /** @@ -33,35 +33,32 @@ public class WifiHelper { * WiFi is enabled and connected. */ public static final int WIFI_STATE_CONNECTED = 5; - + public static final String WIFI_LOCK_TAG = "org.xbmc.android.remote.wifi.lock"; - - private WifiManager.WifiLock mWifiLock = null; - + private static WifiHelper mInstance = null; private final WifiManager mManager; - + private final ConnectivityManager mConnectivityManager; - - private static WifiHelper mInstance = null; + private WifiManager.WifiLock mWifiLock = null; private WifiHelper(Context context) { - this.mManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE); - this.mConnectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + this.mManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + this.mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); mInstance = this; } - + public static WifiHelper getInstance(Context context) { - if(mInstance == null) new WifiHelper(context); + if (mInstance == null) new WifiHelper(context); return mInstance; } - + public void connect(final Host host) { Log.d(TAG, "trying to connect to AP:" + host.access_point); final List hosts = mManager.getConfiguredNetworks(); int networkId = -1; - for(WifiConfiguration conf : hosts) { + for (WifiConfiguration conf : hosts) { Log.d(TAG, "trying host:" + conf.SSID); - if(conf.SSID.equalsIgnoreCase("\"" + host.access_point+ "\"")) { + if (conf.SSID.equalsIgnoreCase("\"" + host.access_point + "\"")) { networkId = conf.networkId; Log.d(TAG, "found hosts AP in Android with ID:" + networkId); break; @@ -69,57 +66,57 @@ public void connect(final Host host) { } mManager.enableNetwork(networkId, true); } - + public void enableWifi(final boolean b) { mManager.setWifiEnabled(b); } - + public void aquireWifiLock() { - if(mWifiLock == null) { + if (mWifiLock == null) { Log.d(TAG, "creating new WifiLock"); - mWifiLock = mManager.createWifiLock(WifiManager.WIFI_MODE_FULL,WIFI_LOCK_TAG); + mWifiLock = mManager.createWifiLock(WifiManager.WIFI_MODE_FULL, WIFI_LOCK_TAG); } - if(!mWifiLock.isHeld()) { + if (!mWifiLock.isHeld()) { Log.d(TAG, "aquiring WifiLock"); mWifiLock.acquire(); } } - + public WifiLock getNewWifiLock(String lock_postfix) { return mManager.createWifiLock(WifiManager.WIFI_MODE_FULL, WIFI_LOCK_TAG + lock_postfix); } - + public void releaseWifiLock() { - if(mWifiLock != null && mWifiLock.isHeld()) { + if (mWifiLock != null && mWifiLock.isHeld()) { Log.d(TAG, "releasing WifiLock"); mWifiLock.release(); } } - + public int getWifiState() { switch (mManager.getWifiState()) { - case WifiManager.WIFI_STATE_UNKNOWN: - Log.d(TAG, "WIFI_STATE_UNKOWN"); - return WIFI_STATE_UNKNOWN; - case WifiManager.WIFI_STATE_DISABLED: - case WifiManager.WIFI_STATE_DISABLING: - Log.d(TAG, "WIFI_STATE_DISABLED"); - return WIFI_STATE_DISABLED; - case WifiManager.WIFI_STATE_ENABLING: - case WifiManager.WIFI_STATE_ENABLED: - final WifiInfo info = mManager.getConnectionInfo(); - if(info != null && info.getSSID() != null) { - Log.d(TAG, "WIFI_STATE_CONNECTED to " + info.getSSID()); - final NetworkInfo mWifi = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); - if (mWifi.isConnected()) { - return WIFI_STATE_CONNECTED; + case WifiManager.WIFI_STATE_UNKNOWN: + Log.d(TAG, "WIFI_STATE_UNKOWN"); + return WIFI_STATE_UNKNOWN; + case WifiManager.WIFI_STATE_DISABLED: + case WifiManager.WIFI_STATE_DISABLING: + Log.d(TAG, "WIFI_STATE_DISABLED"); + return WIFI_STATE_DISABLED; + case WifiManager.WIFI_STATE_ENABLING: + case WifiManager.WIFI_STATE_ENABLED: + final WifiInfo info = mManager.getConnectionInfo(); + if (info != null && info.getSSID() != null) { + Log.d(TAG, "WIFI_STATE_CONNECTED to " + info.getSSID()); + final NetworkInfo mWifi = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (mWifi.isConnected()) { + return WIFI_STATE_CONNECTED; + } } - } - Log.d(TAG, "WIFI_STATE_ENABLED"); - return WIFI_STATE_ENABLED; + Log.d(TAG, "WIFI_STATE_ENABLED"); + return WIFI_STATE_ENABLED; } return -1; } - - + + } diff --git a/src/org/xbmc/android/util/YoutubeURLParser.java b/app/src/main/java/org/xbmc/android/util/YoutubeURLParser.java similarity index 78% rename from src/org/xbmc/android/util/YoutubeURLParser.java rename to app/src/main/java/org/xbmc/android/util/YoutubeURLParser.java index a41969f0..48a63e3a 100644 --- a/src/org/xbmc/android/util/YoutubeURLParser.java +++ b/app/src/main/java/org/xbmc/android/util/YoutubeURLParser.java @@ -1,17 +1,19 @@ package org.xbmc.android.util; +import android.net.Uri; + import java.util.regex.Matcher; import java.util.regex.Pattern; -import android.net.Uri; - public class YoutubeURLParser { public static String parseYoutubeURL(Uri playuri) { if (playuri.getHost().endsWith("youtube.com") || playuri.getHost().endsWith("youtu.be")) { // We'll need to get the v= parameter from the URL and use // that to send to XBMC - final Pattern pattern = Pattern.compile("(?:https?:\\/\\/)?(?:www\\.)?youtu(?:.be\\/|be\\.com\\/watch\\?v=)([\\w-]{11})", Pattern.CASE_INSENSITIVE); -// final Pattern pattern = Pattern.compile("^http(:?s)?:\\/\\/(?:www\\.)?(?:youtube\\.com|youtu\\.be)\\/watch\\?(?=.*v=([\\w-]+))(?:\\S+)?$", Pattern.CASE_INSENSITIVE); + final Pattern pattern = Pattern.compile("(?:https?:\\/\\/)?(?:www\\.)?youtu(?:.be\\/|be\\" + + ".com\\/watch\\?v=)([\\w-]{11})", Pattern.CASE_INSENSITIVE); +// final Pattern pattern = Pattern.compile("^http(:?s)?:\\/\\/(?:www\\.)?(?:youtube\\.com|youtu\\.be) +// \\/watch\\?(?=.*v=([\\w-]+))(?:\\S+)?$", Pattern.CASE_INSENSITIVE); // final Pattern pattern = Pattern.compile(".*v=([a-z0-9_\\-]+)(?:&.)*", Pattern.CASE_INSENSITIVE); final Matcher matcher = pattern.matcher(playuri.toString()); if (matcher.matches()) { diff --git a/src/org/xbmc/android/widget/FastScrollView.java b/app/src/main/java/org/xbmc/android/widget/FastScrollView.java similarity index 98% rename from src/org/xbmc/android/widget/FastScrollView.java rename to app/src/main/java/org/xbmc/android/widget/FastScrollView.java index 510b331b..10612185 100644 --- a/src/org/xbmc/android/widget/FastScrollView.java +++ b/app/src/main/java/org/xbmc/android/widget/FastScrollView.java @@ -16,8 +16,6 @@ package org.xbmc.android.widget; -import org.xbmc.android.remote.R; - import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; @@ -32,12 +30,14 @@ import android.view.View.OnTouchListener; import android.view.ViewGroup.OnHierarchyChangeListener; import android.widget.AbsListView; +import android.widget.AbsListView.OnScrollListener; import android.widget.Adapter; import android.widget.BaseAdapter; import android.widget.FrameLayout; import android.widget.HeaderViewListAdapter; import android.widget.ListView; -import android.widget.AbsListView.OnScrollListener; + +import org.xbmc.android.remote.R; /** * FastScrollView is meant for embedding {@link ListView}s that contain a large @@ -46,22 +46,21 @@ * touch-mode. Only one child can be added to this view group and it must be a * {@link ListView}, with an adapter that is derived from {@link BaseAdapter}. */ -public class FastScrollView extends FrameLayout implements OnScrollListener, OnTouchListener, OnHierarchyChangeListener { +public class FastScrollView extends FrameLayout implements OnScrollListener, OnTouchListener, + OnHierarchyChangeListener { + public static final int SCROLL_STATE_FAST_SCROLLING = 4; + public static final int SCROLL_STATE_FAST_IDLE = 5; + private static final int SCROLL_TOUCH_SLOP = 4; private Drawable mCurrentThumb; private Drawable mOverlayDrawable; - private int mThumbH; private int mThumbW; private int mThumbY; private int mLastScrollThumbY; - private static final int SCROLL_TOUCH_SLOP = 4; - private RectF mOverlayPos; - // Hard coding these for now private int mOverlaySize = 104; - private boolean mDragging; private AbsListView mList; private boolean mScrollCompleted; @@ -69,28 +68,15 @@ public class FastScrollView extends FrameLayout implements OnScrollListener, OnT private int mVisibleItem; private Paint mPaint; private int mListOffset; - private Object[] mSections; private String mSectionText; private boolean mDrawOverlay; private ScrollFade mScrollFade; - private Handler mHandler = new Handler(); - private BaseAdapter mListAdapter; - private IdleListDetector mIdleListDetector; - public static final int SCROLL_STATE_FAST_SCROLLING = 4; - public static final int SCROLL_STATE_FAST_IDLE = 5; - private boolean mChangedBounds; - public interface SectionIndexer { - Object[] getSections(); - int getPositionForSection(int section); - int getSectionForPosition(int position); - } - public FastScrollView(Context context) { super(context); init(context); @@ -190,7 +176,8 @@ public void draw(Canvas canvas) { final Paint paint = mPaint; float descent = paint.descent(); final RectF rectF = mOverlayPos; - canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2, (int) (rectF.bottom + rectF.top) / 2 + mOverlaySize / 4 - descent, paint); + canvas.drawText(mSectionText, (int) (rectF.left + rectF.right) / 2, (int) (rectF.bottom + rectF.top) / 2 + + mOverlaySize / 4 - descent, paint); } else if (alpha == 0) { scrollFade.mStarted = false; removeThumb(); @@ -359,12 +346,12 @@ private void scrollTo(float position) { index = count - 1; // TODO do that properly if (mList instanceof ListView) { - ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); + ((ListView) mList).setSelectionFromTop(index + mListOffset, 0); } } else { int index = (int) (position * count); if (mList instanceof ListView) { - ((ListView)mList).setSelectionFromTop(index + mListOffset, 0); + ((ListView) mList).setSelectionFromTop(index + mListOffset, 0); } sectionIndex = -1; } @@ -435,13 +422,21 @@ public boolean onTouchEvent(MotionEvent me) { return super.onTouchEvent(me); } + public interface SectionIndexer { + Object[] getSections(); + + int getPositionForSection(int section); + + int getSectionForPosition(int position); + } + public class ScrollFade implements Runnable { + static final int ALPHA_MAX = 255; + static final long FADE_DURATION = 200; long mStartTime; long mFadeDuration; boolean mStarted; - static final int ALPHA_MAX = 255; - static final long FADE_DURATION = 200; void startFade() { mFadeDuration = FADE_DURATION; diff --git a/src/org/xbmc/android/widget/IdleListDetector.java b/app/src/main/java/org/xbmc/android/widget/IdleListDetector.java similarity index 93% rename from src/org/xbmc/android/widget/IdleListDetector.java rename to app/src/main/java/org/xbmc/android/widget/IdleListDetector.java index 10e92327..eb443901 100644 --- a/src/org/xbmc/android/widget/IdleListDetector.java +++ b/app/src/main/java/org/xbmc/android/widget/IdleListDetector.java @@ -19,17 +19,14 @@ * Abstracts a mechanism for determining an appropriate time to load images into * an animating ListView. That is, only load the images when the list view is * not flinging. - * + *

* To use, you must make sure that you call through to - * {@link onScrollStateChanged} and {@link onTouch}. - * + * {@link #onScrollStateChanged} and {@link #onTouch}. + *

* This class was inspired by Romain Guy's ShelvesActivity. Rather, it was * blatantly lifted from it :) */ public class IdleListDetector { - - private final ScrollHandler mScrollHandler; - private final OnListIdleListener mListener; /* * Time to wait before loading the images while the user still has their @@ -37,7 +34,8 @@ public class IdleListDetector { */ private static final int DELAY_IDLE_DETECTION = 550; private static final int DELAY_FAST_IDLE_DETECTION = DELAY_IDLE_DETECTION; - + private final ScrollHandler mScrollHandler; + private final OnListIdleListener mListener; private int mScrollState = OnScrollListener.SCROLL_STATE_IDLE; /* Special considerations for FastScrollView. */ @@ -61,10 +59,6 @@ public boolean isListIdle() { return true; } - public interface OnListIdleListener { - void onListIdle(); - } - public boolean onTouch(View v, MotionEvent ev) { int action = ev.getAction(); @@ -77,7 +71,8 @@ public boolean onTouch(View v, MotionEvent ev) { } public void onFastScrollStateChanged(AbsListView view, int scrollState) { - if (mFastScrollState == FastScrollView.SCROLL_STATE_FAST_SCROLLING && scrollState != FastScrollView.SCROLL_STATE_FAST_SCROLLING) + if (mFastScrollState == FastScrollView.SCROLL_STATE_FAST_SCROLLING && scrollState != FastScrollView + .SCROLL_STATE_FAST_SCROLLING) mScrollHandler.sendListIdle(true); else if (scrollState == FastScrollView.SCROLL_STATE_FAST_SCROLLING) mScrollHandler.sendListIdle(DELAY_FAST_IDLE_DETECTION); @@ -98,15 +93,19 @@ else if (scrollState == OnScrollListener.SCROLL_STATE_FLING) mScrollState = scrollState; } + public interface OnListIdleListener { + void onListIdle(); + } + private class ScrollHandler extends Handler { private static final int MSG_LIST_IDLE = 0; public void handleMessage(Message msg) { switch (msg.what) { - case MSG_LIST_IDLE: - mPending = false; - mListener.onListIdle(); - break; + case MSG_LIST_IDLE: + mPending = false; + mListener.onListIdle(); + break; } } diff --git a/src/org/xbmc/android/widget/IdleListener.java b/app/src/main/java/org/xbmc/android/widget/IdleListener.java similarity index 86% rename from src/org/xbmc/android/widget/IdleListener.java rename to app/src/main/java/org/xbmc/android/widget/IdleListener.java index f9bee3e4..3e5e64da 100644 --- a/src/org/xbmc/android/widget/IdleListener.java +++ b/app/src/main/java/org/xbmc/android/widget/IdleListener.java @@ -8,14 +8,14 @@ package org.xbmc.android.widget; +import android.util.Log; +import android.widget.AbsListView; + import org.xbmc.android.remote.presentation.widget.AbstractItemView; import org.xbmc.android.widget.IdleListDetector.OnListIdleListener; import org.xbmc.api.object.ICoverArt; import org.xbmc.api.type.ThumbSize; -import android.util.Log; -import android.widget.AbsListView; - /** * Useful common implementation of OnListIdleListener which handles loading * images that temporarily defaulted during a fling. Utilizes a mem cache to @@ -31,7 +31,7 @@ public IdleListener(AbsListView list, int thumbSize) { mList = list; mThumbSize = thumbSize; } - + public void onListIdle() { final AbsListView list = mList; int n = list.getChildCount(); @@ -40,14 +40,15 @@ public void onListIdle() { System.gc(); for (int i = 0; i < n; i++) { try { - final AbstractItemView itemView = (AbstractItemView)list.getChildAt(i); + final AbstractItemView itemView = (AbstractItemView) list.getChildAt(i); if (!itemView.hasBitmap()) { - ICoverArt cover = (ICoverArt)mList.getAdapter().getItem(itemView.getPosition()); + ICoverArt cover = (ICoverArt) mList.getAdapter().getItem(itemView.getPosition()); Log.i(TAG, "Cover: " + cover + " (" + ThumbSize.getDir(mThumbSize) + ")"); itemView.getResponse().load(cover, mThumbSize, false); } } catch (ClassCastException e) { - Log.e(TAG, "Cannot cast view at index " + i + " to AbstractItemView, class is " + list.getChildAt(i).getClass().getSimpleName() + "."); + Log.e(TAG, "Cannot cast view at index " + i + " to AbstractItemView, class is " + list.getChildAt(i) + .getClass().getSimpleName() + "."); } } System.gc(); diff --git a/src/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java similarity index 83% rename from src/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java rename to app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java index a89ffa1d..728b47a2 100644 --- a/src/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java +++ b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteAnimation.java @@ -1,95 +1,94 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.gestureremote; - -import android.content.Context; -import android.graphics.Point; -import android.util.AttributeSet; -import android.view.animation.Animation; -import android.view.animation.Transformation; - -/** - * Makes the slider glide to the next tab. - * - * @author Team XBMC - */ -class GestureRemoteAnimation extends Animation { - - private final Point mOrigin; - private final Point mFrom; - private final GestureRemoteCursor mCursor; - - private boolean mGestureZoneFadeOut = false; - private boolean mGestureZoneFadeIn = false; - - /** - * Constructor. Animation object can be declared final and re-used. - * - * @param context Current context - * @param attrs Attribute set when inflated from XML - * @param origin Coordinates of screen center - * @param cursor Reference to cursor - */ - public GestureRemoteAnimation(Context context, AttributeSet attrs, Point origin, GestureRemoteCursor cursor) { - super(context, attrs); - mOrigin = origin; - mCursor = cursor; - mFrom = cursor.getPosition(); - } - - public void setFadeIn(boolean fadein) { - mGestureZoneFadeIn = fadein; - } - - public void setFadeOut(boolean fadeout) { - mGestureZoneFadeOut = fadeout; - } - - /** - * Constructor. Animation object can be declared final and re-used. - * - * @param origin Coordinates of screen center - * @param cursor Reference to cursor - */ - public GestureRemoteAnimation(Point origin, GestureRemoteCursor cursor) { - mOrigin = origin; - mCursor = cursor; - mFrom = cursor.getPosition(); - } - - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - final Point to = new Point( - mFrom.x - (int)((mFrom.x - mOrigin.x) * interpolatedTime), - mFrom.y - (int)((mFrom.y - mOrigin.y) * interpolatedTime) - ); - mCursor.setPosition(to); - if (mGestureZoneFadeOut) { - mCursor.backgroundFadePos = (int)(interpolatedTime * 255.0); - } - if (mGestureZoneFadeIn) { - mCursor.backgroundFadePos = (int)((1 - interpolatedTime) * 255.0); - } - - } +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.gestureremote; + +import android.content.Context; +import android.graphics.Point; +import android.util.AttributeSet; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +/** + * Makes the slider glide to the next tab. + * + * @author Team XBMC + */ +class GestureRemoteAnimation extends Animation { + + private final Point mOrigin; + private final Point mFrom; + private final GestureRemoteCursor mCursor; + + private boolean mGestureZoneFadeOut = false; + private boolean mGestureZoneFadeIn = false; + + /** + * Constructor. Animation object can be declared final and re-used. + * + * @param context Current context + * @param attrs Attribute set when inflated from XML + * @param origin Coordinates of screen center + * @param cursor Reference to cursor + */ + public GestureRemoteAnimation(Context context, AttributeSet attrs, Point origin, GestureRemoteCursor cursor) { + super(context, attrs); + mOrigin = origin; + mCursor = cursor; + mFrom = cursor.getPosition(); + } + + /** + * Constructor. Animation object can be declared final and re-used. + * + * @param origin Coordinates of screen center + * @param cursor Reference to cursor + */ + public GestureRemoteAnimation(Point origin, GestureRemoteCursor cursor) { + mOrigin = origin; + mCursor = cursor; + mFrom = cursor.getPosition(); + } + + public void setFadeIn(boolean fadein) { + mGestureZoneFadeIn = fadein; + } + + public void setFadeOut(boolean fadeout) { + mGestureZoneFadeOut = fadeout; + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + final Point to = new Point( + mFrom.x - (int) ((mFrom.x - mOrigin.x) * interpolatedTime), + mFrom.y - (int) ((mFrom.y - mOrigin.y) * interpolatedTime) + ); + mCursor.setPosition(to); + if (mGestureZoneFadeOut) { + mCursor.backgroundFadePos = (int) (interpolatedTime * 255.0); + } + if (mGestureZoneFadeIn) { + mCursor.backgroundFadePos = (int) ((1 - interpolatedTime) * 255.0); + } + + } } \ No newline at end of file diff --git a/src/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java similarity index 92% rename from src/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java rename to app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java index 8cbcc5b9..d2287786 100644 --- a/src/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java +++ b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteCursor.java @@ -1,149 +1,148 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.gestureremote; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.graphics.Rect; - -class GestureRemoteCursor { - - private Bitmap img; // the image of the ball - private int coordX = 0; // the x coordinate at the canvas - private int coordY = 0; // the y coordinate at the canvas - private int id; // gives every ball his own id, for now not necessary - private boolean goRight = true; - private boolean goDown = true; - - public int backgroundFadePos = 0; - - private final int imgWidth, imgHeight; - - public GestureRemoteCursor(Context context, int drawable) { - this(context, drawable, new Point(0, 0)); - } - - public GestureRemoteCursor(Context context, int drawable, Point point) { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - img = BitmapFactory.decodeResource(context.getResources(), drawable); - coordX = point.x; - coordY = point.y; - imgWidth = img.getWidth(); - imgHeight = img.getHeight(); - } - - public Point getBitmapDimensions() { - return new Point(imgWidth, imgHeight); - } - - void setX(int newValue) { - coordX = newValue; - } - - public int getX() { - return coordX; - } - - void setY(int newValue) { - coordY = newValue; - } - - public int getY() { - return coordY; - } - - public void setPosition(Point point) { - coordX = point.x; - coordY = point.y; - } - - public Point getPosition() { - return new Point(coordX, coordY); - } - - public int getID() { - return id; - } - - public Bitmap getBitmap() { - return img; - } - - public String toString() { - return "Cursor(" + coordX + ", " + coordY + ")"; - } - - /** - * Returns the dirty rectangle that needs to be redrawn. - * @param from Original position - * @return - */ - public Rect getDirty(Point from) { - return new Rect( - Math.min(coordX, from.x), - Math.min(coordY, from.y), - Math.max(coordX, from.x) + imgWidth, - Math.max(coordY, from.y) + imgHeight - ); -/* if (coordX > from.x && coordY > from.y) { - return new Rect(from.x, from.y, coordX + imgWidth, coordY + imgHeight); - } else if (coordX > from.x && coordY <= from.y) { - return new Rect(from.x, coordY, coordX + imgWidth, from.y + imgHeight); - } else if (coordX <= from.x && coordY > from.y) { - return new Rect(coordX, from.y, from.x + imgWidth, coordY + imgHeight); - } else { - return new Rect(coordX, coordY, from.x + imgWidth, from.y + imgHeight); - }*/ - } - - public void moveBall(int goX, int goY) { - // check the borders, and set the direction if a border has reached - if (coordX > 270) { - goRight = false; - } - if (coordX < 0) { - goRight = true; - } - if (coordY > 400) { - goDown = false; - } - if (coordY < 0) { - goDown = true; - } - // move the x and y - if (goRight) { - coordX += goX; - } else { - coordX -= goX; - } - if (goDown) { - coordY += goY; - } else { - coordY -= goY; - } - - } - -} +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.gestureremote; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.graphics.Rect; + +class GestureRemoteCursor { + + private final int imgWidth, imgHeight; + public int backgroundFadePos = 0; + private Bitmap img; // the image of the ball + private int coordX = 0; // the x coordinate at the canvas + private int coordY = 0; // the y coordinate at the canvas + private int id; // gives every ball his own id, for now not necessary + private boolean goRight = true; + private boolean goDown = true; + + public GestureRemoteCursor(Context context, int drawable) { + this(context, drawable, new Point(0, 0)); + } + + public GestureRemoteCursor(Context context, int drawable, Point point) { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + img = BitmapFactory.decodeResource(context.getResources(), drawable); + coordX = point.x; + coordY = point.y; + imgWidth = img.getWidth(); + imgHeight = img.getHeight(); + } + + public Point getBitmapDimensions() { + return new Point(imgWidth, imgHeight); + } + + public int getX() { + return coordX; + } + + void setX(int newValue) { + coordX = newValue; + } + + public int getY() { + return coordY; + } + + void setY(int newValue) { + coordY = newValue; + } + + public Point getPosition() { + return new Point(coordX, coordY); + } + + public void setPosition(Point point) { + coordX = point.x; + coordY = point.y; + } + + public int getID() { + return id; + } + + public Bitmap getBitmap() { + return img; + } + + public String toString() { + return "Cursor(" + coordX + ", " + coordY + ")"; + } + + /** + * Returns the dirty rectangle that needs to be redrawn. + * + * @param from Original position + * @return + */ + public Rect getDirty(Point from) { + return new Rect( + Math.min(coordX, from.x), + Math.min(coordY, from.y), + Math.max(coordX, from.x) + imgWidth, + Math.max(coordY, from.y) + imgHeight + ); +/* if (coordX > from.x && coordY > from.y) { + return new Rect(from.x, from.y, coordX + imgWidth, coordY + imgHeight); + } else if (coordX > from.x && coordY <= from.y) { + return new Rect(from.x, coordY, coordX + imgWidth, from.y + imgHeight); + } else if (coordX <= from.x && coordY > from.y) { + return new Rect(coordX, from.y, from.x + imgWidth, coordY + imgHeight); + } else { + return new Rect(coordX, coordY, from.x + imgWidth, from.y + imgHeight); + }*/ + } + + public void moveBall(int goX, int goY) { + // check the borders, and set the direction if a border has reached + if (coordX > 270) { + goRight = false; + } + if (coordX < 0) { + goRight = true; + } + if (coordY > 400) { + goDown = false; + } + if (coordY < 0) { + goDown = true; + } + // move the x and y + if (goRight) { + coordX += goX; + } else { + coordX -= goX; + } + if (goDown) { + coordY += goY; + } else { + coordY -= goY; + } + + } + +} diff --git a/src/org/xbmc/android/widget/gestureremote/GestureRemoteView.java b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteView.java similarity index 82% rename from src/org/xbmc/android/widget/gestureremote/GestureRemoteView.java rename to app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteView.java index dc565392..0c081897 100644 --- a/src/org/xbmc/android/widget/gestureremote/GestureRemoteView.java +++ b/app/src/main/java/org/xbmc/android/widget/gestureremote/GestureRemoteView.java @@ -1,571 +1,566 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.gestureremote; - -import org.xbmc.android.remote.R; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Point; -import android.graphics.Rect; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; - -public class GestureRemoteView extends View { - - private final static String TAG = "GestureRemoteView"; - - public static final float PIXEL_SCALE = Resources.getSystem().getDisplayMetrics().density; - - private final static int ANIMATION_DURATION = 100; - - private final static int CURSOR_NEG_PADDING = (int)(17 * PIXEL_SCALE); - private final static int CURSOR_POS_PADDING = (int)(30 * PIXEL_SCALE); - - private final static int SCROLL_ZONE_WIDTH = 62; - private final static int LEFT_BORDER_WIDTH = 22; - private final static int RIGHT_BORDER_WIDTH = 21; - private final static int TOP_BORDER_HEIGHT = 11; - private final static int BOTTOM_BORDER_HEIGHT = 19; - - private final static int BOX_LEFT_WIDTH = 101; - private final static int BOX_RIGHT_WIDTH = 81; - private final static int BOX_TOP_HEIGHT = 89; - private final static int BOX_BOTTOM_HEIGHT = 96; - - private final static int REFERENCE_WIDTH = 320; - private final static int REFERENCE_HEIGHT = 270; - - private final static Paint PAINT = new Paint(); - - private final static boolean HORIZ = true; - private final static boolean VERT = false; - - private IGestureListener mListener; - private GestureRemoteCursor mCursor; - private Point mDelta = new Point(0, 0); - private Point mOrigin = mDelta; - private boolean mIsDragging = false; - private boolean mIsScrolling = false; - - private boolean mLastDirection = HORIZ; - private int mLastZone = 0; - private boolean mMoved = false; - private double mLastScrollValue = 0.0; - - private final Bitmap mGestureOverlay; - - private final Bitmap mBorderRight; - private final Bitmap mBorderLeft; - private final Rect mBorderRightRect; - private final Rect mBorderLeftRect; - - private final Rect mScrollerRect; - private final Rect mGestureRect; - - private final Rect mTitleRect; - private final Rect mInfoRect; - private final Rect mMenuRect; - private final Rect mBackRect; - - private int mMaxPosX = 0; - private int mMaxPosY = 0; - - private final Point mCursorDim; - private double[] mZones; - - private double mScaleWidth = 1; - private double mScaleHeight = 1; - - private int mWidth = REFERENCE_WIDTH; - private int mHeight = REFERENCE_HEIGHT; - - private int mCurrentButtonPressed = 0; - - public GestureRemoteView(Context context, AttributeSet attrs) { - super(context, attrs); - setFocusable(true); // necessary for getting the touch events - mCursor = new GestureRemoteCursor(context, R.drawable.remote_gest_cursor, new Point(50, 20)); - mCursorDim = mCursor.getBitmapDimensions(); - setBackgroundResource(R.drawable.remote_xbox_gesturezone); - mBorderLeft = BitmapFactory.decodeResource(getResources(), R.drawable.remote_gest_border_left); - mBorderRight = BitmapFactory.decodeResource(getResources(), R.drawable.remote_gest_border_right); - mGestureOverlay = BitmapFactory.decodeResource(getResources(), R.drawable.remote_xbox_gesturezone_dim); - mBorderRightRect = new Rect(); - mBorderLeftRect = new Rect(); - mScrollerRect = new Rect(); - mGestureRect = new Rect(); - - final int leftPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH - BOX_RIGHT_WIDTH; - final int rightPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH; - final int topPosOfBottomBox = REFERENCE_HEIGHT - BOX_BOTTOM_HEIGHT; - - mTitleRect = new Rect(0, 0, (int)(BOX_LEFT_WIDTH), (int)(BOX_TOP_HEIGHT)); - mInfoRect = new Rect((int)(leftPosOfRightBox), 0, (int)(rightPosOfRightBox), (int)(BOX_TOP_HEIGHT)); - mMenuRect = new Rect(0, (int)(topPosOfBottomBox), (int)(BOX_LEFT_WIDTH), (int)(REFERENCE_HEIGHT)); - mBackRect = new Rect((int)(leftPosOfRightBox), (int)(topPosOfBottomBox), (int)(rightPosOfRightBox), (int)(REFERENCE_HEIGHT)); - } - - public void setGestureListener(IGestureListener listener) { - mListener = listener; - mZones = listener.getZones(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - mWidth = MeasureSpec.getSize(widthMeasureSpec); - mHeight = MeasureSpec.getSize(heightMeasureSpec); - - final double scaleHeight = (double)mHeight / (double)REFERENCE_HEIGHT; - final double scaleWidth = (double)mWidth / (double)REFERENCE_WIDTH; - - setMeasuredDimension(mWidth, mHeight); - - if (scaleHeight != 1 || scaleWidth != 1) { - - Log.d(TAG, "Non-reference screen size detected. Scale width = " + scaleWidth + ", scale height = " + scaleHeight); - - final int leftPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH - BOX_RIGHT_WIDTH; - final int rightPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH; - final int topPosOfBottomBox = REFERENCE_HEIGHT - BOX_BOTTOM_HEIGHT; - - mTitleRect.right = (int)(BOX_LEFT_WIDTH * scaleWidth); - mTitleRect.bottom = (int)(BOX_TOP_HEIGHT * scaleHeight); - mInfoRect.left = (int)(leftPosOfRightBox * scaleWidth); - mInfoRect.right = (int)(rightPosOfRightBox * scaleWidth); - mInfoRect.bottom = (int)(BOX_TOP_HEIGHT * scaleHeight); - mMenuRect.top = (int)(topPosOfBottomBox * scaleHeight); - mMenuRect.right = (int)(BOX_LEFT_WIDTH * scaleWidth); - mMenuRect.bottom = (int)(REFERENCE_HEIGHT * scaleHeight); - mBackRect.left = (int)(leftPosOfRightBox * scaleWidth); - mBackRect.top = (int)(topPosOfBottomBox * scaleHeight); - mBackRect.right = (int)(rightPosOfRightBox * scaleWidth); - mBackRect.bottom = (int)(REFERENCE_HEIGHT * scaleHeight); - } - mScaleWidth = scaleWidth; - mScaleHeight = scaleHeight; - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mOrigin = new Point( - LEFT_BORDER_WIDTH + (w - mCursorDim.x - SCROLL_ZONE_WIDTH - LEFT_BORDER_WIDTH) / 2, - TOP_BORDER_HEIGHT + (h - mCursorDim.y - TOP_BORDER_HEIGHT - BOTTOM_BORDER_HEIGHT) / 2); - mCursor.setPosition(mOrigin); - - final double scaleWidth = mScaleWidth; - final double scaleHeight = mScaleHeight; - - // define gesture rectangle - mGestureRect.left = (int)(LEFT_BORDER_WIDTH * scaleWidth); - mGestureRect.top = (int)(TOP_BORDER_HEIGHT * scaleHeight); - mGestureRect.right = (int)(w - SCROLL_ZONE_WIDTH * scaleWidth); - mGestureRect.bottom = (int)(h - BOTTOM_BORDER_HEIGHT * scaleHeight); - - // define fast scroller rectangle - mScrollerRect.left = (int)(w - SCROLL_ZONE_WIDTH * scaleWidth); - mScrollerRect.top = (int)(TOP_BORDER_HEIGHT * scaleHeight); - mScrollerRect.right = w; - mScrollerRect.bottom = (int)(h - BOTTOM_BORDER_HEIGHT * scaleHeight); - - final int lPad = (int)(22 * scaleWidth); - final int tPad = (int)(-3 * scaleHeight); - final int rPad = (int)(21 * scaleWidth); - mBorderLeftRect.left = lPad; - mBorderLeftRect.top = (h - mBorderLeft.getHeight()) / 2 + tPad; - mBorderLeftRect.right = mBorderLeft.getWidth() + lPad; - mBorderLeftRect.bottom = (h + mBorderLeft.getHeight()) / 2 + tPad; - - mBorderRightRect.left = w - mBorderRight.getWidth() - rPad; - mBorderRightRect.top = (h - mBorderRight.getHeight()) / 2 + tPad; - mBorderRightRect.right = w - rPad; - mBorderRightRect.bottom = (h + mBorderRight.getHeight()) / 2 + tPad; - - mMaxPosX = (mGestureRect.width() - mCursorDim.x) / 2 + CURSOR_NEG_PADDING; - mMaxPosY = (mGestureRect.height() - mCursorDim.y) / 2 + CURSOR_NEG_PADDING; - } - - @Override - protected void onDraw(Canvas canvas) { - switch (mCurrentButtonPressed) { - case R.drawable.remote_xbox_gesture_title_down: - canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, mTitleRect, null); - break; - case R.drawable.remote_xbox_gesture_menu_down: - canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, mMenuRect, null); - break; - case R.drawable.remote_xbox_gesture_info_down: - canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, mInfoRect, null); - break; - case R.drawable.remote_xbox_gesture_back_down: - canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, mBackRect, null); - break; - } - if (mCursor.backgroundFadePos > 0) { - PAINT.setAlpha(mCursor.backgroundFadePos); - canvas.drawBitmap(mGestureOverlay, null, new Rect(0, 0, mWidth, mHeight), PAINT); - } - canvas.drawBitmap(mCursor.getBitmap(), mCursor.getX(), mCursor.getY(), null); - drawZones(canvas); - } - - /** - * Paints the gesture zone, scrolling zone, acceleration zones - * with different colors. For debug purposes only. - * @param canvas - */ - private void drawZones(Canvas canvas) { - final boolean drawZones = false; - final boolean drawRects = false; - if (drawRects) { - PAINT.setColor(Color.BLUE); - PAINT.setAlpha(50); - canvas.drawRect(mScrollerRect, PAINT); - PAINT.setColor(Color.RED); - PAINT.setAlpha(50); - canvas.drawRect(mGestureRect, PAINT); - - PAINT.setColor(Color.MAGENTA); - PAINT.setAlpha(50); - canvas.drawRect(mTitleRect, PAINT); - PAINT.setColor(Color.CYAN); - PAINT.setAlpha(50); - canvas.drawRect(mInfoRect, PAINT); - PAINT.setColor(Color.YELLOW); - PAINT.setAlpha(50); - canvas.drawRect(mMenuRect, PAINT); - PAINT.setColor(Color.BLUE); - PAINT.setAlpha(50); - canvas.drawRect(mBackRect, PAINT); - } - - if (drawZones) { - for (int x = mGestureRect.left; x < mGestureRect.right + SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH; x++) { - for (int y = mGestureRect.top; y < mGestureRect.bottom; y++) { - Point centered = getCenteredPos(new Point(x - mCursorDim.x / 2, y - mCursorDim.y / 2)); - final int zone; - if (Math.abs(centered.x) > Math.abs(centered.y)) { - // horizontally moving - final double pos = (double)centered.x / (double)mMaxPosX; - zone = findZone(pos); - PAINT.setColor(Color.MAGENTA); - } else { - // vertically moving - final double pos = (double)centered.y / (double)mMaxPosY; - zone = findZone(pos); - PAINT.setColor(Color.CYAN); - } - PAINT.setAlpha(10 * (Math.abs(zone) + 1)); - canvas.drawPoint(x, y, PAINT); - } - } - } - } - - /** - * Invalidates one of the four option buttons. - * @param buttonResId Button ID - */ - private void invalidateButton(int buttonResId) { - switch (buttonResId) { - case R.drawable.remote_xbox_gesture_title_down: - invalidate(mTitleRect); - break; - case R.drawable.remote_xbox_gesture_menu_down: - invalidate(mMenuRect); - break; - case R.drawable.remote_xbox_gesture_info_down: - invalidate(mInfoRect); - break; - case R.drawable.remote_xbox_gesture_back_down: - invalidate(mBackRect); - break; - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - final int eventaction = event.getAction(); - int x = (int)event.getX(); - int y = (int)event.getY(); - - switch (eventaction) { - /* - * Cursor is PRESSED - */ - case MotionEvent.ACTION_DOWN: - final int cursorX = mCursor.getX(); - final int cursorY = mCursor.getY(); - mIsDragging = x + CURSOR_POS_PADDING > cursorX && x - CURSOR_POS_PADDING < cursorX + mCursorDim.x && y + CURSOR_POS_PADDING > cursorY && y - CURSOR_POS_PADDING < cursorY + mCursorDim.y; - if (mScrollerRect.contains(x, y)) { // tapping on scroll bar? - final Point target = getScrollTarget(x - mCursorDim.x / 2, y - mCursorDim.y / 2); - GestureRemoteAnimation anim = new GestureRemoteAnimation(target, mCursor); - anim.setDuration(ANIMATION_DURATION); - anim.setFadeOut(true); - startAnimation(anim); - mIsScrolling = true; - mDelta = new Point(mCursorDim.x / 2, mCursorDim.y / 2); - if (mListener != null && target.y > mOrigin.y) { - mListener.onScrollDown(); - } else if (mListener != null && target.y < mOrigin.y) { - mListener.onScrollUp(); - } -// invalidate(mGestureRect); - } else if (mTitleRect.contains(x, y)) { - mCurrentButtonPressed = R.drawable.remote_xbox_gesture_title_down; - invalidateButton(R.drawable.remote_xbox_gesture_title_down); - if (mListener != null) { - mListener.onTitle(); - } - } else if (mMenuRect.contains(x, y)) { - mCurrentButtonPressed = R.drawable.remote_xbox_gesture_menu_down; - invalidateButton(R.drawable.remote_xbox_gesture_menu_down); - if (mListener != null) { - mListener.onMenu(); - } - } else if (mInfoRect.contains(x, y)) { - mCurrentButtonPressed = R.drawable.remote_xbox_gesture_info_down; - invalidateButton(R.drawable.remote_xbox_gesture_info_down); - if (mListener != null) { - mListener.onInfo(); - } - } else if (mBackRect.contains(x, y)) { - mCurrentButtonPressed = R.drawable.remote_xbox_gesture_back_down; - invalidateButton(R.drawable.remote_xbox_gesture_back_down); - if (mListener != null) { - mListener.onBack(); - } - } else { - mDelta = new Point(x - cursorX, y - cursorY); - mIsScrolling = false; - mLastZone = 0; - } - mMoved = false; - break; - - /* - * Cursor is MOVED - */ - case MotionEvent.ACTION_MOVE: - // DRAGGING - if (mIsDragging) { - final Point from = mCursor.getPosition(); - x -= mDelta.x; - y -= mDelta.y; - Point target = getGestureTarget(x, y); - mCursor.setPosition(target); - - // calculate redraw aera - invalidate(mCursor.getDirty(from)); - - if (mListener != null) { - Point centered = getCenteredPos(target); - if (Math.abs(centered.x) > Math.abs(centered.y)) { - // horizontally moving - final double pos = (double)centered.x / (double)mMaxPosX; - final int zone = findZone(pos); - if (zone != mLastZone || (mLastDirection != HORIZ && zone != 0)) { - mListener.onHorizontalMove(zone); - mLastZone = zone; - mLastDirection = HORIZ; - if (zone != 0) { - mMoved = true; - } - } - } else { - // vertically moving - final double pos = (double)centered.y / (double)mMaxPosY; - final int zone = findZone(pos); - if (zone != mLastZone || (mLastDirection != VERT && zone != 0)) { - Log.d("GestureRemoteView", "launching onVerticalMove() with pos = " + pos); - mListener.onVerticalMove(zone); - mLastZone = zone; - mLastDirection = VERT; - if (zone != 0) { - mMoved = true; - } - } - } - } - // SCROLLING - } else if (mIsScrolling) { - final Point from = mCursor.getPosition(); - x -= mDelta.x; - y -= mDelta.y; - Point target = getScrollTarget(x, y); - mCursor.setPosition(target); - - // calculate redraw aera - invalidate(mCursor.getDirty(from)); - - if (mListener != null) { - Point centered = getCenteredPos(target); - final double pos = (double)centered.y / (double)mMaxPosY; - if (pos != mLastScrollValue) { - if (pos > 0) { - if (mLastScrollValue > 0 != pos > 0 && mMoved) { // direction changed? - mListener.onScrollUp(0); - } - if (pos != 0) { - mListener.onScrollDown(pos); - } - } else { - if (mLastScrollValue > 0 != pos > 0 && mMoved) { // direction changed? - mListener.onScrollDown(0); - } - if (pos != 0) { - mListener.onScrollUp(-pos); - } - } - mLastScrollValue = pos; - } - } - mMoved = true; - } - break; - - /* - * Cursor is RELEASED - */ - case MotionEvent.ACTION_UP: - if (mIsDragging || mIsScrolling) { - if (mListener != null && mIsDragging) { - if (mLastZone == 0 && !mMoved) { - mListener.onSelect(); - } else { - if (mLastZone != 0 && mLastDirection == HORIZ) { - mListener.onHorizontalMove(0); - } else if (mLastZone != 0 && mLastDirection == VERT) { - mListener.onVerticalMove(0); - } - } - mLastZone = 0; - } - if (mListener != null && mIsScrolling) { - if (mLastScrollValue > 0 && mMoved) { - mListener.onScrollDown(0); - } else if (mLastScrollValue < 0 && mMoved) { - mListener.onScrollUp(0); - } - } - GestureRemoteAnimation anim = new GestureRemoteAnimation(mOrigin, mCursor); - anim.setDuration(ANIMATION_DURATION); - if (mIsScrolling) { - anim.setFadeIn(true); - } - this.startAnimation(anim); - mIsDragging = false; - mIsScrolling = false; - } - if (mCurrentButtonPressed != 0) { - final int clearupBtn = mCurrentButtonPressed; - mCurrentButtonPressed = 0; - invalidateButton(clearupBtn); - } - break; - } - return true; - } - - /** - * Returns the point where the cursor is finally rendered. It basically - * crops the movement to the predefined boundaries. - * @param x X-value where user dragged the cursor - * @param y Y-value where user dragged the cursor - * @return Point where cursor is finally rendered. - */ - private Point getGestureTarget(int x, int y) { - int targetX, targetY; - Rect rect = mGestureRect; - if (x >= rect.left - CURSOR_NEG_PADDING) { - if (x + mCursorDim.x < rect.right + CURSOR_NEG_PADDING + (SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH)) { - targetX = x; - } else { - targetX = rect.right - mCursorDim.x + CURSOR_NEG_PADDING + (SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH); - } - } else { - targetX = rect.left - CURSOR_NEG_PADDING; - } - if (y >= rect.top - CURSOR_NEG_PADDING) { - if (y + mCursorDim.y < rect.bottom + CURSOR_NEG_PADDING) { - targetY = y; - } else { - targetY = rect.bottom - mCursorDim.y + CURSOR_NEG_PADDING; - } - } else { - targetY = rect.top - CURSOR_NEG_PADDING; - } - return new Point(targetX, targetY); - } - - private Point getScrollTarget(int x, int y) { - int targetX, targetY; - Rect rect = mScrollerRect; - // fix X and move only Y - targetX = rect.left - CURSOR_NEG_PADDING; - if (y >= rect.top - CURSOR_NEG_PADDING) { - if (y + mCursorDim.y < rect.bottom + CURSOR_NEG_PADDING) { - targetY = y; - } else { - targetY = rect.bottom - mCursorDim.y + CURSOR_NEG_PADDING; - } - } else { - targetY = rect.top - CURSOR_NEG_PADDING; - } - return new Point(targetX, targetY); - } - - /** - * Converts coordinates from Android's Origin (top left of the view) to - * the center of the screen. - * @param from - * @return - */ - private Point getCenteredPos(Point from) { - return new Point( - from.x - mGestureRect.left - (mGestureRect.width() - mCursorDim.x) / 2, - from.y - mGestureRect.top - (mGestureRect.height() - mCursorDim.y) / 2); - } - - /** - * Returns the index of the zone defined for a position. - * @param pos - * @return - */ - private int findZone(double pos) { - for (int i = 0; i < mZones.length; i++) { - if (Math.abs(pos) <= mZones[i]) { - return (pos > 0 ? 1 : - 1) * i; - } - } - return (pos > 0 ? 1 : - 1) * mZones.length; - } +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.gestureremote; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; + +import org.xbmc.android.remote.R; + +public class GestureRemoteView extends View { + + public static final float PIXEL_SCALE = Resources.getSystem().getDisplayMetrics().density; + private final static int CURSOR_NEG_PADDING = (int) (17 * PIXEL_SCALE); + private final static int CURSOR_POS_PADDING = (int) (30 * PIXEL_SCALE); + private final static String TAG = "GestureRemoteView"; + private final static int ANIMATION_DURATION = 100; + private final static int SCROLL_ZONE_WIDTH = 62; + private final static int LEFT_BORDER_WIDTH = 22; + private final static int RIGHT_BORDER_WIDTH = 21; + private final static int TOP_BORDER_HEIGHT = 11; + private final static int BOTTOM_BORDER_HEIGHT = 19; + + private final static int BOX_LEFT_WIDTH = 101; + private final static int BOX_RIGHT_WIDTH = 81; + private final static int BOX_TOP_HEIGHT = 89; + private final static int BOX_BOTTOM_HEIGHT = 96; + + private final static int REFERENCE_WIDTH = 320; + private int mWidth = REFERENCE_WIDTH; + private final static int REFERENCE_HEIGHT = 270; + private int mHeight = REFERENCE_HEIGHT; + private final static Paint PAINT = new Paint(); + private final static boolean HORIZ = true; + private boolean mLastDirection = HORIZ; + private final static boolean VERT = false; + private final Bitmap mGestureOverlay; + private final Bitmap mBorderRight; + private final Bitmap mBorderLeft; + private final Rect mBorderRightRect; + private final Rect mBorderLeftRect; + private final Rect mScrollerRect; + private final Rect mGestureRect; + private final Rect mTitleRect; + private final Rect mInfoRect; + private final Rect mMenuRect; + private final Rect mBackRect; + private final Point mCursorDim; + private IGestureListener mListener; + private GestureRemoteCursor mCursor; + private Point mDelta = new Point(0, 0); + private Point mOrigin = mDelta; + private boolean mIsDragging = false; + private boolean mIsScrolling = false; + private int mLastZone = 0; + private boolean mMoved = false; + private double mLastScrollValue = 0.0; + private int mMaxPosX = 0; + private int mMaxPosY = 0; + private double[] mZones; + private double mScaleWidth = 1; + private double mScaleHeight = 1; + private int mCurrentButtonPressed = 0; + + public GestureRemoteView(Context context, AttributeSet attrs) { + super(context, attrs); + setFocusable(true); // necessary for getting the touch events + mCursor = new GestureRemoteCursor(context, R.drawable.remote_gest_cursor, new Point(50, 20)); + mCursorDim = mCursor.getBitmapDimensions(); + setBackgroundResource(R.drawable.remote_xbox_gesturezone); + mBorderLeft = BitmapFactory.decodeResource(getResources(), R.drawable.remote_gest_border_left); + mBorderRight = BitmapFactory.decodeResource(getResources(), R.drawable.remote_gest_border_right); + mGestureOverlay = BitmapFactory.decodeResource(getResources(), R.drawable.remote_xbox_gesturezone_dim); + mBorderRightRect = new Rect(); + mBorderLeftRect = new Rect(); + mScrollerRect = new Rect(); + mGestureRect = new Rect(); + + final int leftPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH - BOX_RIGHT_WIDTH; + final int rightPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH; + final int topPosOfBottomBox = REFERENCE_HEIGHT - BOX_BOTTOM_HEIGHT; + + mTitleRect = new Rect(0, 0, (int) (BOX_LEFT_WIDTH), (int) (BOX_TOP_HEIGHT)); + mInfoRect = new Rect((int) (leftPosOfRightBox), 0, (int) (rightPosOfRightBox), (int) (BOX_TOP_HEIGHT)); + mMenuRect = new Rect(0, (int) (topPosOfBottomBox), (int) (BOX_LEFT_WIDTH), (int) (REFERENCE_HEIGHT)); + mBackRect = new Rect((int) (leftPosOfRightBox), (int) (topPosOfBottomBox), (int) (rightPosOfRightBox), + (int) (REFERENCE_HEIGHT)); + } + + public void setGestureListener(IGestureListener listener) { + mListener = listener; + mZones = listener.getZones(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + mWidth = MeasureSpec.getSize(widthMeasureSpec); + mHeight = MeasureSpec.getSize(heightMeasureSpec); + + final double scaleHeight = (double) mHeight / (double) REFERENCE_HEIGHT; + final double scaleWidth = (double) mWidth / (double) REFERENCE_WIDTH; + + setMeasuredDimension(mWidth, mHeight); + + if (scaleHeight != 1 || scaleWidth != 1) { + + Log.d(TAG, "Non-reference screen size detected. Scale width = " + scaleWidth + ", " + + "scale height = " + scaleHeight); + + final int leftPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH - BOX_RIGHT_WIDTH; + final int rightPosOfRightBox = REFERENCE_WIDTH - SCROLL_ZONE_WIDTH; + final int topPosOfBottomBox = REFERENCE_HEIGHT - BOX_BOTTOM_HEIGHT; + + mTitleRect.right = (int) (BOX_LEFT_WIDTH * scaleWidth); + mTitleRect.bottom = (int) (BOX_TOP_HEIGHT * scaleHeight); + mInfoRect.left = (int) (leftPosOfRightBox * scaleWidth); + mInfoRect.right = (int) (rightPosOfRightBox * scaleWidth); + mInfoRect.bottom = (int) (BOX_TOP_HEIGHT * scaleHeight); + mMenuRect.top = (int) (topPosOfBottomBox * scaleHeight); + mMenuRect.right = (int) (BOX_LEFT_WIDTH * scaleWidth); + mMenuRect.bottom = (int) (REFERENCE_HEIGHT * scaleHeight); + mBackRect.left = (int) (leftPosOfRightBox * scaleWidth); + mBackRect.top = (int) (topPosOfBottomBox * scaleHeight); + mBackRect.right = (int) (rightPosOfRightBox * scaleWidth); + mBackRect.bottom = (int) (REFERENCE_HEIGHT * scaleHeight); + } + mScaleWidth = scaleWidth; + mScaleHeight = scaleHeight; + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + mOrigin = new Point( + LEFT_BORDER_WIDTH + (w - mCursorDim.x - SCROLL_ZONE_WIDTH - LEFT_BORDER_WIDTH) / 2, + TOP_BORDER_HEIGHT + (h - mCursorDim.y - TOP_BORDER_HEIGHT - BOTTOM_BORDER_HEIGHT) / 2); + mCursor.setPosition(mOrigin); + + final double scaleWidth = mScaleWidth; + final double scaleHeight = mScaleHeight; + + // define gesture rectangle + mGestureRect.left = (int) (LEFT_BORDER_WIDTH * scaleWidth); + mGestureRect.top = (int) (TOP_BORDER_HEIGHT * scaleHeight); + mGestureRect.right = (int) (w - SCROLL_ZONE_WIDTH * scaleWidth); + mGestureRect.bottom = (int) (h - BOTTOM_BORDER_HEIGHT * scaleHeight); + + // define fast scroller rectangle + mScrollerRect.left = (int) (w - SCROLL_ZONE_WIDTH * scaleWidth); + mScrollerRect.top = (int) (TOP_BORDER_HEIGHT * scaleHeight); + mScrollerRect.right = w; + mScrollerRect.bottom = (int) (h - BOTTOM_BORDER_HEIGHT * scaleHeight); + + final int lPad = (int) (22 * scaleWidth); + final int tPad = (int) (-3 * scaleHeight); + final int rPad = (int) (21 * scaleWidth); + mBorderLeftRect.left = lPad; + mBorderLeftRect.top = (h - mBorderLeft.getHeight()) / 2 + tPad; + mBorderLeftRect.right = mBorderLeft.getWidth() + lPad; + mBorderLeftRect.bottom = (h + mBorderLeft.getHeight()) / 2 + tPad; + + mBorderRightRect.left = w - mBorderRight.getWidth() - rPad; + mBorderRightRect.top = (h - mBorderRight.getHeight()) / 2 + tPad; + mBorderRightRect.right = w - rPad; + mBorderRightRect.bottom = (h + mBorderRight.getHeight()) / 2 + tPad; + + mMaxPosX = (mGestureRect.width() - mCursorDim.x) / 2 + CURSOR_NEG_PADDING; + mMaxPosY = (mGestureRect.height() - mCursorDim.y) / 2 + CURSOR_NEG_PADDING; + } + + @Override + protected void onDraw(Canvas canvas) { + switch (mCurrentButtonPressed) { + case R.drawable.remote_xbox_gesture_title_down: + canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, + mTitleRect, null); + break; + case R.drawable.remote_xbox_gesture_menu_down: + canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, + mMenuRect, null); + break; + case R.drawable.remote_xbox_gesture_info_down: + canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, + mInfoRect, null); + break; + case R.drawable.remote_xbox_gesture_back_down: + canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), mCurrentButtonPressed), null, + mBackRect, null); + break; + } + if (mCursor.backgroundFadePos > 0) { + PAINT.setAlpha(mCursor.backgroundFadePos); + canvas.drawBitmap(mGestureOverlay, null, new Rect(0, 0, mWidth, mHeight), PAINT); + } + canvas.drawBitmap(mCursor.getBitmap(), mCursor.getX(), mCursor.getY(), null); + drawZones(canvas); + } + + /** + * Paints the gesture zone, scrolling zone, acceleration zones + * with different colors. For debug purposes only. + * + * @param canvas + */ + private void drawZones(Canvas canvas) { + final boolean drawZones = false; + final boolean drawRects = false; + if (drawRects) { + PAINT.setColor(Color.BLUE); + PAINT.setAlpha(50); + canvas.drawRect(mScrollerRect, PAINT); + PAINT.setColor(Color.RED); + PAINT.setAlpha(50); + canvas.drawRect(mGestureRect, PAINT); + + PAINT.setColor(Color.MAGENTA); + PAINT.setAlpha(50); + canvas.drawRect(mTitleRect, PAINT); + PAINT.setColor(Color.CYAN); + PAINT.setAlpha(50); + canvas.drawRect(mInfoRect, PAINT); + PAINT.setColor(Color.YELLOW); + PAINT.setAlpha(50); + canvas.drawRect(mMenuRect, PAINT); + PAINT.setColor(Color.BLUE); + PAINT.setAlpha(50); + canvas.drawRect(mBackRect, PAINT); + } + + if (drawZones) { + for (int x = mGestureRect.left; x < mGestureRect.right + SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH; x++) { + for (int y = mGestureRect.top; y < mGestureRect.bottom; y++) { + Point centered = getCenteredPos(new Point(x - mCursorDim.x / 2, y - mCursorDim.y / 2)); + final int zone; + if (Math.abs(centered.x) > Math.abs(centered.y)) { + // horizontally moving + final double pos = (double) centered.x / (double) mMaxPosX; + zone = findZone(pos); + PAINT.setColor(Color.MAGENTA); + } else { + // vertically moving + final double pos = (double) centered.y / (double) mMaxPosY; + zone = findZone(pos); + PAINT.setColor(Color.CYAN); + } + PAINT.setAlpha(10 * (Math.abs(zone) + 1)); + canvas.drawPoint(x, y, PAINT); + } + } + } + } + + /** + * Invalidates one of the four option buttons. + * + * @param buttonResId Button ID + */ + private void invalidateButton(int buttonResId) { + switch (buttonResId) { + case R.drawable.remote_xbox_gesture_title_down: + invalidate(mTitleRect); + break; + case R.drawable.remote_xbox_gesture_menu_down: + invalidate(mMenuRect); + break; + case R.drawable.remote_xbox_gesture_info_down: + invalidate(mInfoRect); + break; + case R.drawable.remote_xbox_gesture_back_down: + invalidate(mBackRect); + break; + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int eventaction = event.getAction(); + int x = (int) event.getX(); + int y = (int) event.getY(); + + switch (eventaction) { + /* + * Cursor is PRESSED + */ + case MotionEvent.ACTION_DOWN: + final int cursorX = mCursor.getX(); + final int cursorY = mCursor.getY(); + mIsDragging = x + CURSOR_POS_PADDING > cursorX && x - CURSOR_POS_PADDING < cursorX + mCursorDim.x && y + + CURSOR_POS_PADDING > cursorY && y - CURSOR_POS_PADDING < cursorY + mCursorDim.y; + if (mScrollerRect.contains(x, y)) { // tapping on scroll bar? + final Point target = getScrollTarget(x - mCursorDim.x / 2, y - mCursorDim.y / 2); + GestureRemoteAnimation anim = new GestureRemoteAnimation(target, mCursor); + anim.setDuration(ANIMATION_DURATION); + anim.setFadeOut(true); + startAnimation(anim); + mIsScrolling = true; + mDelta = new Point(mCursorDim.x / 2, mCursorDim.y / 2); + if (mListener != null && target.y > mOrigin.y) { + mListener.onScrollDown(); + } else if (mListener != null && target.y < mOrigin.y) { + mListener.onScrollUp(); + } +// invalidate(mGestureRect); + } else if (mTitleRect.contains(x, y)) { + mCurrentButtonPressed = R.drawable.remote_xbox_gesture_title_down; + invalidateButton(R.drawable.remote_xbox_gesture_title_down); + if (mListener != null) { + mListener.onTitle(); + } + } else if (mMenuRect.contains(x, y)) { + mCurrentButtonPressed = R.drawable.remote_xbox_gesture_menu_down; + invalidateButton(R.drawable.remote_xbox_gesture_menu_down); + if (mListener != null) { + mListener.onMenu(); + } + } else if (mInfoRect.contains(x, y)) { + mCurrentButtonPressed = R.drawable.remote_xbox_gesture_info_down; + invalidateButton(R.drawable.remote_xbox_gesture_info_down); + if (mListener != null) { + mListener.onInfo(); + } + } else if (mBackRect.contains(x, y)) { + mCurrentButtonPressed = R.drawable.remote_xbox_gesture_back_down; + invalidateButton(R.drawable.remote_xbox_gesture_back_down); + if (mListener != null) { + mListener.onBack(); + } + } else { + mDelta = new Point(x - cursorX, y - cursorY); + mIsScrolling = false; + mLastZone = 0; + } + mMoved = false; + break; + + /* + * Cursor is MOVED + */ + case MotionEvent.ACTION_MOVE: + // DRAGGING + if (mIsDragging) { + final Point from = mCursor.getPosition(); + x -= mDelta.x; + y -= mDelta.y; + Point target = getGestureTarget(x, y); + mCursor.setPosition(target); + + // calculate redraw aera + invalidate(mCursor.getDirty(from)); + + if (mListener != null) { + Point centered = getCenteredPos(target); + if (Math.abs(centered.x) > Math.abs(centered.y)) { + // horizontally moving + final double pos = (double) centered.x / (double) mMaxPosX; + final int zone = findZone(pos); + if (zone != mLastZone || (mLastDirection != HORIZ && zone != 0)) { + mListener.onHorizontalMove(zone); + mLastZone = zone; + mLastDirection = HORIZ; + if (zone != 0) { + mMoved = true; + } + } + } else { + // vertically moving + final double pos = (double) centered.y / (double) mMaxPosY; + final int zone = findZone(pos); + if (zone != mLastZone || (mLastDirection != VERT && zone != 0)) { + Log.d("GestureRemoteView", "launching onVerticalMove() with pos = " + pos); + mListener.onVerticalMove(zone); + mLastZone = zone; + mLastDirection = VERT; + if (zone != 0) { + mMoved = true; + } + } + } + } + // SCROLLING + } else if (mIsScrolling) { + final Point from = mCursor.getPosition(); + x -= mDelta.x; + y -= mDelta.y; + Point target = getScrollTarget(x, y); + mCursor.setPosition(target); + + // calculate redraw aera + invalidate(mCursor.getDirty(from)); + + if (mListener != null) { + Point centered = getCenteredPos(target); + final double pos = (double) centered.y / (double) mMaxPosY; + if (pos != mLastScrollValue) { + if (pos > 0) { + if (mLastScrollValue > 0 != pos > 0 && mMoved) { // direction changed? + mListener.onScrollUp(0); + } + if (pos != 0) { + mListener.onScrollDown(pos); + } + } else { + if (mLastScrollValue > 0 != pos > 0 && mMoved) { // direction changed? + mListener.onScrollDown(0); + } + if (pos != 0) { + mListener.onScrollUp(-pos); + } + } + mLastScrollValue = pos; + } + } + mMoved = true; + } + break; + + /* + * Cursor is RELEASED + */ + case MotionEvent.ACTION_UP: + if (mIsDragging || mIsScrolling) { + if (mListener != null && mIsDragging) { + if (mLastZone == 0 && !mMoved) { + mListener.onSelect(); + } else { + if (mLastZone != 0 && mLastDirection == HORIZ) { + mListener.onHorizontalMove(0); + } else if (mLastZone != 0 && mLastDirection == VERT) { + mListener.onVerticalMove(0); + } + } + mLastZone = 0; + } + if (mListener != null && mIsScrolling) { + if (mLastScrollValue > 0 && mMoved) { + mListener.onScrollDown(0); + } else if (mLastScrollValue < 0 && mMoved) { + mListener.onScrollUp(0); + } + } + GestureRemoteAnimation anim = new GestureRemoteAnimation(mOrigin, mCursor); + anim.setDuration(ANIMATION_DURATION); + if (mIsScrolling) { + anim.setFadeIn(true); + } + this.startAnimation(anim); + mIsDragging = false; + mIsScrolling = false; + } + if (mCurrentButtonPressed != 0) { + final int clearupBtn = mCurrentButtonPressed; + mCurrentButtonPressed = 0; + invalidateButton(clearupBtn); + } + break; + } + return true; + } + + /** + * Returns the point where the cursor is finally rendered. It basically + * crops the movement to the predefined boundaries. + * + * @param x X-value where user dragged the cursor + * @param y Y-value where user dragged the cursor + * @return Point where cursor is finally rendered. + */ + private Point getGestureTarget(int x, int y) { + int targetX, targetY; + Rect rect = mGestureRect; + if (x >= rect.left - CURSOR_NEG_PADDING) { + if (x + mCursorDim.x < rect.right + CURSOR_NEG_PADDING + (SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH)) { + targetX = x; + } else { + targetX = rect.right - mCursorDim.x + CURSOR_NEG_PADDING + (SCROLL_ZONE_WIDTH - RIGHT_BORDER_WIDTH); + } + } else { + targetX = rect.left - CURSOR_NEG_PADDING; + } + if (y >= rect.top - CURSOR_NEG_PADDING) { + if (y + mCursorDim.y < rect.bottom + CURSOR_NEG_PADDING) { + targetY = y; + } else { + targetY = rect.bottom - mCursorDim.y + CURSOR_NEG_PADDING; + } + } else { + targetY = rect.top - CURSOR_NEG_PADDING; + } + return new Point(targetX, targetY); + } + + private Point getScrollTarget(int x, int y) { + int targetX, targetY; + Rect rect = mScrollerRect; + // fix X and move only Y + targetX = rect.left - CURSOR_NEG_PADDING; + if (y >= rect.top - CURSOR_NEG_PADDING) { + if (y + mCursorDim.y < rect.bottom + CURSOR_NEG_PADDING) { + targetY = y; + } else { + targetY = rect.bottom - mCursorDim.y + CURSOR_NEG_PADDING; + } + } else { + targetY = rect.top - CURSOR_NEG_PADDING; + } + return new Point(targetX, targetY); + } + + /** + * Converts coordinates from Android's Origin (top left of the view) to + * the center of the screen. + * + * @param from + * @return + */ + private Point getCenteredPos(Point from) { + return new Point( + from.x - mGestureRect.left - (mGestureRect.width() - mCursorDim.x) / 2, + from.y - mGestureRect.top - (mGestureRect.height() - mCursorDim.y) / 2); + } + + /** + * Returns the index of the zone defined for a position. + * + * @param pos + * @return + */ + private int findZone(double pos) { + for (int i = 0; i < mZones.length; i++) { + if (Math.abs(pos) <= mZones[i]) { + return (pos > 0 ? 1 : -1) * i; + } + } + return (pos > 0 ? 1 : -1) * mZones.length; + } } \ No newline at end of file diff --git a/src/org/xbmc/android/widget/gestureremote/IGestureListener.java b/app/src/main/java/org/xbmc/android/widget/gestureremote/IGestureListener.java similarity index 97% rename from src/org/xbmc/android/widget/gestureremote/IGestureListener.java rename to app/src/main/java/org/xbmc/android/widget/gestureremote/IGestureListener.java index a88056e4..cba9d5e3 100644 --- a/src/org/xbmc/android/widget/gestureremote/IGestureListener.java +++ b/app/src/main/java/org/xbmc/android/widget/gestureremote/IGestureListener.java @@ -1,37 +1,48 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.gestureremote; - -public interface IGestureListener { - public void onVerticalMove(int zoneIndex); - public void onHorizontalMove(int zoneIndex); - public void onSelect(); - public void onScrollUp(double amount); - public void onScrollDown(double amount); - public void onScrollUp(); - public void onScrollDown(); - public void onMenu(); - public void onTitle(); - public void onInfo(); - public void onBack(); - public double[] getZones(); +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.gestureremote; + +public interface IGestureListener { + public void onVerticalMove(int zoneIndex); + + public void onHorizontalMove(int zoneIndex); + + public void onSelect(); + + public void onScrollUp(double amount); + + public void onScrollDown(double amount); + + public void onScrollUp(); + + public void onScrollDown(); + + public void onMenu(); + + public void onTitle(); + + public void onInfo(); + + public void onBack(); + + public double[] getZones(); } \ No newline at end of file diff --git a/src/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java similarity index 87% rename from src/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java rename to app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java index 82794f99..7d812166 100644 --- a/src/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java +++ b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabActivity.java @@ -1,213 +1,212 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.slidingtabs; - -import org.xbmc.android.remote.R; -import org.xbmc.android.remote.presentation.activity.HomeActivity; -import org.xbmc.android.util.KeyTracker; -import org.xbmc.android.util.OnLongPressBackKeyTracker; -import org.xbmc.android.util.KeyTracker.Stage; -import org.xbmc.api.type.ThumbSize; - -import android.app.Activity; -import android.app.ActivityGroup; -import android.content.Intent; -import android.os.Bundle; -import android.os.Build.VERSION; -import android.view.Display; -import android.view.KeyEvent; -import android.view.View; -import android.widget.TabHost; -import android.widget.TabWidget; -import android.widget.TextView; - -public class SlidingTabActivity extends ActivityGroup { - - private SlidingTabHost mTabHost; - private String mDefaultTab = null; - private int mDefaultTabIndex = -1; - private KeyTracker mKeyTracker = null; - - public SlidingTabActivity() { - if (Integer.parseInt(VERSION.SDK) < 5) { - mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { - - @Override - public void onLongPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - onKeyLongPress(keyCode, event); - } - - @Override - public void onShortPressBack(int keyCode, KeyEvent event, - Stage stage, int duration) { - callSuperOnKeyDown(keyCode, event); - } - - }); - } - } - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // set display size - final Display display = getWindowManager().getDefaultDisplay(); - ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); - } - - protected void callSuperOnKeyDown(int keyCode, KeyEvent event) { - super.onKeyDown(keyCode, event); - } - - /** - * Sets the default tab that is the first tab highlighted. - * - * @param tag - * the name of the default tab - */ - public void setDefaultTab(String tag) { - mDefaultTab = tag; - mDefaultTabIndex = -1; - } - - /** - * Sets the default tab that is the first tab highlighted. - * - * @param index - * the index of the default tab - */ - public void setDefaultTab(int index) { - mDefaultTab = null; - mDefaultTabIndex = index; - } - - @Override - protected void onRestoreInstanceState(Bundle state) { - super.onRestoreInstanceState(state); - ensureTabHost(); - String cur = state.getString("currentTab"); - if (cur != null) { - mTabHost.setCurrentTabByTag(cur); - } - if (mTabHost.getCurrentTab() < 0) { - if (mDefaultTab != null) { - mTabHost.setCurrentTabByTag(mDefaultTab); - } else if (mDefaultTabIndex >= 0) { - mTabHost.setCurrentTab(mDefaultTabIndex); - } - } - } - - @Override - protected void onPostCreate(Bundle icicle) { - super.onPostCreate(icicle); - - ensureTabHost(); - - if (mTabHost.getCurrentTab() == -1) { - mTabHost.setCurrentTab(0); - } - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - String currentTabTag = mTabHost.getCurrentTabTag(); - if (currentTabTag != null) { - outState.putString("currentTab", currentTabTag); - } - } - - /** - * Updates the screen state (current list and other views) when the content - * changes. - * - *@see Activity#onContentChanged() - */ - @Override - public void onContentChanged() { - super.onContentChanged(); - mTabHost = (SlidingTabHost) findViewById(R.id.slidingtabhost); - - if (mTabHost == null) { - throw new RuntimeException("Your content must have a TabHost whose id attribute is " + "'android.R.id.tabhost'"); - } - mTabHost.setup(getLocalActivityManager()); - } - - private void ensureTabHost() { - if (mTabHost == null) { - this.setContentView(R.id.slidingtabhost); - } - } - - @Override - protected void onChildTitleChanged(Activity childActivity, CharSequence title) { - // Dorky implementation until we can have multiple activities running. - if (getLocalActivityManager().getCurrentActivity() == childActivity) { - View tabView = mTabHost.getCurrentTabView(); - if (tabView != null && tabView instanceof TextView) { - ((TextView) tabView).setText(title); - } - } - } - - /** - * Returns the {@link TabHost} the activity is using to host its tabs. - * - * @return the {@link TabHost} the activity is using to host its tabs. - */ - public SlidingTabHost getTabHost() { - ensureTabHost(); - return mTabHost; - } - - /** - * Returns the {@link TabWidget} the activity is using to draw the actual - * tabs. - * - * @return the {@link TabWidget} the activity is using to draw the actual - * tabs. - */ - public SlidingTabWidget getTabWidget() { - return mTabHost.getTabWidget(); - } - - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - Intent intent = new Intent(SlidingTabActivity.this, HomeActivity.class); - intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - return true; - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyDown(keyCode, event):false; - return handled || super.onKeyDown(keyCode, event); - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - boolean handled = (mKeyTracker != null)?mKeyTracker.doKeyUp(keyCode, event):false; - return handled || super.onKeyUp(keyCode, event); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.slidingtabs; + +import android.app.Activity; +import android.app.ActivityGroup; +import android.content.Intent; +import android.os.Build.VERSION; +import android.os.Bundle; +import android.view.Display; +import android.view.KeyEvent; +import android.view.View; +import android.widget.TabHost; +import android.widget.TabWidget; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.remote.presentation.activity.HomeActivity; +import org.xbmc.android.util.KeyTracker; +import org.xbmc.android.util.KeyTracker.Stage; +import org.xbmc.android.util.OnLongPressBackKeyTracker; +import org.xbmc.api.type.ThumbSize; + +public class SlidingTabActivity extends ActivityGroup { + + private SlidingTabHost mTabHost; + private String mDefaultTab = null; + private int mDefaultTabIndex = -1; + private KeyTracker mKeyTracker = null; + + public SlidingTabActivity() { + if (Integer.parseInt(VERSION.SDK) < 5) { + mKeyTracker = new KeyTracker(new OnLongPressBackKeyTracker() { + + @Override + public void onLongPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + onKeyLongPress(keyCode, event); + } + + @Override + public void onShortPressBack(int keyCode, KeyEvent event, + Stage stage, int duration) { + callSuperOnKeyDown(keyCode, event); + } + + }); + } + } + + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // set display size + final Display display = getWindowManager().getDefaultDisplay(); + ThumbSize.setScreenSize(display.getWidth(), display.getHeight()); + } + + protected void callSuperOnKeyDown(int keyCode, KeyEvent event) { + super.onKeyDown(keyCode, event); + } + + /** + * Sets the default tab that is the first tab highlighted. + * + * @param tag the name of the default tab + */ + public void setDefaultTab(String tag) { + mDefaultTab = tag; + mDefaultTabIndex = -1; + } + + /** + * Sets the default tab that is the first tab highlighted. + * + * @param index the index of the default tab + */ + public void setDefaultTab(int index) { + mDefaultTab = null; + mDefaultTabIndex = index; + } + + @Override + protected void onRestoreInstanceState(Bundle state) { + super.onRestoreInstanceState(state); + ensureTabHost(); + String cur = state.getString("currentTab"); + if (cur != null) { + mTabHost.setCurrentTabByTag(cur); + } + if (mTabHost.getCurrentTab() < 0) { + if (mDefaultTab != null) { + mTabHost.setCurrentTabByTag(mDefaultTab); + } else if (mDefaultTabIndex >= 0) { + mTabHost.setCurrentTab(mDefaultTabIndex); + } + } + } + + @Override + protected void onPostCreate(Bundle icicle) { + super.onPostCreate(icicle); + + ensureTabHost(); + + if (mTabHost.getCurrentTab() == -1) { + mTabHost.setCurrentTab(0); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + String currentTabTag = mTabHost.getCurrentTabTag(); + if (currentTabTag != null) { + outState.putString("currentTab", currentTabTag); + } + } + + /** + * Updates the screen state (current list and other views) when the content + * changes. + * + * @see Activity#onContentChanged() + */ + @Override + public void onContentChanged() { + super.onContentChanged(); + mTabHost = (SlidingTabHost) findViewById(R.id.slidingtabhost); + + if (mTabHost == null) { + throw new RuntimeException("Your content must have a TabHost whose id attribute is " + "'android.R.id" + + ".tabhost'"); + } + mTabHost.setup(getLocalActivityManager()); + } + + private void ensureTabHost() { + if (mTabHost == null) { + this.setContentView(R.id.slidingtabhost); + } + } + + @Override + protected void onChildTitleChanged(Activity childActivity, CharSequence title) { + // Dorky implementation until we can have multiple activities running. + if (getLocalActivityManager().getCurrentActivity() == childActivity) { + View tabView = mTabHost.getCurrentTabView(); + if (tabView != null && tabView instanceof TextView) { + ((TextView) tabView).setText(title); + } + } + } + + /** + * Returns the {@link TabHost} the activity is using to host its tabs. + * + * @return the {@link TabHost} the activity is using to host its tabs. + */ + public SlidingTabHost getTabHost() { + ensureTabHost(); + return mTabHost; + } + + /** + * Returns the {@link TabWidget} the activity is using to draw the actual + * tabs. + * + * @return the {@link TabWidget} the activity is using to draw the actual + * tabs. + */ + public SlidingTabWidget getTabWidget() { + return mTabHost.getTabWidget(); + } + + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + Intent intent = new Intent(SlidingTabActivity.this, HomeActivity.class); + intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + return true; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyDown(keyCode, event) : false; + return handled || super.onKeyDown(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + boolean handled = (mKeyTracker != null) ? mKeyTracker.doKeyUp(keyCode, event) : false; + return handled || super.onKeyUp(keyCode, event); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java similarity index 91% rename from src/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java rename to app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java index f3973d7a..5b247418 100644 --- a/src/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java +++ b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabHost.java @@ -1,585 +1,589 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.slidingtabs; - -import java.util.ArrayList; -import java.util.List; - -import org.xbmc.android.remote.R; - -import android.app.LocalActivityManager; -import android.content.Context; -import android.content.Intent; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.Window; -import android.widget.FrameLayout; - -/** - * Container for a tabbed window view. This object holds two children: a set of - * tab labels that the user clicks to select a specific tab, and a FrameLayout - * object that displays the contents of that page. The individual elements are - * typically controlled using this container object, rather than setting values - * on the child elements themselves. - */ -public class SlidingTabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener { - - private SlidingTabWidget mTabWidget; - private FrameLayout mTabContent; - private List mTabSpecs = new ArrayList(2); - /** - * This field should be made private, so it is hidden from the SDK. {@hide - * } - */ - protected int mCurrentTab = -1; - private View mCurrentView = null; - /** - * This field should be made private, so it is hidden from the SDK. {@hide - * } - */ - protected LocalActivityManager mLocalActivityManager = null; - private OnTabChangeListener mOnTabChangeListener; - - public SlidingTabHost(Context context) { - super(context); - initTabHost(); - } - - public SlidingTabHost(Context context, AttributeSet attrs) { - super(context, attrs); - initTabHost(); - } - - private final void initTabHost() { - setFocusableInTouchMode(true); - setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); - - mCurrentTab = -1; - mCurrentView = null; - } - - /** - * Get a new {@link SlidingTabSpec} associated with this tab host. - * - * @param tag - * required tag of tab. - */ - public SlidingTabSpec newTabSpec(String tag, String label, int resActiveIcon, int resInactiveIcon) { - return new SlidingTabSpec(tag, label, resActiveIcon, resInactiveIcon); - } - - /** - *

- * Call setup() before adding tabs if loading SlidingTabHost using - * findViewById(). However: You do not need to call setup() - * after getTabHost() in {@link android.app.TabActivity TabActivity}. - * Example: - *

- * - *
-	 * mTabHost = (SlidingTabHost) findViewById(R.id.tabhost);
-	 * mTabHost.setup();
-	 * mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
-	 */
-	public void setup() {
-		mTabWidget = (SlidingTabWidget) findViewById(R.id.slidingtabs);
-		if (mTabWidget == null) {
-			throw new RuntimeException("Your SlidingTabHost must have a SlidingTabWidget whose id attribute is 'R.id.slidingtabs'");
-		}
-
-		mTabWidget.setTabSelectionListener(new SlidingTabWidget.OnTabSelectionChanged() {
-			public void onTabSelectionChanged(int tabIndex, boolean clicked) {
-				setCurrentTab(tabIndex);
-				if (clicked) {
-					mTabContent.requestFocus(View.FOCUS_FORWARD);
-				}
-			}
-		});
-
-		mTabContent = (FrameLayout) findViewById(R.id.slidingtabcontent);
-		if (mTabContent == null) {
-			throw new RuntimeException("Your SlidingTabHost must have a FrameLayout whose id attribute is 'android.R.id.tabcontent'");
-		}
-		mTabWidget.setTabContent(mTabContent);
-		
-	}
-
-	/**
-	 * If you are using {@link SlidingTabSpec#setContent(android.content.Intent)}, this
-	 * must be called since the activityGroup is needed to launch the local
-	 * activity.
-	 * 
-	 * This is done for you if you extend {@link android.app.TabActivity}.
-	 * 
-	 * @param activityGroup
-	 *            Used to launch activities for tab content.
-	 */
-	public void setup(LocalActivityManager activityGroup) {
-		setup();
-		mLocalActivityManager = activityGroup;
-	}
-
-	@Override
-	protected void onAttachedToWindow() {
-		super.onAttachedToWindow();
-		final ViewTreeObserver treeObserver = getViewTreeObserver();
-		if (treeObserver != null) {
-			treeObserver.addOnTouchModeChangeListener(this);
-		}
-	}
-
-	@Override
-	protected void onDetachedFromWindow() {
-		super.onDetachedFromWindow();
-		final ViewTreeObserver treeObserver = getViewTreeObserver();
-		if (treeObserver != null) {
-			treeObserver.removeOnTouchModeChangeListener(this);
-		}
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	public void onTouchModeChanged(boolean isInTouchMode) {
-		if (!isInTouchMode) {
-			// leaving touch mode.. if nothing has focus, let's give it to
-			// the indicator of the current tab
-			if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) {
-				mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus();
-			}
-		}
-	}
-
-	/**
-	 * Add a tab.
-	 * 
-	 * @param tabSpec
-	 *            Specifies how to create the indicator and content.
-	 */
-	public void addTab(SlidingTabSpec tabSpec) {
-		
-//		LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-//		View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, false);
-
-		if (tabSpec.mContentStrategy == null) {
-			throw new IllegalArgumentException("you must specify a way to create the tab content");
-		}
-
-		mTabWidget.addTab(tabSpec); //.setOnKeyListener(mTabKeyListener);
-//		mTabWidget.updateOnKeyListener(mTabKeyListener);
-		mTabSpecs.add(tabSpec);
-
-		if (mCurrentTab == -1) {
-			setCurrentTab(0);
-		}
-	}
-	
-	/*
-	 * Moves the slider to the given tab and switches the content 
-	 */
-	public void selectTabByTag(String tag) {
-		int i;
-		for (i = 0; i < mTabSpecs.size(); i++) {
-			if (mTabSpecs.get(i).getTag().equals(tag)) {
-				setCurrentTab(i);
-				mTabWidget.moveTo(i);
-				break;
-			}
-		}
-	}
-
-	/**
-	 * Removes all tabs from the tab widget associated with this tab host.
-	 */
-	public void clearAllTabs() {
-		mTabWidget.removeAllViews();
-		initTabHost();
-		mTabContent.removeAllViews();
-		mTabSpecs.clear();
-		requestLayout();
-		invalidate();
-	}
-
-	public SlidingTabWidget getTabWidget() {
-		return mTabWidget;
-	}
-
-	public int getCurrentTab() {
-		return mCurrentTab;
-	}
-
-	public String getCurrentTabTag() {
-		if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
-			return mTabSpecs.get(mCurrentTab).getTag();
-		}
-		return null;
-	}
-
-	public View getCurrentTabView() {
-		if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) {
-			return mTabWidget.getChildTabViewAt(mCurrentTab);
-		}
-		return null;
-	}
-
-	public View getCurrentView() {
-		return mCurrentView;
-	}
-
-	public void setCurrentTabByTag(String tag) {
-		int i;
-		for (i = 0; i < mTabSpecs.size(); i++) {
-			if (mTabSpecs.get(i).getTag().equals(tag)) {
-				setCurrentTab(i);
-				break;
-			}
-		}
-	}
-
-	/**
-	 * Get the FrameLayout which holds tab content
-	 */
-	public FrameLayout getTabContentView() {
-		return mTabContent;
-	}
-
-	@Override
-	public boolean dispatchKeyEvent(KeyEvent event) {
-		switch (event.getKeyCode()) {
-			case KeyEvent.KEYCODE_DPAD_LEFT:
-				if (event.getAction() == KeyEvent.ACTION_DOWN) {
-					final int tabIndex = mCurrentTab - 1;
-					if (tabIndex >= 0) {
-						setCurrentTab(tabIndex);
-						mTabWidget.moveTo(tabIndex);
-					}
-				}
-				return true;
-			case KeyEvent.KEYCODE_DPAD_RIGHT:
-				if (event.getAction() == KeyEvent.ACTION_DOWN) {
-					final int tabIndex = mCurrentTab + 1;
-					if (tabIndex <= mTabWidget.getTabCount()) {
-						setCurrentTab(tabIndex);
-						mTabWidget.moveTo(tabIndex);
-					}
-				}
-				return true;
-			default:
-				return super.dispatchKeyEvent(event);
-		}
-	}
-
-
-	@Override
-	public void dispatchWindowFocusChanged(boolean hasFocus) {
-		View v = mCurrentView;
-		if (v != null) {
-			mCurrentView.dispatchWindowFocusChanged(hasFocus);
-		}
-	}
-
-	public void setCurrentTab(int index) {
-		if (index < 0 || index >= mTabSpecs.size()) {
-			return;
-		}
-
-		if (index == mCurrentTab) {
-			return;
-		}
-
-		// notify old tab content
-		if (mCurrentTab != -1) {
-			mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed();
-		}
-
-		mCurrentTab = index;
-		final SlidingTabHost.SlidingTabSpec spec = mTabSpecs.get(index);
-
-		// Call the tab widget's focusCurrentTab(), instead of just
-		// selecting the tab.
-//		mTabWidget.focusCurrentTab(mCurrentTab);
-
-		// tab content
-		mCurrentView = spec.mContentStrategy.getContentView();
-
-		if (mCurrentView.getParent() == null) {
-			mTabContent.addView(mCurrentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
-		}
-
-		if (!mTabWidget.hasFocus()) {
-			// if the tab widget didn't take focus (likely because we're in
-			// touch mode)
-			// give the current tab content view a shot
-			mCurrentView.requestFocus();
-		}
-
-		// mTabContent.requestFocus(View.FOCUS_FORWARD);
-		invokeOnTabChangeListener();
-	}
-
-	/**
-	 * Register a callback to be invoked when the selected state of any of the
-	 * items in this list changes
-	 * 
-	 * @param l
-	 *            The callback that will run
-	 */
-	public void setOnTabChangedListener(OnTabChangeListener l) {
-		mOnTabChangeListener = l;
-	}
-
-	private void invokeOnTabChangeListener() {
-		if (mOnTabChangeListener != null) {
-			mOnTabChangeListener.onTabChanged(getCurrentTabTag());
-		}
-	}
-
-	/**
-	 * Interface definition for a callback to be invoked when tab changed
-	 */
-	public interface OnTabChangeListener {
-		void onTabChanged(String tabId);
-	}
-
-	/**
-	 * Makes the content of a tab when it is selected. Use this if your tab
-	 * content needs to be created on demand, i.e. you are not showing an
-	 * existing view or starting an activity.
-	 */
-	public interface TabContentFactory {
-		/**
-		 * Callback to make the tab contents
-		 * 
-		 * @param tag
-		 *            Which tab was selected.
-		 * @return The view to display the contents of the selected tab.
-		 */
-		View createTabContent(String tag);
-	}
-
-	/**
-	 * A sliding tab has an active icon, a passive icon, a big icon and a text.A tab has a tab indicator, content, and a tag that is used to keep track
-	 * of it. This builder helps choose among these options.
-	 * 
-	 * For the tab indicator, your choices are: 1) set a label 2) set a label
-	 * and an icon
-	 * 
-	 * For the tab content, your choices are: 1) the id of a {@link View} 2) a
-	 * {@link TabContentFactory} that creates the {@link View} content. 3) an
-	 * {@link Intent} that launches an {@link android.app.Activity}.
-	 */
-	public class SlidingTabSpec {
-
-		private String mTag;
-		private int mBigIcon = -1;
-		
-		private final int mActiveIcon;
-		private final int mInactiveIcon;
-		private final String mLabel;
-		
-		private ContentStrategy mContentStrategy;
-
-		private SlidingTabSpec(String tag, String label, int resActiveIcon, int resInactiveIcon) {
-			mTag = tag;
-			mLabel = label;
-			mActiveIcon = resActiveIcon;
-			mInactiveIcon = resInactiveIcon;
-		}
-		
-		/**
-		 * Sets the big icon display in the content zone while sliding.
-		 */
-		public SlidingTabSpec setBigIcon(int resBigIcon) {
-			mBigIcon = resBigIcon;
-			return this;
-		}
-
-		/**
-		 * Specify the id of the view that should be used as the content of the
-		 * tab.
-		 */
-		public SlidingTabSpec setContent(int viewId) {
-			mContentStrategy = new ViewIdContentStrategy(viewId);
-			return this;
-		}
-
-		/**
-		 * Specify a {@link android.widget.TabHost.TabContentFactory} to use to
-		 * create the content of the tab.
-		 */
-		public SlidingTabSpec setContent(TabContentFactory contentFactory) {
-			mContentStrategy = new FactoryContentStrategy(mTag, contentFactory);
-			return this;
-		}
-
-		/**
-		 * Specify an intent to use to launch an activity as the tab content.
-		 */
-		public SlidingTabSpec setContent(Intent intent) {
-			mContentStrategy = new IntentContentStrategy(mTag, intent);
-			return this;
-		}
-
-		public String getTag() {
-			return mTag;
-		}
-		public int getActiveIconResource() {
-			return mActiveIcon;
-		}
-		public int getInactiveIconResource() {
-			return mInactiveIcon;
-		}
-		public String getLabel() {
-			return mLabel;
-		}
-		public int getBigIconResource() {
-			return mBigIcon;
-		}
-		
-		
-	}
-
-	/**
-	 * Specifies what you do to manage the tab content.
-	 */
-	private static interface ContentStrategy {
-
-		/**
-		 * Return the content view. The view should may be cached locally.
-		 */
-		View getContentView();
-
-		/**
-		 * Perhaps do something when the tab associated with this content has
-		 * been closed (i.e make it invisible, or remove it).
-		 */
-		void tabClosed();
-	}
-
-	/**
-	 * How to create the tab content via a view id.
-	 */
-	private class ViewIdContentStrategy implements ContentStrategy {
-
-		private final View mView;
-
-		private ViewIdContentStrategy(int viewId) {
-			mView = mTabContent.findViewById(viewId);
-			if (mView != null) {
-				mView.setVisibility(View.GONE);
-			} else {
-				throw new RuntimeException("Could not create tab content because " + "could not find view with id " + viewId);
-			}
-		}
-
-		public View getContentView() {
-			mView.setVisibility(View.VISIBLE);
-			return mView;
-		}
-
-		public void tabClosed() {
-			mView.setVisibility(View.GONE);
-		}
-	}
-
-	/**
-	 * How tab content is managed using {@link TabContentFactory}.
-	 */
-	private class FactoryContentStrategy implements ContentStrategy {
-		private View mTabContent;
-		private final CharSequence mTag;
-		private TabContentFactory mFactory;
-
-		public FactoryContentStrategy(CharSequence tag, TabContentFactory factory) {
-			mTag = tag;
-			mFactory = factory;
-		}
-
-		public View getContentView() {
-			if (mTabContent == null) {
-				mTabContent = mFactory.createTabContent(mTag.toString());
-			}
-			mTabContent.setVisibility(View.VISIBLE);
-			return mTabContent;
-		}
-
-		public void tabClosed() {
-			mTabContent.setVisibility(View.INVISIBLE);
-		}
-	}
-
-	/**
-	 * How tab content is managed via an {@link Intent}: the content view is the
-	 * decorview of the launched activity.
-	 */
-	private class IntentContentStrategy implements ContentStrategy {
-
-		private final String mTag;
-		private final Intent mIntent;
-
-		private View mLaunchedView;
-
-		private IntentContentStrategy(String tag, Intent intent) {
-			mTag = tag;
-			mIntent = intent;
-		}
-
-		public View getContentView() {
-			if (mLocalActivityManager == null) {
-				throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager activityGroup)'?");
-			}
-			final Window w = mLocalActivityManager.startActivity(mTag, mIntent);
-			final View wd = w != null ? w.getDecorView() : null;
-			if (mLaunchedView != wd && mLaunchedView != null) {
-				if (mLaunchedView.getParent() != null) {
-					mTabContent.removeView(mLaunchedView);
-				}
-			}
-			mLaunchedView = wd;
-
-			// XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so
-			// they can get
-			// focus if none of their children have it. They need focus to be
-			// able to
-			// display menu items.
-			//
-			// Replace this with something better when Bug 628886 is fixed...
-			//
-			if (mLaunchedView != null) {
-				mLaunchedView.setVisibility(View.VISIBLE);
-				mLaunchedView.setFocusableInTouchMode(true);
-				((ViewGroup) mLaunchedView).setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
-			}
-			return mLaunchedView;
-		}
-
-		public void tabClosed() {
-			if (mLaunchedView != null) {
-				mLaunchedView.setVisibility(View.GONE);
-			}
-		}
-	}
-
-}
+/*
+ *      Copyright (C) 2005-2009 Team XBMC
+ *      http://xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC Remote; see the file license.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+package org.xbmc.android.widget.slidingtabs;
+
+import android.app.LocalActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.Window;
+import android.widget.FrameLayout;
+
+import org.xbmc.android.remote.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Container for a tabbed window view. This object holds two children: a set of
+ * tab labels that the user clicks to select a specific tab, and a FrameLayout
+ * object that displays the contents of that page. The individual elements are
+ * typically controlled using this container object, rather than setting values
+ * on the child elements themselves.
+ */
+public class SlidingTabHost extends FrameLayout implements ViewTreeObserver.OnTouchModeChangeListener {
+
+	/**
+	 * This field should be made private, so it is hidden from the SDK. {@hide
+	 * }
+	 */
+	protected int mCurrentTab = -1;
+	/**
+	 * This field should be made private, so it is hidden from the SDK. {@hide
+	 * }
+	 */
+	protected LocalActivityManager mLocalActivityManager = null;
+	private SlidingTabWidget mTabWidget;
+	private FrameLayout mTabContent;
+	private List mTabSpecs = new ArrayList(2);
+	private View mCurrentView = null;
+	private OnTabChangeListener mOnTabChangeListener;
+
+	public SlidingTabHost(Context context) {
+		super(context);
+		initTabHost();
+	}
+
+	public SlidingTabHost(Context context, AttributeSet attrs) {
+		super(context, attrs);
+		initTabHost();
+	}
+
+	private final void initTabHost() {
+		setFocusableInTouchMode(true);
+		setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+
+		mCurrentTab = -1;
+		mCurrentView = null;
+	}
+
+	/**
+	 * Get a new {@link SlidingTabSpec} associated with this tab host.
+	 *
+	 * @param tag required tag of tab.
+	 */
+	public SlidingTabSpec newTabSpec(String tag, String label, int resActiveIcon, int resInactiveIcon) {
+		return new SlidingTabSpec(tag, label, resActiveIcon, resInactiveIcon);
+	}
+
+	/**
+	 * 

+ * Call setup() before adding tabs if loading SlidingTabHost using + * findViewById(). However: You do not need to call setup() + * after getTabHost() in {@link android.app.TabActivity TabActivity}. + * Example: + *

+ *

+ *

+	 * mTabHost = (SlidingTabHost) findViewById(R.id.tabhost);
+	 * mTabHost.setup();
+	 * mTabHost.addTab(TAB_TAG_1, "Hello, world!", "Tab 1");
+	 */
+	public void setup() {
+		mTabWidget = (SlidingTabWidget) findViewById(R.id.slidingtabs);
+		if (mTabWidget == null) {
+			throw new RuntimeException("Your SlidingTabHost must have a SlidingTabWidget whose id attribute is 'R.id" +
+					".slidingtabs'");
+		}
+
+		mTabWidget.setTabSelectionListener(new SlidingTabWidget.OnTabSelectionChanged() {
+			public void onTabSelectionChanged(int tabIndex, boolean clicked) {
+				setCurrentTab(tabIndex);
+				if (clicked) {
+					mTabContent.requestFocus(View.FOCUS_FORWARD);
+				}
+			}
+		});
+
+		mTabContent = (FrameLayout) findViewById(R.id.slidingtabcontent);
+		if (mTabContent == null) {
+			throw new RuntimeException("Your SlidingTabHost must have a FrameLayout whose id attribute is 'android.R" +
+					".id.tabcontent'");
+		}
+		mTabWidget.setTabContent(mTabContent);
+
+	}
+
+	/**
+	 * If you are using {@link SlidingTabSpec#setContent(android.content.Intent)}, this
+	 * must be called since the activityGroup is needed to launch the local
+	 * activity.
+	 * 

+ * This is done for you if you extend {@link android.app.TabActivity}. + * + * @param activityGroup Used to launch activities for tab content. + */ + public void setup(LocalActivityManager activityGroup) { + setup(); + mLocalActivityManager = activityGroup; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + final ViewTreeObserver treeObserver = getViewTreeObserver(); + if (treeObserver != null) { + treeObserver.addOnTouchModeChangeListener(this); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + final ViewTreeObserver treeObserver = getViewTreeObserver(); + if (treeObserver != null) { + treeObserver.removeOnTouchModeChangeListener(this); + } + } + + /** + * {@inheritDoc} + */ + public void onTouchModeChanged(boolean isInTouchMode) { + if (!isInTouchMode) { + // leaving touch mode.. if nothing has focus, let's give it to + // the indicator of the current tab + if (!mCurrentView.hasFocus() || mCurrentView.isFocused()) { + mTabWidget.getChildTabViewAt(mCurrentTab).requestFocus(); + } + } + } + + /** + * Add a tab. + * + * @param tabSpec Specifies how to create the indicator and content. + */ + public void addTab(SlidingTabSpec tabSpec) { + +// LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); +// View tabIndicator = inflater.inflate(R.layout.tab_indicator, mTabWidget, false); + + if (tabSpec.mContentStrategy == null) { + throw new IllegalArgumentException("you must specify a way to create the tab content"); + } + + mTabWidget.addTab(tabSpec); //.setOnKeyListener(mTabKeyListener); +// mTabWidget.updateOnKeyListener(mTabKeyListener); + mTabSpecs.add(tabSpec); + + if (mCurrentTab == -1) { + setCurrentTab(0); + } + } + + /* + * Moves the slider to the given tab and switches the content + */ + public void selectTabByTag(String tag) { + int i; + for (i = 0; i < mTabSpecs.size(); i++) { + if (mTabSpecs.get(i).getTag().equals(tag)) { + setCurrentTab(i); + mTabWidget.moveTo(i); + break; + } + } + } + + /** + * Removes all tabs from the tab widget associated with this tab host. + */ + public void clearAllTabs() { + mTabWidget.removeAllViews(); + initTabHost(); + mTabContent.removeAllViews(); + mTabSpecs.clear(); + requestLayout(); + invalidate(); + } + + public SlidingTabWidget getTabWidget() { + return mTabWidget; + } + + public int getCurrentTab() { + return mCurrentTab; + } + + public void setCurrentTab(int index) { + if (index < 0 || index >= mTabSpecs.size()) { + return; + } + + if (index == mCurrentTab) { + return; + } + + // notify old tab content + if (mCurrentTab != -1) { + mTabSpecs.get(mCurrentTab).mContentStrategy.tabClosed(); + } + + mCurrentTab = index; + final SlidingTabHost.SlidingTabSpec spec = mTabSpecs.get(index); + + // Call the tab widget's focusCurrentTab(), instead of just + // selecting the tab. +// mTabWidget.focusCurrentTab(mCurrentTab); + + // tab content + mCurrentView = spec.mContentStrategy.getContentView(); + + if (mCurrentView.getParent() == null) { + mTabContent.addView(mCurrentView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT)); + } + + if (!mTabWidget.hasFocus()) { + // if the tab widget didn't take focus (likely because we're in + // touch mode) + // give the current tab content view a shot + mCurrentView.requestFocus(); + } + + // mTabContent.requestFocus(View.FOCUS_FORWARD); + invokeOnTabChangeListener(); + } + + public String getCurrentTabTag() { + if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) { + return mTabSpecs.get(mCurrentTab).getTag(); + } + return null; + } + + public View getCurrentTabView() { + if (mCurrentTab >= 0 && mCurrentTab < mTabSpecs.size()) { + return mTabWidget.getChildTabViewAt(mCurrentTab); + } + return null; + } + + public View getCurrentView() { + return mCurrentView; + } + + public void setCurrentTabByTag(String tag) { + int i; + for (i = 0; i < mTabSpecs.size(); i++) { + if (mTabSpecs.get(i).getTag().equals(tag)) { + setCurrentTab(i); + break; + } + } + } + + /** + * Get the FrameLayout which holds tab content + */ + public FrameLayout getTabContentView() { + return mTabContent; + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + switch (event.getKeyCode()) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (event.getAction() == KeyEvent.ACTION_DOWN) { + final int tabIndex = mCurrentTab - 1; + if (tabIndex >= 0) { + setCurrentTab(tabIndex); + mTabWidget.moveTo(tabIndex); + } + } + return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (event.getAction() == KeyEvent.ACTION_DOWN) { + final int tabIndex = mCurrentTab + 1; + if (tabIndex <= mTabWidget.getTabCount()) { + setCurrentTab(tabIndex); + mTabWidget.moveTo(tabIndex); + } + } + return true; + default: + return super.dispatchKeyEvent(event); + } + } + + @Override + public void dispatchWindowFocusChanged(boolean hasFocus) { + View v = mCurrentView; + if (v != null) { + mCurrentView.dispatchWindowFocusChanged(hasFocus); + } + } + + /** + * Register a callback to be invoked when the selected state of any of the + * items in this list changes + * + * @param l The callback that will run + */ + public void setOnTabChangedListener(OnTabChangeListener l) { + mOnTabChangeListener = l; + } + + private void invokeOnTabChangeListener() { + if (mOnTabChangeListener != null) { + mOnTabChangeListener.onTabChanged(getCurrentTabTag()); + } + } + + /** + * Interface definition for a callback to be invoked when tab changed + */ + public interface OnTabChangeListener { + void onTabChanged(String tabId); + } + + /** + * Makes the content of a tab when it is selected. Use this if your tab + * content needs to be created on demand, i.e. you are not showing an + * existing view or starting an activity. + */ + public interface TabContentFactory { + /** + * Callback to make the tab contents + * + * @param tag Which tab was selected. + * @return The view to display the contents of the selected tab. + */ + View createTabContent(String tag); + } + + + /** + * Specifies what you do to manage the tab content. + */ + private static interface ContentStrategy { + + /** + * Return the content view. The view should may be cached locally. + */ + View getContentView(); + + /** + * Perhaps do something when the tab associated with this content has + * been closed (i.e make it invisible, or remove it). + */ + void tabClosed(); + } + + /** + * /** + * A sliding tab has an active icon, a passive icon, a big icon and a text.A tab has a tab indicator, content, + * and a tag that is used to keep track + * of it. This builder helps choose among these options. + *

+ * For the tab indicator, your choices are: 1) set a label 2) set a label + * and an icon + *

+ * For the tab content, your choices are: 1) the id of a {@link View} 2) a + * {@link TabContentFactory} that creates the {@link View} content. 3) an + * {@link Intent} that launches an {@link android.app.Activity}. + */ + public class SlidingTabSpec { + + private final int mActiveIcon; + private final int mInactiveIcon; + private final String mLabel; + private String mTag; + private int mBigIcon = -1; + private ContentStrategy mContentStrategy; + + private SlidingTabSpec(String tag, String label, int resActiveIcon, int resInactiveIcon) { + mTag = tag; + mLabel = label; + mActiveIcon = resActiveIcon; + mInactiveIcon = resInactiveIcon; + } + + /** + * Sets the big icon display in the content zone while sliding. + */ + public SlidingTabSpec setBigIcon(int resBigIcon) { + mBigIcon = resBigIcon; + return this; + } + + /** + * Specify the id of the view that should be used as the content of the + * tab. + */ + public SlidingTabSpec setContent(int viewId) { + mContentStrategy = new ViewIdContentStrategy(viewId); + return this; + } + + /** + * Specify a {@link android.widget.TabHost.TabContentFactory} to use to + * create the content of the tab. + */ + public SlidingTabSpec setContent(TabContentFactory contentFactory) { + mContentStrategy = new FactoryContentStrategy(mTag, contentFactory); + return this; + } + + /** + * Specify an intent to use to launch an activity as the tab content. + */ + public SlidingTabSpec setContent(Intent intent) { + mContentStrategy = new IntentContentStrategy(mTag, intent); + return this; + } + + public String getTag() { + return mTag; + } + + public int getActiveIconResource() { + return mActiveIcon; + } + + public int getInactiveIconResource() { + return mInactiveIcon; + } + + public String getLabel() { + return mLabel; + } + + public int getBigIconResource() { + return mBigIcon; + } + + + } + + /** + * How to create the tab content via a view id. + */ + private class ViewIdContentStrategy implements ContentStrategy { + + private final View mView; + + private ViewIdContentStrategy(int viewId) { + mView = mTabContent.findViewById(viewId); + if (mView != null) { + mView.setVisibility(View.GONE); + } else { + throw new RuntimeException("Could not create tab content because " + "could not find view with id " + + viewId); + } + } + + public View getContentView() { + mView.setVisibility(View.VISIBLE); + return mView; + } + + public void tabClosed() { + mView.setVisibility(View.GONE); + } + } + + /** + * How tab content is managed using {@link TabContentFactory}. + */ + private class FactoryContentStrategy implements ContentStrategy { + private final CharSequence mTag; + private View mTabContent; + private TabContentFactory mFactory; + + public FactoryContentStrategy(CharSequence tag, TabContentFactory factory) { + mTag = tag; + mFactory = factory; + } + + public View getContentView() { + if (mTabContent == null) { + mTabContent = mFactory.createTabContent(mTag.toString()); + } + mTabContent.setVisibility(View.VISIBLE); + return mTabContent; + } + + public void tabClosed() { + mTabContent.setVisibility(View.INVISIBLE); + } + } + + /** + * How tab content is managed via an {@link Intent}: the content view is the + * decorview of the launched activity. + */ + private class IntentContentStrategy implements ContentStrategy { + + private final String mTag; + private final Intent mIntent; + + private View mLaunchedView; + + private IntentContentStrategy(String tag, Intent intent) { + mTag = tag; + mIntent = intent; + } + + public View getContentView() { + if (mLocalActivityManager == null) { + throw new IllegalStateException("Did you forget to call 'public void setup(LocalActivityManager " + + "activityGroup)'?"); + } + final Window w = mLocalActivityManager.startActivity(mTag, mIntent); + final View wd = w != null ? w.getDecorView() : null; + if (mLaunchedView != wd && mLaunchedView != null) { + if (mLaunchedView.getParent() != null) { + mTabContent.removeView(mLaunchedView); + } + } + mLaunchedView = wd; + + // XXX Set FOCUS_AFTER_DESCENDANTS on embedded activities for now so + // they can get + // focus if none of their children have it. They need focus to be + // able to + // display menu items. + // + // Replace this with something better when Bug 628886 is fixed... + // + if (mLaunchedView != null) { + mLaunchedView.setVisibility(View.VISIBLE); + mLaunchedView.setFocusableInTouchMode(true); + ((ViewGroup) mLaunchedView).setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); + } + return mLaunchedView; + } + + public void tabClosed() { + if (mLaunchedView != null) { + mLaunchedView.setVisibility(View.GONE); + } + } + } + +} diff --git a/src/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java similarity index 85% rename from src/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java rename to app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java index 5d7acd71..3cf01158 100644 --- a/src/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java +++ b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabScrollView.java @@ -1,61 +1,65 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.slidingtabs; - -import org.xbmc.android.remote.R; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; - -/** - * This is roughly taken from Android's HorizontalScrollView code. The idea - * is to have a view that can be as large as its content but doesn't scroll - * - * @author Team XBMC - */ -public class SlidingTabScrollView extends FrameLayout { - - public SlidingTabScrollView(Context context) { - this(context, null); - } - - public SlidingTabScrollView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.slidingTabScrollViewStyle); - } - - public SlidingTabScrollView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { - final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); - - final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin - + heightUsed, lp.height); - final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED); - - child.measure(childWidthMeasureSpec, childHeightMeasureSpec); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.slidingtabs; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.FrameLayout; + +import org.xbmc.android.remote.R; + +/** + * This is roughly taken from Android's HorizontalScrollView code. The idea + * is to have a view that can be as large as its content but doesn't scroll + * + * @author Team XBMC + */ +public class SlidingTabScrollView extends FrameLayout { + + public SlidingTabScrollView(Context context) { + this(context, null); + } + + public SlidingTabScrollView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.slidingTabScrollViewStyle); + } + + public SlidingTabScrollView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, + int parentHeightMeasureSpec, int heightUsed) { + final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); + + final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, + getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin + + heightUsed, lp.height + ); + final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.leftMargin + lp.rightMargin, + MeasureSpec.UNSPECIFIED); + + child.measure(childWidthMeasureSpec, childHeightMeasureSpec); + } } \ No newline at end of file diff --git a/src/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java similarity index 77% rename from src/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java rename to app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java index 523e5732..a089eb55 100644 --- a/src/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java +++ b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SlidingTabWidget.java @@ -1,563 +1,569 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.slidingtabs; - -import org.xbmc.android.remote.R; -import org.xbmc.android.widget.slidingtabs.SlidingTabHost.SlidingTabSpec; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TabHost; -import android.widget.TextView; - -/** - * Displays the sliding tabs. - * - * Displays a list of icons representing each page in the parent's tab - * collection. The container object for this widget is - * {@link org.xbmc.android.widget.slidingtabs.SlidingTabHost SlidingTabHost}. - * When the user selects a tab, this object sends a message to the parent - * container, SlidingTabHost, to tell it to switch the displayed page. You - * typically won't use many methods directly on this object. The container - * SlidingTabHost is used to add labels, add the callback handler, and manage - * callbacks. - * - * @author Team XBMC - */ -public class SlidingTabWidget extends LinearLayout { - - private final static int SCROLLBAR_HEIGHT = 42; - private final static int SHADOW_PADDING = 18; - - private int mSeparationWidth; - - protected Context mContext; - - private OnTabSelectionChanged mSelectionChangedListener; - private int mSelectedTab = 0; - - private final LinearLayout mOuterLayout; - private final ImageButton mSlider; - private final LinearLayout mInverseSliderBackground; - private final LinearLayout mOverlayLayout; - - private final ImageView mOverlayIcon; - private final TextView mOverlayText; - - private final SnapAnimation mSnapAnimation; - - private FrameLayout mTabContent; - - private int mNumTabs = 0; - private int mInverseSliderWidth = 0; - - private int mSliderMoveWidth = 0; - private int mBackMoveWidth = 0; - float mBackMoveFactor = 0; - - private static float sScale; - - - public SlidingTabWidget(Context context) { - this(context, null); - mContext = context; - } - - public SlidingTabWidget(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.slidingTabWidgetStyle); - mContext = context; - } - - public SlidingTabWidget(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs); - - sScale = context.getResources().getDisplayMetrics().density; - - mContext = context; - setOrientation(LinearLayout.HORIZONTAL); - - // inflate widget layout from xml - inflate(context, R.layout.slidingtab_widget, this); - - // set all the view references - mOuterLayout = (LinearLayout)findViewById(R.id.SlidingTabLinearLayoutOuter); - mSlider = (ImageButton)findViewById(R.id.SlidingTabImageButtonSlider); - mInverseSliderBackground = (LinearLayout)findViewById(R.id.SlidingTabLinearLayoutBackslider); - - mSnapAnimation = new SnapAnimation(mSlider, mInverseSliderBackground); - mSlider.setOnTouchListener(new SliderOnTouchListener()); - - // inflate and prepare the overlay - final LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - mOverlayLayout = (LinearLayout) inflater.inflate(R.layout.slidingtab_overlay, mTabContent, false); - mOverlayIcon = (ImageView)mOverlayLayout.findViewById(R.id.slidingtab_overlay_image); - mOverlayText = (TextView)mOverlayLayout.findViewById(R.id.slidingtab_overlay_label); - - // Deal with focus, as we don't want the focus to go by default - // to a tab other than the current tab - setFocusable(true); -// setOnFocusChangeListener(this); - - setOnKeyListener(new OnKeyListener() { - public boolean onKey(View v, int keyCode, KeyEvent event) { - - if (event.getAction() == KeyEvent.ACTION_DOWN) { - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - if (mSelectedTab > 0) { - snapTo(mSelectedTab - 1); - setCurrentTab(mSelectedTab - 1); - } - return true; - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (mSelectedTab < mNumTabs + 1) { - snapTo(mSelectedTab + 1); - setCurrentTab(mSelectedTab + 1); - } - return true; - } - } else { - return true; - } - mTabContent.requestFocus(View.FOCUS_FORWARD); - return mTabContent.dispatchKeyEvent(event); - } - }); - - // apply the styled attributes - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabWidget, defStyle, 0); - mSeparationWidth = a.getInt(R.styleable.SlidingTabWidget_separationWidth, 0); - if (mSeparationWidth == 0) { - mSeparationWidth = (int)(75 * sScale); - } - a.recycle(); - } - - /** - * Adds a new tab and sets the correct paddings defined by the - * separation width. - * @param newTab - */ - void addTab(SlidingTabSpec newTab) { - - BackgroundImage bgImg = new BackgroundImage(mContext, mNumTabs, newTab); - - final int drawableWidth = bgImg.getDrawable().getIntrinsicWidth(); - final int drawableHeight = bgImg.getDrawable().getIntrinsicHeight(); - final int hPadding = Math.round((float)(mSeparationWidth - drawableWidth) / 2.0f); - final int vPadding = Math.round((float)((int)(SCROLLBAR_HEIGHT * sScale) - drawableHeight) / 2.0f); - - bgImg.setOverlayIconResource(newTab.getBigIconResource()); - - final int sliderWidth = mSlider.getBackground().getIntrinsicWidth() - 2 * SHADOW_PADDING; - final int borderVPadding = (int) Math.floor((float)(sliderWidth - drawableWidth) / 2.0f); - - if (mNumTabs == 0) { - bgImg.setPadding(borderVPadding, vPadding, hPadding, 0); - mSlider.setImageResource(newTab.getActiveIconResource()); - mInverseSliderWidth += (borderVPadding + drawableWidth + hPadding); - } else { - if (mNumTabs > 1) { - BackgroundImage lastTab = (BackgroundImage)mInverseSliderBackground.getChildAt(mNumTabs - 1); - mInverseSliderWidth += (lastTab.getPaddingLeft() - lastTab.getPaddingRight()); - lastTab.setPadding(lastTab.getPaddingLeft(), lastTab.getPaddingTop(), lastTab.getPaddingLeft(), 0); - } - mInverseSliderWidth += (hPadding + drawableWidth + borderVPadding); - bgImg.setPadding(hPadding, vPadding, borderVPadding, 0); - } - - if (bgImg.getLayoutParams() == null) { - final LinearLayout.LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); - lp.setMargins(0, 0, 0, 0); - bgImg.setLayoutParams(lp); - } - - - // ensure you can navigate to the tab with the keyboard, and you can touch it - bgImg.setFocusable(false); - bgImg.setClickable(true); - // make the buttons accessible by click directly. - bgImg.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - updateLayoutDimensions(); - final BackgroundImage bgImg = (BackgroundImage)v; - if (bgImg.getTabIndex() != mSelectedTab) { - mSlider.setImageResource(bgImg.getSliderIconResource()); - snapTo(bgImg.getTabIndex()); - setCurrentTab(bgImg.getTabIndex()); - } - } - }); - - mInverseSliderBackground.addView(bgImg); - mNumTabs++; - -/* StringBuilder sb = new StringBuilder(); - int total = 0; - for (int i = 0; i < mNumTabs; i++) { - BackgroundImage img = (BackgroundImage)mInverseSliderBackground.getChildAt(i); - total += img.getPaddingLeft(); - total += img.getDrawable().getIntrinsicWidth(); - total += img.getPaddingRight(); - sb.append("[" + img.getPaddingLeft() + "|" + img.getDrawable().getIntrinsicWidth() + "|" + img.getPaddingRight() + "] "); - } - mInverseSliderBackground.invalidate(); - Log.i("padding", total + ": " + sb.toString() + "(" + mInverseSliderWidth + ")"); -*/ - } - - /** - * Automatically animates the slider (and background) to given tabindex. - * @param tabIndex - */ - void moveTo(int tabIndex) { - updateLayoutDimensions(); - final BackgroundImage bgImg = (BackgroundImage)getChildTabViewAt(tabIndex); - if (bgImg != null && tabIndex != mSelectedTab) { - mSlider.setImageResource(bgImg.getSliderIconResource()); - snapTo(bgImg.getTabIndex()); - setCurrentTab(bgImg.getTabIndex()); - } - } - - /** - * Moves the slider to a position - * @param pos Absolute position of outer-left edge of the slider (0 = left aligned) - */ - private void moveSlider(int pos) { - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - params.setMargins(pos, 0, 0, 0); - mSlider.setLayoutParams(params); - } - - /** - * Moves the background to a position. Won't move if all icons already visible. - * @param pos Relative position of all background icons. - */ - private void moveBackground(int pos) { - // only move background if there are more icons than visible - if (pos != 0 && mBackMoveFactor > 0) { - mInverseSliderBackground.offsetLeftAndRight(pos); - mInverseSliderBackground.invalidate(); - } - } - - - /** - * Moves the slider (and the background) to the correct position. Note that - * the actual content switch is not done in here and must be manually called: - *

mSelectionChangedListener.onTabSelectionChanged(mCurrTabIndex, true);
- * @param tabIndex Tab index (first tab = 0) - */ - private void snapTo(int tabIndex) { - if (mBackMoveFactor > 0) { // background scrolls - final float snapWidth; - if (mNumTabs > 1) { - snapWidth = (float)mSliderMoveWidth / (float)(mNumTabs - 1); - } else { - snapWidth = mSliderMoveWidth; - } - final int snapPos = Math.round(tabIndex * snapWidth); - final int backSnapPos = -(int)Math.round((snapPos * mBackMoveFactor)); -// Log.i("snap", "Snapping to " + index + "(" + snapPos + " / " + backSnapPos + ")"); - mSnapAnimation.init(snapPos, backSnapPos); - } else { // background doesn't scroll - final BackgroundImage bgImg = (BackgroundImage)mInverseSliderBackground.getChildAt(tabIndex); - final int snapPos = bgImg.getCenteredPosition() - Math.round((float)mSlider.getBackground().getIntrinsicWidth() / 2.0f) + SHADOW_PADDING; - mSnapAnimation.init(snapPos, SnapAnimation.NO_ANIMATION); - } - mSnapAnimation.setDuration(100); - mSlider.startAnimation(mSnapAnimation); - } - - /** - * Updates layout dimensions. This should be done only once, though I - * haven't found out yet how. Should be called when the layout is rendered. - */ - private void updateLayoutDimensions() { - if (mSliderMoveWidth == 0) { - mSliderMoveWidth = mOuterLayout.getWidth() - mSlider.getBackground().getIntrinsicWidth() + (2 * SHADOW_PADDING); - } - if (mBackMoveWidth == 0) { - mBackMoveWidth = mInverseSliderWidth - mOuterLayout.getWidth() + mOuterLayout.getPaddingRight() + mOuterLayout.getPaddingLeft();// - (2 * SHADOW_PADDING); - } - if (mBackMoveFactor == 0) { - mBackMoveFactor = (float)mBackMoveWidth / (float)mSliderMoveWidth; - } - } - - - /** - * Returns background ImageButton at the given index. - * @param index The zero-based index of the tab indicator view to return - * @return the tab indicator view at the given index - */ - public View getChildTabViewAt(int index) { - return mInverseSliderBackground.getChildAt(index); - } - - /** - * Sets the reference to the tab content layer (needed for the overlay). - * @param layout - */ - void setTabContent(FrameLayout layout) { - mTabContent = layout; - } - - /** - * Returns the number of tab indicator views. - * @return the number of tab indicator views. - */ - public int getTabCount() { - return mInverseSliderBackground.getChildCount(); - } - - - /** - * Sets the current tab. - * - * Note that it doesn't move the slider, this must be done separately. - * However, it does switch the content. - * - * @param tabIndex Which tab is going to be selected - */ - public void setCurrentTab(int tabIndex) { - if (tabIndex < 0 || tabIndex >= getTabCount()) { - return; - } - mSelectionChangedListener.onTabSelectionChanged(tabIndex, true); - mSelectedTab = tabIndex; - } - - /** - * Sets the current tab and focuses the UI on it. This method makes sure - * that the focused tab matches the selected tab, normally at - * {@link #setCurrentTab}. Normally this would not be an issue if we go - * through the UI, since the UI is responsible for calling - * TabWidget.onFocusChanged(), but in the case where we are selecting the - * tab programmatically, we'll need to make sure focus keeps up. - * - * @param index - * The tab that you want focused (highlighted in orange) and - * selected (tab brought to the front of the widget) - * - * @see #setCurrentTab - */ - public void focusCurrentTab2(int index) { - final int oldTab = mSelectedTab; - - // set the tab - setCurrentTab(index); - - // change the focus if applicable. - if (oldTab != index) { -// getChildTabViewAt(index).requestFocus(); - } - } - -/* @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - int count = getTabCount(); - - for (int i = 0; i < count; i++) { - View child = getChildTabViewAt(i); - child.setEnabled(enabled); - } - }*/ - - - /** - * Takes care of all the sliding stuff. - */ - private class SliderOnTouchListener implements View.OnTouchListener { - - private int mClickPos = 0; - private int mCurrTabIndex = -1; - private boolean mIsMoving = false; - - public boolean onTouch(View v, MotionEvent event) { - - updateLayoutDimensions(); - - final int sliderRelPos = (int)event.getX() - mClickPos; - final int sliderAbsPos = mSlider.getLeft() + sliderRelPos; - - final int bgAbsPos = -(int)Math.round(((sliderAbsPos) * mBackMoveFactor)); - final int bgRelPos = bgAbsPos - mInverseSliderBackground.getLeft(); - - switch (event.getAction()) { - - case MotionEvent.ACTION_DOWN: - mClickPos = (int)event.getX(); - break; - - case MotionEvent.ACTION_UP: - if (mIsMoving) { - // remove overlay - mTabContent.removeView(mOverlayLayout); - - // snap to selected position and change the tab contents - snapTo(mCurrTabIndex); - setCurrentTab(mCurrTabIndex); - mIsMoving = false; - } - break; - - case MotionEvent.ACTION_MOVE: - - if (!mIsMoving) { - // add overlay - mTabContent.addView(mOverlayLayout); - } - mIsMoving = true; - - // only move within boundaries - if (sliderAbsPos >= mOuterLayout.getLeft() + mOuterLayout.getPaddingLeft() && - sliderAbsPos <= mOuterLayout.getWidth() - mOuterLayout.getPaddingRight() - mSlider.getWidth() + (2 * SHADOW_PADDING)) { - - moveSlider(sliderAbsPos); - moveBackground(bgRelPos); - - // find out nearest background icon - final int slPos = mSlider.getLeft() + (int)Math.round((float)mSlider.getWidth() / 2.0f) - SHADOW_PADDING; - int minVal = -1; - BackgroundImage nearestTab = null; - for (int i = 0; i < mNumTabs; i++) { // TODO some basic optimization wouldn't hurt. - final BackgroundImage bgTab = (BackgroundImage)mInverseSliderBackground.getChildAt(i); - final int bgPos = mInverseSliderBackground.getLeft() + bgTab.getCenteredPosition(); - if (Math.abs(bgPos - slPos) < minVal || minVal == -1) { - minVal = Math.abs(bgPos - slPos); - nearestTab = bgTab; - } - } - // update overlay icons, text and slider icon on changes - if (mCurrTabIndex == -1 || mCurrTabIndex != nearestTab.getTabIndex()) { - mSlider.setImageResource(nearestTab.getSliderIconResource()); - mOverlayText.setText(nearestTab.getLabel()); - mOverlayIcon.setImageResource(nearestTab.getOverlayIconResource()); - mCurrTabIndex = nearestTab.getTabIndex(); - } - } - break; - } - return true; - } - } - - /** - * Used for the background icons. They additionally hold some resource - * references for direct access. - */ - private class BackgroundImage extends ImageButton { - private final int mSliderIconResource; - private final int mTabIndex; - private final String mLabel; - private int mOverlayIconResource; - public BackgroundImage(Context context, int tabIndex, SlidingTabSpec specs) { - super(context); - mTabIndex = tabIndex; - mSliderIconResource = specs.getActiveIconResource(); - mLabel = specs.getLabel(); - setImageResource(specs.getInactiveIconResource()); - setBackgroundDrawable(null); - } - public void setOverlayIconResource(int res) { - mOverlayIconResource = res; - } - public int getOverlayIconResource() { - return mOverlayIconResource; - } - public int getSliderIconResource() { - return mSliderIconResource; - } - public int getTabIndex() { - return mTabIndex; - } - public String getLabel() { - return mLabel; - } - public int getCenteredPosition() { - return getLeft() + getPaddingLeft() + Math.round((float)getDrawable().getIntrinsicWidth() / 2.0f); - } - } - - - /** - * Provides a way for {@link SlidingTabHost} to be notified that the user clicked - * on a tab indicator. - */ - void setTabSelectionListener(OnTabSelectionChanged listener) { - mSelectionChangedListener = listener; - } - - - - public void onFocusChange2(View v, boolean hasFocus) { - if (v == this && hasFocus) { - getChildTabViewAt(mSelectedTab).requestFocus(); - return; - } - - if (hasFocus) { - int i = 0; - int numTabs = getTabCount(); - while (i < numTabs) { - if (getChildTabViewAt(i) == v) { - setCurrentTab(i); - mSelectionChangedListener.onTabSelectionChanged(i, false); - break; - } - i++; - } - } - } - - /** - * Let {@link TabHost} know that the user clicked on a tab indicator. - */ - static interface OnTabSelectionChanged { - /** - * Informs the TabHost which tab was selected. It also indicates if the - * tab was clicked/pressed or just focused into. - * - * @param tabIndex - * index of the tab that was selected - * @param clicked - * whether the selection changed due to a touch/click or due - * to focus entering the tab through navigation. Pass true if - * it was due to a press/click and false otherwise. - */ - void onTabSelectionChanged(int tabIndex, boolean clicked); - } - -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.slidingtabs; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TabHost; +import android.widget.TextView; + +import org.xbmc.android.remote.R; +import org.xbmc.android.widget.slidingtabs.SlidingTabHost.SlidingTabSpec; + +/** + * Displays the sliding tabs. + *

+ * Displays a list of icons representing each page in the parent's tab + * collection. The container object for this widget is + * {@link org.xbmc.android.widget.slidingtabs.SlidingTabHost SlidingTabHost}. + * When the user selects a tab, this object sends a message to the parent + * container, SlidingTabHost, to tell it to switch the displayed page. You + * typically won't use many methods directly on this object. The container + * SlidingTabHost is used to add labels, add the callback handler, and manage + * callbacks. + * + * @author Team XBMC + */ +public class SlidingTabWidget extends LinearLayout { + + private final static int SCROLLBAR_HEIGHT = 42; + private final static int SHADOW_PADDING = 18; + private static float sScale; + private final LinearLayout mOuterLayout; + private final ImageButton mSlider; + private final LinearLayout mInverseSliderBackground; + private final LinearLayout mOverlayLayout; + private final ImageView mOverlayIcon; + private final TextView mOverlayText; + private final SnapAnimation mSnapAnimation; + protected Context mContext; + float mBackMoveFactor = 0; + private int mSeparationWidth; + private OnTabSelectionChanged mSelectionChangedListener; + private int mSelectedTab = 0; + private FrameLayout mTabContent; + private int mNumTabs = 0; + private int mInverseSliderWidth = 0; + private int mSliderMoveWidth = 0; + private int mBackMoveWidth = 0; + + + public SlidingTabWidget(Context context) { + this(context, null); + mContext = context; + } + + public SlidingTabWidget(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.slidingTabWidgetStyle); + mContext = context; + } + + public SlidingTabWidget(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs); + + sScale = context.getResources().getDisplayMetrics().density; + + mContext = context; + setOrientation(LinearLayout.HORIZONTAL); + + // inflate widget layout from xml + inflate(context, R.layout.slidingtab_widget, this); + + // set all the view references + mOuterLayout = (LinearLayout) findViewById(R.id.SlidingTabLinearLayoutOuter); + mSlider = (ImageButton) findViewById(R.id.SlidingTabImageButtonSlider); + mInverseSliderBackground = (LinearLayout) findViewById(R.id.SlidingTabLinearLayoutBackslider); + + mSnapAnimation = new SnapAnimation(mSlider, mInverseSliderBackground); + mSlider.setOnTouchListener(new SliderOnTouchListener()); + + // inflate and prepare the overlay + final LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mOverlayLayout = (LinearLayout) inflater.inflate(R.layout.slidingtab_overlay, mTabContent, false); + mOverlayIcon = (ImageView) mOverlayLayout.findViewById(R.id.slidingtab_overlay_image); + mOverlayText = (TextView) mOverlayLayout.findViewById(R.id.slidingtab_overlay_label); + + // Deal with focus, as we don't want the focus to go by default + // to a tab other than the current tab + setFocusable(true); +// setOnFocusChangeListener(this); + + setOnKeyListener(new OnKeyListener() { + public boolean onKey(View v, int keyCode, KeyEvent event) { + + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch (keyCode) { + case KeyEvent.KEYCODE_DPAD_LEFT: + if (mSelectedTab > 0) { + snapTo(mSelectedTab - 1); + setCurrentTab(mSelectedTab - 1); + } + return true; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (mSelectedTab < mNumTabs + 1) { + snapTo(mSelectedTab + 1); + setCurrentTab(mSelectedTab + 1); + } + return true; + } + } else { + return true; + } + mTabContent.requestFocus(View.FOCUS_FORWARD); + return mTabContent.dispatchKeyEvent(event); + } + }); + + // apply the styled attributes + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlidingTabWidget, defStyle, 0); + mSeparationWidth = a.getInt(R.styleable.SlidingTabWidget_separationWidth, 0); + if (mSeparationWidth == 0) { + mSeparationWidth = (int) (75 * sScale); + } + a.recycle(); + } + + /** + * Adds a new tab and sets the correct paddings defined by the + * separation width. + * + * @param newTab + */ + void addTab(SlidingTabSpec newTab) { + + BackgroundImage bgImg = new BackgroundImage(mContext, mNumTabs, newTab); + + final int drawableWidth = bgImg.getDrawable().getIntrinsicWidth(); + final int drawableHeight = bgImg.getDrawable().getIntrinsicHeight(); + final int hPadding = Math.round((float) (mSeparationWidth - drawableWidth) / 2.0f); + final int vPadding = Math.round((float) ((int) (SCROLLBAR_HEIGHT * sScale) - drawableHeight) / 2.0f); + + bgImg.setOverlayIconResource(newTab.getBigIconResource()); + + final int sliderWidth = mSlider.getBackground().getIntrinsicWidth() - 2 * SHADOW_PADDING; + final int borderVPadding = (int) Math.floor((float) (sliderWidth - drawableWidth) / 2.0f); + + if (mNumTabs == 0) { + bgImg.setPadding(borderVPadding, vPadding, hPadding, 0); + mSlider.setImageResource(newTab.getActiveIconResource()); + mInverseSliderWidth += (borderVPadding + drawableWidth + hPadding); + } else { + if (mNumTabs > 1) { + BackgroundImage lastTab = (BackgroundImage) mInverseSliderBackground.getChildAt(mNumTabs - 1); + mInverseSliderWidth += (lastTab.getPaddingLeft() - lastTab.getPaddingRight()); + lastTab.setPadding(lastTab.getPaddingLeft(), lastTab.getPaddingTop(), lastTab.getPaddingLeft(), 0); + } + mInverseSliderWidth += (hPadding + drawableWidth + borderVPadding); + bgImg.setPadding(hPadding, vPadding, borderVPadding, 0); + } + + if (bgImg.getLayoutParams() == null) { + final LinearLayout.LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f); + lp.setMargins(0, 0, 0, 0); + bgImg.setLayoutParams(lp); + } + + + // ensure you can navigate to the tab with the keyboard, and you can touch it + bgImg.setFocusable(false); + bgImg.setClickable(true); + // make the buttons accessible by click directly. + bgImg.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + updateLayoutDimensions(); + final BackgroundImage bgImg = (BackgroundImage) v; + if (bgImg.getTabIndex() != mSelectedTab) { + mSlider.setImageResource(bgImg.getSliderIconResource()); + snapTo(bgImg.getTabIndex()); + setCurrentTab(bgImg.getTabIndex()); + } + } + }); + + mInverseSliderBackground.addView(bgImg); + mNumTabs++; + +/* StringBuilder sb = new StringBuilder(); + int total = 0; + for (int i = 0; i < mNumTabs; i++) { + BackgroundImage img = (BackgroundImage)mInverseSliderBackground.getChildAt(i); + total += img.getPaddingLeft(); + total += img.getDrawable().getIntrinsicWidth(); + total += img.getPaddingRight(); + sb.append("[" + img.getPaddingLeft() + "|" + img.getDrawable().getIntrinsicWidth() + "|" + img + .getPaddingRight() + "] "); + } + mInverseSliderBackground.invalidate(); + Log.i("padding", total + ": " + sb.toString() + "(" + mInverseSliderWidth + ")"); +*/ + } + + /** + * Automatically animates the slider (and background) to given tabindex. + * + * @param tabIndex + */ + void moveTo(int tabIndex) { + updateLayoutDimensions(); + final BackgroundImage bgImg = (BackgroundImage) getChildTabViewAt(tabIndex); + if (bgImg != null && tabIndex != mSelectedTab) { + mSlider.setImageResource(bgImg.getSliderIconResource()); + snapTo(bgImg.getTabIndex()); + setCurrentTab(bgImg.getTabIndex()); + } + } + + /** + * Moves the slider to a position + * + * @param pos Absolute position of outer-left edge of the slider (0 = left aligned) + */ + private void moveSlider(int pos) { + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + params.setMargins(pos, 0, 0, 0); + mSlider.setLayoutParams(params); + } + + /** + * Moves the background to a position. Won't move if all icons already visible. + * + * @param pos Relative position of all background icons. + */ + private void moveBackground(int pos) { + // only move background if there are more icons than visible + if (pos != 0 && mBackMoveFactor > 0) { + mInverseSliderBackground.offsetLeftAndRight(pos); + mInverseSliderBackground.invalidate(); + } + } + + + /** + * Moves the slider (and the background) to the correct position. Note that + * the actual content switch is not done in here and must be manually called: + *

mSelectionChangedListener.onTabSelectionChanged(mCurrTabIndex, true);
+ * + * @param tabIndex Tab index (first tab = 0) + */ + private void snapTo(int tabIndex) { + if (mBackMoveFactor > 0) { // background scrolls + final float snapWidth; + if (mNumTabs > 1) { + snapWidth = (float) mSliderMoveWidth / (float) (mNumTabs - 1); + } else { + snapWidth = mSliderMoveWidth; + } + final int snapPos = Math.round(tabIndex * snapWidth); + final int backSnapPos = -(int) Math.round((snapPos * mBackMoveFactor)); +// Log.i("snap", "Snapping to " + index + "(" + snapPos + " / " + backSnapPos + ")"); + mSnapAnimation.init(snapPos, backSnapPos); + } else { // background doesn't scroll + final BackgroundImage bgImg = (BackgroundImage) mInverseSliderBackground.getChildAt(tabIndex); + final int snapPos = bgImg.getCenteredPosition() - Math.round((float) mSlider.getBackground() + .getIntrinsicWidth() / 2.0f) + SHADOW_PADDING; + mSnapAnimation.init(snapPos, SnapAnimation.NO_ANIMATION); + } + mSnapAnimation.setDuration(100); + mSlider.startAnimation(mSnapAnimation); + } + + /** + * Updates layout dimensions. This should be done only once, though I + * haven't found out yet how. Should be called when the layout is rendered. + */ + private void updateLayoutDimensions() { + if (mSliderMoveWidth == 0) { + mSliderMoveWidth = mOuterLayout.getWidth() - mSlider.getBackground().getIntrinsicWidth() + (2 * + SHADOW_PADDING); + } + if (mBackMoveWidth == 0) { + mBackMoveWidth = mInverseSliderWidth - mOuterLayout.getWidth() + mOuterLayout.getPaddingRight() + + mOuterLayout.getPaddingLeft();// - (2 * SHADOW_PADDING); + } + if (mBackMoveFactor == 0) { + mBackMoveFactor = (float) mBackMoveWidth / (float) mSliderMoveWidth; + } + } + + + /** + * Returns background ImageButton at the given index. + * + * @param index The zero-based index of the tab indicator view to return + * @return the tab indicator view at the given index + */ + public View getChildTabViewAt(int index) { + return mInverseSliderBackground.getChildAt(index); + } + + /** + * Sets the reference to the tab content layer (needed for the overlay). + * + * @param layout + */ + void setTabContent(FrameLayout layout) { + mTabContent = layout; + } + + /** + * Returns the number of tab indicator views. + * + * @return the number of tab indicator views. + */ + public int getTabCount() { + return mInverseSliderBackground.getChildCount(); + } + + + /** + * Sets the current tab. + *

+ * Note that it doesn't move the slider, this must be done separately. + * However, it does switch the content. + * + * @param tabIndex Which tab is going to be selected + */ + public void setCurrentTab(int tabIndex) { + if (tabIndex < 0 || tabIndex >= getTabCount()) { + return; + } + mSelectionChangedListener.onTabSelectionChanged(tabIndex, true); + mSelectedTab = tabIndex; + } + + /** + * Sets the current tab and focuses the UI on it. This method makes sure + * that the focused tab matches the selected tab, normally at + * {@link #setCurrentTab}. Normally this would not be an issue if we go + * through the UI, since the UI is responsible for calling + * TabWidget.onFocusChanged(), but in the case where we are selecting the + * tab programmatically, we'll need to make sure focus keeps up. + * + * @param index The tab that you want focused (highlighted in orange) and + * selected (tab brought to the front of the widget) + * @see #setCurrentTab + */ + public void focusCurrentTab2(int index) { + final int oldTab = mSelectedTab; + + // set the tab + setCurrentTab(index); + + // change the focus if applicable. + if (oldTab != index) { +// getChildTabViewAt(index).requestFocus(); + } + } + +/* @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + int count = getTabCount(); + + for (int i = 0; i < count; i++) { + View child = getChildTabViewAt(i); + child.setEnabled(enabled); + } + }*/ + + /** + * Provides a way for {@link SlidingTabHost} to be notified that the user clicked + * on a tab indicator. + */ + void setTabSelectionListener(OnTabSelectionChanged listener) { + mSelectionChangedListener = listener; + } + + public void onFocusChange2(View v, boolean hasFocus) { + if (v == this && hasFocus) { + getChildTabViewAt(mSelectedTab).requestFocus(); + return; + } + + if (hasFocus) { + int i = 0; + int numTabs = getTabCount(); + while (i < numTabs) { + if (getChildTabViewAt(i) == v) { + setCurrentTab(i); + mSelectionChangedListener.onTabSelectionChanged(i, false); + break; + } + i++; + } + } + } + + + /** + * Let {@link TabHost} know that the user clicked on a tab indicator. + */ + static interface OnTabSelectionChanged { + /** + * Informs the TabHost which tab was selected. It also indicates if the + * tab was clicked/pressed or just focused into. + * + * @param tabIndex index of the tab that was selected + * @param clicked whether the selection changed due to a touch/click or due + * to focus entering the tab through navigation. Pass true if + * it was due to a press/click and false otherwise. + */ + void onTabSelectionChanged(int tabIndex, boolean clicked); + } + + /** + * Takes care of all the sliding stuff. + */ + private class SliderOnTouchListener implements View.OnTouchListener { + + private int mClickPos = 0; + private int mCurrTabIndex = -1; + private boolean mIsMoving = false; + + public boolean onTouch(View v, MotionEvent event) { + + updateLayoutDimensions(); + + final int sliderRelPos = (int) event.getX() - mClickPos; + final int sliderAbsPos = mSlider.getLeft() + sliderRelPos; + + final int bgAbsPos = -(int) Math.round(((sliderAbsPos) * mBackMoveFactor)); + final int bgRelPos = bgAbsPos - mInverseSliderBackground.getLeft(); + + switch (event.getAction()) { + + case MotionEvent.ACTION_DOWN: + mClickPos = (int) event.getX(); + break; + + case MotionEvent.ACTION_UP: + if (mIsMoving) { + // remove overlay + mTabContent.removeView(mOverlayLayout); + + // snap to selected position and change the tab contents + snapTo(mCurrTabIndex); + setCurrentTab(mCurrTabIndex); + mIsMoving = false; + } + break; + + case MotionEvent.ACTION_MOVE: + + if (!mIsMoving) { + // add overlay + mTabContent.addView(mOverlayLayout); + } + mIsMoving = true; + + // only move within boundaries + if (sliderAbsPos >= mOuterLayout.getLeft() + mOuterLayout.getPaddingLeft() && + sliderAbsPos <= mOuterLayout.getWidth() - mOuterLayout.getPaddingRight() - mSlider + .getWidth() + (2 * SHADOW_PADDING)) { + + moveSlider(sliderAbsPos); + moveBackground(bgRelPos); + + // find out nearest background icon + final int slPos = mSlider.getLeft() + (int) Math.round((float) mSlider.getWidth() / 2.0f) - + SHADOW_PADDING; + int minVal = -1; + BackgroundImage nearestTab = null; + for (int i = 0; i < mNumTabs; i++) { // TODO some basic optimization wouldn't hurt. + final BackgroundImage bgTab = (BackgroundImage) mInverseSliderBackground.getChildAt(i); + final int bgPos = mInverseSliderBackground.getLeft() + bgTab.getCenteredPosition(); + if (Math.abs(bgPos - slPos) < minVal || minVal == -1) { + minVal = Math.abs(bgPos - slPos); + nearestTab = bgTab; + } + } + // update overlay icons, text and slider icon on changes + if (mCurrTabIndex == -1 || mCurrTabIndex != nearestTab.getTabIndex()) { + mSlider.setImageResource(nearestTab.getSliderIconResource()); + mOverlayText.setText(nearestTab.getLabel()); + mOverlayIcon.setImageResource(nearestTab.getOverlayIconResource()); + mCurrTabIndex = nearestTab.getTabIndex(); + } + } + break; + } + return true; + } + } + + /** + * Used for the background icons. They additionally hold some resource + * references for direct access. + */ + private class BackgroundImage extends ImageButton { + private final int mSliderIconResource; + private final int mTabIndex; + private final String mLabel; + private int mOverlayIconResource; + + public BackgroundImage(Context context, int tabIndex, SlidingTabSpec specs) { + super(context); + mTabIndex = tabIndex; + mSliderIconResource = specs.getActiveIconResource(); + mLabel = specs.getLabel(); + setImageResource(specs.getInactiveIconResource()); + setBackgroundDrawable(null); + } + + public int getOverlayIconResource() { + return mOverlayIconResource; + } + + public void setOverlayIconResource(int res) { + mOverlayIconResource = res; + } + + public int getSliderIconResource() { + return mSliderIconResource; + } + + public int getTabIndex() { + return mTabIndex; + } + + public String getLabel() { + return mLabel; + } + + public int getCenteredPosition() { + return getLeft() + getPaddingLeft() + Math.round((float) getDrawable().getIntrinsicWidth() / 2.0f); + } + } + +} diff --git a/src/org/xbmc/android/widget/slidingtabs/SnapAnimation.java b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SnapAnimation.java similarity index 84% rename from src/org/xbmc/android/widget/slidingtabs/SnapAnimation.java rename to app/src/main/java/org/xbmc/android/widget/slidingtabs/SnapAnimation.java index 9d2ea012..6f0e453d 100644 --- a/src/org/xbmc/android/widget/slidingtabs/SnapAnimation.java +++ b/app/src/main/java/org/xbmc/android/widget/slidingtabs/SnapAnimation.java @@ -1,98 +1,100 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.android.widget.slidingtabs; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.animation.Animation; -import android.view.animation.Transformation; -import android.widget.ImageButton; -import android.widget.LinearLayout; - -/** - * Makes the slider glide to the next tab. - * - * @author Team XBMC - */ -class SnapAnimation extends Animation { - - private final ImageButton mSlider; - private final LinearLayout mBackLayout; - - public static int NO_ANIMATION = -99999; - - private int mSliderSnapPosition; - private int mBackSnapPosition; - private int mInitialMargin; - private int mInitialBackPosition; - - /** - * Constructor. Animation object can be declared final and re-used. - * - * @param context Current context - * @param attrs Attribute set when inflated from XML - * @param slider Slider object - * @param bl Background sliding layout - */ - public SnapAnimation(Context context, AttributeSet attrs, ImageButton slider, LinearLayout bl) { - super(context, attrs); - mBackLayout = bl; - mSlider = slider; - } - - /** - * Constructor. Animation object can be declared final and re-used. - * - * @param slider Slider object - * @param bl Background sliding layout - */ - public SnapAnimation(ImageButton slider, LinearLayout bl) { - mBackLayout = bl; - mSlider = slider; - } - - /** - * Initialization is needed before starting the application. - * @param sliderSnapPos To which position the slider should be moved - * @param backSnapPos To which position the background should be moved - */ - public void init(int sliderSnapPos, int backSnapPos) { - mSliderSnapPosition = sliderSnapPos; - mBackSnapPosition = backSnapPos; - mInitialMargin = ((LinearLayout.LayoutParams)mSlider.getLayoutParams()).leftMargin; - mInitialBackPosition = mBackLayout.getLeft(); - } - - @Override - protected void applyTransformation(float interpolatedTime, Transformation t) { - final int interPadding = mInitialMargin + Math.round((float)(mSliderSnapPosition - mInitialMargin) * interpolatedTime); - final int interBackPosition = mInitialBackPosition + Math.round((float)(mBackSnapPosition - mInitialBackPosition) * interpolatedTime); - final int interBackRelPosition = interBackPosition - mBackLayout.getLeft(); - if (interBackRelPosition != 0 && mBackSnapPosition != NO_ANIMATION) { - mBackLayout.offsetLeftAndRight(interBackRelPosition); - mBackLayout.invalidate(); - } - LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - params.setMargins(interPadding, 0, 0, 0); - mSlider.setLayoutParams(params); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.android.widget.slidingtabs; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.animation.Animation; +import android.view.animation.Transformation; +import android.widget.ImageButton; +import android.widget.LinearLayout; + +/** + * Makes the slider glide to the next tab. + * + * @author Team XBMC + */ +class SnapAnimation extends Animation { + + public static int NO_ANIMATION = -99999; + private final ImageButton mSlider; + private final LinearLayout mBackLayout; + private int mSliderSnapPosition; + private int mBackSnapPosition; + private int mInitialMargin; + private int mInitialBackPosition; + + /** + * Constructor. Animation object can be declared final and re-used. + * + * @param context Current context + * @param attrs Attribute set when inflated from XML + * @param slider Slider object + * @param bl Background sliding layout + */ + public SnapAnimation(Context context, AttributeSet attrs, ImageButton slider, LinearLayout bl) { + super(context, attrs); + mBackLayout = bl; + mSlider = slider; + } + + /** + * Constructor. Animation object can be declared final and re-used. + * + * @param slider Slider object + * @param bl Background sliding layout + */ + public SnapAnimation(ImageButton slider, LinearLayout bl) { + mBackLayout = bl; + mSlider = slider; + } + + /** + * Initialization is needed before starting the application. + * + * @param sliderSnapPos To which position the slider should be moved + * @param backSnapPos To which position the background should be moved + */ + public void init(int sliderSnapPos, int backSnapPos) { + mSliderSnapPosition = sliderSnapPos; + mBackSnapPosition = backSnapPos; + mInitialMargin = ((LinearLayout.LayoutParams) mSlider.getLayoutParams()).leftMargin; + mInitialBackPosition = mBackLayout.getLeft(); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + final int interPadding = mInitialMargin + Math.round((float) (mSliderSnapPosition - mInitialMargin) * + interpolatedTime); + final int interBackPosition = mInitialBackPosition + Math.round((float) (mBackSnapPosition - + mInitialBackPosition) * interpolatedTime); + final int interBackRelPosition = interBackPosition - mBackLayout.getLeft(); + if (interBackRelPosition != 0 && mBackSnapPosition != NO_ANIMATION) { + mBackLayout.offsetLeftAndRight(interBackRelPosition); + mBackLayout.invalidate(); + } + LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT); + params.setMargins(interPadding, 0, 0, 0); + mSlider.setLayoutParams(params); + } } \ No newline at end of file diff --git a/src/org/xbmc/api/business/CoverResponse.java b/app/src/main/java/org/xbmc/api/business/CoverResponse.java similarity index 94% rename from src/org/xbmc/api/business/CoverResponse.java rename to app/src/main/java/org/xbmc/api/business/CoverResponse.java index 6b7c3702..93be2499 100644 --- a/src/org/xbmc/api/business/CoverResponse.java +++ b/app/src/main/java/org/xbmc/api/business/CoverResponse.java @@ -1,54 +1,55 @@ -package org.xbmc.api.business; - -import org.xbmc.android.remote.presentation.widget.AbstractItemView; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.type.ThumbSize; - -import android.content.Context; -import android.graphics.Bitmap; -import android.os.Handler; - -public class CoverResponse extends DataResponse { - - private final Context mContext; - private final IManager mManager; - private final Bitmap mDefaultCover; - private final int mThumbSize; - private final Handler mHandler; - - private boolean mIsLoading = false; - private ICoverArt mMostRecentCover = null; - - public CoverResponse(Context context, IManager manager, Bitmap defaultCover, int thumbSize, Handler handler) { - mContext = context; - mManager = manager; - mDefaultCover = defaultCover; - mThumbSize = thumbSize; - mHandler = handler; - } - - public synchronized void load(ICoverArt cover, boolean getFromCacheOnly) { - load(cover, ThumbSize.SMALL, getFromCacheOnly); - } - public synchronized void load(ICoverArt cover, int size, boolean getFromCacheOnly) { - if (mIsLoading) { - mMostRecentCover = cover; - } else { - mIsLoading = true; - mMostRecentCover = null; - mManager.getCover(this, cover, size, mDefaultCover, mContext, getFromCacheOnly); - } - } - - public synchronized void run() { - if (mMostRecentCover == null) { - if(mHandler != null) { - mHandler.sendMessage(mHandler.obtainMessage(AbstractItemView.MSG_UPDATE_COVER, value)); - } - mIsLoading = false; - } else { - mManager.getCover(this, mMostRecentCover, mThumbSize, mDefaultCover, mContext, false); - mMostRecentCover = null; - } - } +package org.xbmc.api.business; + +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Handler; + +import org.xbmc.android.remote.presentation.widget.AbstractItemView; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.type.ThumbSize; + +public class CoverResponse extends DataResponse { + + private final Context mContext; + private final IManager mManager; + private final Bitmap mDefaultCover; + private final int mThumbSize; + private final Handler mHandler; + + private boolean mIsLoading = false; + private ICoverArt mMostRecentCover = null; + + public CoverResponse(Context context, IManager manager, Bitmap defaultCover, int thumbSize, Handler handler) { + mContext = context; + mManager = manager; + mDefaultCover = defaultCover; + mThumbSize = thumbSize; + mHandler = handler; + } + + public synchronized void load(ICoverArt cover, boolean getFromCacheOnly) { + load(cover, ThumbSize.SMALL, getFromCacheOnly); + } + + public synchronized void load(ICoverArt cover, int size, boolean getFromCacheOnly) { + if (mIsLoading) { + mMostRecentCover = cover; + } else { + mIsLoading = true; + mMostRecentCover = null; + mManager.getCover(this, cover, size, mDefaultCover, mContext, getFromCacheOnly); + } + } + + public synchronized void run() { + if (mMostRecentCover == null) { + if (mHandler != null) { + mHandler.sendMessage(mHandler.obtainMessage(AbstractItemView.MSG_UPDATE_COVER, value)); + } + mIsLoading = false; + } else { + mManager.getCover(this, mMostRecentCover, mThumbSize, mDefaultCover, mContext, false); + mMostRecentCover = null; + } + } } \ No newline at end of file diff --git a/src/org/xbmc/api/business/DataResponse.java b/app/src/main/java/org/xbmc/api/business/DataResponse.java similarity index 86% rename from src/org/xbmc/api/business/DataResponse.java rename to app/src/main/java/org/xbmc/api/business/DataResponse.java index efdada2c..a00e1e6d 100644 --- a/src/org/xbmc/api/business/DataResponse.java +++ b/app/src/main/java/org/xbmc/api/business/DataResponse.java @@ -1,51 +1,52 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - - - -/** - * Basically contains two things: - *

    - *
  • The callback code of a completed HTTP API command
  • - *
  • The result of the HTTP API command
  • - *
- * - * @author Team XBMC - * @param Type of the API command's result - */ -public class DataResponse implements Runnable, Cloneable { - public T value; - public int cacheType; - public void run () { - // do nothing if not overloaded - } - - /** - * Executed before downloading large files. Overload and return false to - * skip downloading, for instance when a list with covers is scrolling. - * @return - */ - public boolean postCache() { - return true; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + + +/** + * Basically contains two things: + *
    + *
  • The callback code of a completed HTTP API command
  • + *
  • The result of the HTTP API command
  • + *
+ * + * @param Type of the API command's result + * @author Team XBMC + */ +public class DataResponse implements Runnable, Cloneable { + public T value; + public int cacheType; + + public void run() { + // do nothing if not overloaded + } + + /** + * Executed before downloading large files. Overload and return false to + * skip downloading, for instance when a list with covers is scrolling. + * + * @return + */ + public boolean postCache() { + return true; + } } \ No newline at end of file diff --git a/src/org/xbmc/api/business/IControlManager.java b/app/src/main/java/org/xbmc/api/business/IControlManager.java similarity index 70% rename from src/org/xbmc/api/business/IControlManager.java rename to app/src/main/java/org/xbmc/api/business/IControlManager.java index 5d1070eb..557d4f7d 100644 --- a/src/org/xbmc/api/business/IControlManager.java +++ b/app/src/main/java/org/xbmc/api/business/IControlManager.java @@ -1,183 +1,204 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; -import org.xbmc.api.type.SeekType; - -import android.content.Context; - -/** - * This is the interface between the presentation layer and the business layer. - * All the controller of the presentation layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IControlManager extends IManager { - - /** - * Starts playing the media file filename . - * @param response Response object - * @param filename File to play - */ - public void playFile(final DataResponse response, final String filename, final int playlistType, final Context context); - - /** - * Starts playing a whole folder - * @param response Response object - * @param foldername Path to the folder to play - * @param playlistType Playlist type ("0" = music, "1" = video) - * @param context Context reference - */ - public void playFolder(final DataResponse response, final String foldername, final int playlistType, final Context context); - - /** - * Queues a whole folder - * @param response Response object - * @param foldername Path to the folder to play - * @param playlistType Playlist type ("0" = music, "1" = video) - * @param context Context reference - */ - public void queueFolder(final DataResponse response, final String foldername, final int playlistType, final Context context); - - /** - * Start playing the media file at the given URL - * @param response Response object - * @param url An URL pointing to a supported media file - * @param context Context reference - * @return true on success, false otherwise. - */ - public void playUrl(final DataResponse response, String url, final Context context); - - /** - * Plays the next item in the playlist. - * @param response Response object - * @param context Context reference - * @return true on success, false otherwise. - */ - public void playNext(final DataResponse response, final Context context); - - /** - * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. - * @param response Response object - * @param fileOrFolder File to play - * @param context Context reference - */ - public void addToPlaylist(final DataResponse response, final String fileOrFolder, final int playlistType, final Context context); - - /** - * Seeks to a position. If type is - *
    - *
  • absolute - Sets the playing position of the currently - * playing media as a percentage of the media's length.
  • - *
  • relative - Adds/Subtracts the current percentage on to - * the current position in the song
  • - *
- * @param response Response object - * @param type Seek type, relative or absolute - * @param progress Progress - * @param context Context reference - * @return true on success, false otherwise. - */ - public void seek(final DataResponse response, SeekType type, int progress, final Context context); - - /** - * Takes either "video" or "music" as a parameter to begin updating the - * corresponding database. - * - * @param response Response object - * @param context Context reference - * @param mediaType - */ - public void updateLibrary(final DataResponse response, final String mediaType, final Context context); - - /** - * Displays the image filename . - * @param response Response object - * @param filename File to show - * @param context Context reference - */ - public void showPicture(final DataResponse response, final String filename, final Context context); - - /** - * Returns what's currently playing. - * @param response Response object - * @param context Context reference - */ - public void getCurrentlyPlaying(final DataResponse response, final Context context); - - /** - * Returns the current playlist identifier - * @param response Response object - * @param context Context reference - */ - public void getPlaylistId(final DataResponse response, final Context context); - - /** - * Sets the current playlist identifier - * @param response Response object - * @param id Playlist identifier - * @param context Context reference - */ - public void setPlaylistId(final DataResponse response, final int id, final Context context); - - /** - * Sets the current playlist position - * @param response Response object - * @param position New playlist position - * @param context Context reference - */ - public void setPlaylistPos(final DataResponse response, final int playlistId, final int position, final Context context); - - /** - * Clears playlist - * @param response Response object - * @param playlistId Playlist ID (0 = music, 1 = video) - * @param context Context reference - */ - public void clearPlaylist(final DataResponse response, final int playlistId, final Context context); - - /** - * Sets the gui setting of XBMC to value - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings - * @param value the value to set - */ - public void setGuiSetting(final DataResponse response, final int setting, - final String value, final Context context); - - /** - * Reads the current volume of XBMC - * @param response Response object - * @param context - */ - public void getVolume(final DataResponse response, final Context context); - - /** - * Send the string text via keys on the virtual keyboard. - * @param response Response object - * @param text The text string to send. - * @param context Context reference - * @return true on success, false otherwise. - */ - public void sendText(final DataResponse response, final String text, final Context context); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.Context; + +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.type.SeekType; + +/** + * This is the interface between the presentation layer and the business layer. + * All the controller of the presentation layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IControlManager extends IManager { + + /** + * Starts playing the media file filename . + * + * @param response Response object + * @param filename File to play + */ + public void playFile(final DataResponse response, final String filename, final int playlistType, + final Context context); + + /** + * Starts playing a whole folder + * + * @param response Response object + * @param foldername Path to the folder to play + * @param playlistType Playlist type ("0" = music, "1" = video) + * @param context Context reference + */ + public void playFolder(final DataResponse response, final String foldername, final int playlistType, + final Context context); + + /** + * Queues a whole folder + * + * @param response Response object + * @param foldername Path to the folder to play + * @param playlistType Playlist type ("0" = music, "1" = video) + * @param context Context reference + */ + public void queueFolder(final DataResponse response, final String foldername, final int playlistType, + final Context context); + + /** + * Start playing the media file at the given URL + * + * @param response Response object + * @param url An URL pointing to a supported media file + * @param context Context reference + * @return true on success, false otherwise. + */ + public void playUrl(final DataResponse response, String url, final Context context); + + /** + * Plays the next item in the playlist. + * + * @param response Response object + * @param context Context reference + * @return true on success, false otherwise. + */ + public void playNext(final DataResponse response, final Context context); + + /** + * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. + * + * @param response Response object + * @param fileOrFolder File to play + * @param context Context reference + */ + public void addToPlaylist(final DataResponse response, final String fileOrFolder, final int playlistType, + final Context context); + + /** + * Seeks to a position. If type is + *
    + *
  • absolute - Sets the playing position of the currently + * playing media as a percentage of the media's length.
  • + *
  • relative - Adds/Subtracts the current percentage on to + * the current position in the song
  • + *
+ * + * @param response Response object + * @param type Seek type, relative or absolute + * @param progress Progress + * @param context Context reference + * @return true on success, false otherwise. + */ + public void seek(final DataResponse response, SeekType type, int progress, final Context context); + + /** + * Takes either "video" or "music" as a parameter to begin updating the + * corresponding database. + * + * @param response Response object + * @param context Context reference + * @param mediaType + */ + public void updateLibrary(final DataResponse response, final String mediaType, final Context context); + + /** + * Displays the image filename . + * + * @param response Response object + * @param filename File to show + * @param context Context reference + */ + public void showPicture(final DataResponse response, final String filename, final Context context); + + /** + * Returns what's currently playing. + * + * @param response Response object + * @param context Context reference + */ + public void getCurrentlyPlaying(final DataResponse response, final Context context); + + /** + * Returns the current playlist identifier + * + * @param response Response object + * @param context Context reference + */ + public void getPlaylistId(final DataResponse response, final Context context); + + /** + * Sets the current playlist identifier + * + * @param response Response object + * @param id Playlist identifier + * @param context Context reference + */ + public void setPlaylistId(final DataResponse response, final int id, final Context context); + + /** + * Sets the current playlist position + * + * @param response Response object + * @param position New playlist position + * @param context Context reference + */ + public void setPlaylistPos(final DataResponse response, final int playlistId, final int position, + final Context context); + + /** + * Clears playlist + * + * @param response Response object + * @param playlistId Playlist ID (0 = music, 1 = video) + * @param context Context reference + */ + public void clearPlaylist(final DataResponse response, final int playlistId, final Context context); + + /** + * Sets the gui setting of XBMC to value + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings + * @param value the value to set + */ + public void setGuiSetting(final DataResponse response, final int setting, + final String value, final Context context); + + /** + * Reads the current volume of XBMC + * + * @param response Response object + * @param context + */ + public void getVolume(final DataResponse response, final Context context); + + /** + * Send the string text via keys on the virtual keyboard. + * + * @param response Response object + * @param text The text string to send. + * @param context Context reference + * @return true on success, false otherwise. + */ + public void sendText(final DataResponse response, final String text, final Context context); } \ No newline at end of file diff --git a/app/src/main/java/org/xbmc/api/business/IEventClientManager.java b/app/src/main/java/org/xbmc/api/business/IEventClientManager.java new file mode 100644 index 00000000..56c77df2 --- /dev/null +++ b/app/src/main/java/org/xbmc/api/business/IEventClientManager.java @@ -0,0 +1,113 @@ +package org.xbmc.api.business; + +import java.io.IOException; + +/** + * XBMC Event Client Class + *

+ * Implements an XBMC-Client. This class can be used to implement your own + * application which should act as a Input device for XBMC. Also starts a + * Ping-Thread, which tells the XBMC EventServer that the client is alive. + * Therefore if you close your application you SHOULD call stopClient()! + * + * @author Team XBMC + */ +public interface IEventClientManager extends IManager { + + + /** + * Displays a notification window in XBMC. + * + * @param title Message title + * @param message The actual message + */ + public void sendNotification(String title, String message) throws IOException; + + public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException; + + /** + * Sends a Button event + * + * @param code Raw button code (default: 0) + * @param repeat This key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down If this is 1, it implies a press event, 0 implies a + * release event. (default: 1) + * @param queue A queued key press means that the button event is executed + * just once after which the next key press is processed. It + * can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount Unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, + byte axis) throws IOException; + + /** + * Sends a Button event + * + * @param map_name A combination of map_name and button_name refers to a mapping + * in the user's Keymap.xml or Lircmap.xml. map_name can be one + * of the following: + *

    + *
  • KB - Standard keyboard map (<keyboard> section)
  • + *
  • XG - Xbox gamepad map (<gamepad> section)
  • + *
  • R1 - Xbox remote map (<remote> section)
  • + *
  • R2 - Xbox universal remote map (<universalremote> + * section)
  • + *
  • LI:devicename - LIRC remote map where devicename is + * the actual device's name
  • + *
+ * @param button_name A button name defined in the map specified in map_name. For + * example, if map_name is "KB" refering to the + * section in Keymap.xml then, valid button_names include + * "printscreen", "minus", "x", etc. + * @param repeat This key press should repeat until released (default: 1) Note + * that queued pressed cannot repeat. + * @param down If this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue A queued key press means that the button event is executed + * just once after which the next key press is processed. It can + * be used for macros. Currently there is no support for time + * delays between queued presses. (default: 0) + * @param amount Unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(String map_name, String button_name, boolean repeat, + boolean down, boolean queue, short amount, byte axis); + + /** + * Sets the mouse position in XBMC + * + * @param x Horizontal position ranging from 0 to 65535 + * @param y Vertical position ranging from 0 to 65535 + */ + public void sendMouse(int x, int y) throws IOException; + + /** + * Tells XBMC to log the message to xbmc.log with the loglevel as specified. + * + * @param loglevel The log level, follows XBMC standard. + *
    + *
  • 0 = DEBUG
  • + *
  • 1 = INFO
  • + *
  • 2 = NOTICE
  • + *
  • 3 = WARNING
  • + *
  • 4 = ERROR
  • + *
  • 5 = SEVERE
  • + *
+ * @param logmessage The message to log + */ + public void sendLog(byte loglevel, String logmessage) throws IOException; + + /** + * Tells XBMC to do the action specified, based on the type it knows were it + * needs to be sent. + * + * @param actionmessage Actionmessage (as in scripting/skinning) + */ + public void sendAction(String actionmessage) throws IOException; + +} \ No newline at end of file diff --git a/src/org/xbmc/api/business/IInfoManager.java b/app/src/main/java/org/xbmc/api/business/IInfoManager.java similarity index 78% rename from src/org/xbmc/api/business/IInfoManager.java rename to app/src/main/java/org/xbmc/api/business/IInfoManager.java index 12d4a4e0..6f7f2475 100644 --- a/src/org/xbmc/api/business/IInfoManager.java +++ b/app/src/main/java/org/xbmc/api/business/IInfoManager.java @@ -1,105 +1,119 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import java.util.ArrayList; - -import org.xbmc.api.object.FileLocation; -import org.xbmc.api.type.DirectoryMask; - -import android.content.Context; - -/** - * This is the interface between the presentation layer and the business layer. - * All the controller of the presentation layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IInfoManager extends IManager { - - /** - * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} - * @param response Response object - * @param field Field to return - */ - public void getSystemInfo(final DataResponse response, final int field, final Context context); - - /** - * Returns all defined shares of a media type - * @param response Response object - * @param mediaType Media type - */ - public void getShares(final DataResponse> response, final int mediaType, final Context context); - - /** - * Returns the contents of a directory - * @param response Response object - * @param path Path to the directory - * @param mask Mask to filter - * @param offset Offset (0 for none) - * @param limit Limit (0 for none) - * @return - */ - public void getDirectory(final DataResponse> response, final String path, final DirectoryMask mask, final int offset, final int limit, final Context context, final int mediaType); - - /** - * Returns the contents of a directory - * @param response Response object - * @param path Path to the directory - * @return - */ - public void getDirectory(final DataResponse> response, final String path, final Context context, final int mediaType); - - /** - * Returns the gui setting of XBMC - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. - * @param context - */ - public void getGuiSettingInt(final DataResponse response, final int setting, final Context context); - - /** - * Returns the gui setting of XBMC - * @param response Response object - * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. - * @param context - */ - public void getGuiSettingBool(final DataResponse response, final int setting, final Context context); - - /** - * Sets an integer GUI setting - * @param response Response object - * @param field Field to return (see GuiSettings.java) - * @param val Integer value to set - */ - public void setGuiSettingInt(final DataResponse response, final int field, final int val, final Context context); - - /** - * Sets an integer GUI setting - * @param response Response object - * @param field Field to return (see GuiSettings.java) - * @param val Boolean value to set - */ - public void setGuiSettingBool(final DataResponse response, final int field, final boolean val, final Context context); - - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.Context; + +import org.xbmc.api.object.FileLocation; +import org.xbmc.api.type.DirectoryMask; + +import java.util.ArrayList; + +/** + * This is the interface between the presentation layer and the business layer. + * All the controller of the presentation layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IInfoManager extends IManager { + + /** + * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} + * + * @param response Response object + * @param field Field to return + */ + public void getSystemInfo(final DataResponse response, final int field, final Context context); + + /** + * Returns all defined shares of a media type + * + * @param response Response object + * @param mediaType Media type + */ + public void getShares(final DataResponse> response, final int mediaType, + final Context context); + + /** + * Returns the contents of a directory + * + * @param response Response object + * @param path Path to the directory + * @param mask Mask to filter + * @param offset Offset (0 for none) + * @param limit Limit (0 for none) + * @return + */ + public void getDirectory(final DataResponse> response, final String path, + final DirectoryMask mask, final int offset, final int limit, final Context context, + final int mediaType); + + /** + * Returns the contents of a directory + * + * @param response Response object + * @param path Path to the directory + * @return + */ + public void getDirectory(final DataResponse> response, final String path, + final Context context, final int mediaType); + + /** + * Returns the gui setting of XBMC + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. + * @param context + */ + public void getGuiSettingInt(final DataResponse response, final int setting, final Context context); + + /** + * Returns the gui setting of XBMC + * + * @param response Response object + * @param setting see {@link org.xbmc.api.info.GuiSettings} for all settings you can query. + * @param context + */ + public void getGuiSettingBool(final DataResponse response, final int setting, final Context context); + + /** + * Sets an integer GUI setting + * + * @param response Response object + * @param field Field to return (see GuiSettings.java) + * @param val Integer value to set + */ + public void setGuiSettingInt(final DataResponse response, final int field, final int val, + final Context context); + + /** + * Sets an integer GUI setting + * + * @param response Response object + * @param field Field to return (see GuiSettings.java) + * @param val Boolean value to set + */ + public void setGuiSettingBool(final DataResponse response, final int field, final boolean val, + final Context context); + + } \ No newline at end of file diff --git a/src/org/xbmc/api/business/IManager.java b/app/src/main/java/org/xbmc/api/business/IManager.java similarity index 90% rename from src/org/xbmc/api/business/IManager.java rename to app/src/main/java/org/xbmc/api/business/IManager.java index e8ad5f04..9db1f858 100644 --- a/src/org/xbmc/api/business/IManager.java +++ b/app/src/main/java/org/xbmc/api/business/IManager.java @@ -1,47 +1,53 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.presentation.INotifiableController; - -import android.content.Context; -import android.graphics.Bitmap; - -public interface IManager { - - /** - * Sets the current controller object. Must be set on each activity's onResume(). - * @param controller Controller object - */ - public void setController(INotifiableController controller); - - /** - * Returns bitmap of any cover. Note that the callback is done by the - * helper methods below. - * @param response Response object - */ - public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, Bitmap defaultCover, final Context context, final boolean getFromCacheOnly); - public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize); - public boolean coverLoaded(final ICoverArt cover, final int thumbSize); - public void post(Runnable runnable); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.Context; +import android.graphics.Bitmap; + +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.presentation.INotifiableController; + +public interface IManager { + + /** + * Sets the current controller object. Must be set on each activity's onResume(). + * + * @param controller Controller object + */ + public void setController(INotifiableController controller); + + /** + * Returns bitmap of any cover. Note that the callback is done by the + * helper methods below. + * + * @param response Response object + */ + public void getCover(final DataResponse response, final ICoverArt cover, final int thumbSize, + Bitmap defaultCover, final Context context, final boolean getFromCacheOnly); + + public Bitmap getCoverSync(final ICoverArt cover, final int thumbSize); + + public boolean coverLoaded(final ICoverArt cover, final int thumbSize); + + public void post(Runnable runnable); } \ No newline at end of file diff --git a/src/org/xbmc/api/business/IMusicManager.java b/app/src/main/java/org/xbmc/api/business/IMusicManager.java similarity index 85% rename from src/org/xbmc/api/business/IMusicManager.java rename to app/src/main/java/org/xbmc/api/business/IMusicManager.java index b5b29524..fea81688 100644 --- a/src/org/xbmc/api/business/IMusicManager.java +++ b/app/src/main/java/org/xbmc/api/business/IMusicManager.java @@ -1,274 +1,306 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import java.util.ArrayList; - -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Song; - -import android.content.Context; - -/** - * This is the interface between the presentation layer and the business layer. - * All the controller of the presentation layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IMusicManager extends IManager { - - /** - * Gets all albums from database - * @param response Response object - */ - public void getCompilations(final DataResponse> response, final Context context); - - /** - * Gets all albums from database - * @param response Response object - */ - public void getAlbums(final DataResponse> response, final Context context); - - /** - * SYNCHRONOUSLY gets all albums from database - * @return All albums in database - */ - public ArrayList getAlbums(final Context context); - - /** - * Gets all albums of an artist from database - * @param response Response object - * @param artist Artist of the albums - */ - public void getAlbums(final DataResponse> response, final Artist artist, final Context context); - - /** - * Gets all albums of a genre from database - * @param response Response object - * @param artist Genre of the albums - */ - public void getAlbums(final DataResponse> response, final Genre genre, final Context context); - - /** - * Gets all songs of an album from database - * @param response Response object - * @param album Album - */ - public void getSongs(final DataResponse> response, final Album album, final Context context); - - /** - * Gets all songs from an artist from database - * @param response Response object - * @param album Artist - */ - public void getSongs(final DataResponse> response, final Artist artist, final Context context); - - /** - * Gets all songs of a genre from database - * @param response Response object - * @param album Genre - */ - public void getSongs(final DataResponse> response, final Genre genre, final Context context); - - /** - * Gets all artists from database - * @param response Response object - */ - public void getArtists(final DataResponse> response, final Context context); - - /** - * Gets all artists with at least one song of a genre. - * @param response Response object - * @param genre Genre - */ - public void getArtists(final DataResponse> response, final Genre genre, final Context context); - - /** - * Gets all artists from database - * @param response Response object - */ - public void getGenres(final DataResponse> response, final Context context); - - /** - * Adds an album to the current playlist. If current playlist is stopped, - * the album is added to playlist and the first song is selected to play. - * If something is playing already, the album is only queued. - * - * @param response Response object - * @param album Album to add - */ - public void addToPlaylist(final DataResponse response, final Album album, final Context context); - - /** - * Adds all songs of a genre to the current playlist. If current playlist is stopped, - * play is executed. Value is the first song of the added album. - * @param response Response object - * @param genre Genre of songs to add - */ - public void addToPlaylist(final DataResponse response, final Genre genre, final Context context); - - /** - * Adds a song to the current playlist. Even if the playlist is empty, only this song will be added. - * @param response Response object - * @param album Song to add - */ - public void addToPlaylist(final DataResponse response, final Song song, final Context context); - - /** - * Adds a song to the current playlist. If the playlist is empty, the whole - * album will be added with this song playing, otherwise only this song is - * added. - * - * Attention, the response.value result is different as usual: True - * means the whole album was added, false means ony the song. - * - * @param response Response object - * @param album Album to add - * @param song Song to play - */ - public void addToPlaylist(final DataResponse response, final Album album, final Song song, final Context context); - - /** - * Adds all songs from an artist to the playlist. If current playlist is - * stopped, the all songs of the artist are added to playlist and the first - * song is selected to play. If something is playing already, the songs are - * only queued. - * @param response Response object - * @param artist - */ - public void addToPlaylist(final DataResponse response, final Artist artist, final Context context); - - /** - * Adds all songs of a genre from an artist to the playlist. If nothing is playing, - * the first song will be played, otherwise songs are just added to the playlist. - * @param response Response object - * @param artist - * @param genre - */ - public void addToPlaylist(final DataResponse response, final Artist artist, final Genre genre, final Context context); - - /** - * Sets the media at playlist position position to be the next item to be played. - * @param response Response object - * @param position Position, starting with 0. - */ - public void setPlaylistSong(final DataResponse response, final int position, final Context context); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param response Response object - * @param position Position to remove, starting with 0. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final int position, final Context context); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final String path, final Context context); - - /** - * Plays an album - * @param response Response object - * @param album Album to play - */ - public void play(final DataResponse response, final Album album, final Context context); - - /** - * Plays all songs of a genre - * @param response Response object - * @param genre Genre of songs to play - */ - public void play(final DataResponse response, final Genre genre, final Context context); - - /** - * Plays a song - * @param response Response object - * @param song Song to play - */ - public void play(final DataResponse response, final Song song, final Context context); - - /** - * Plays a song, but the whole album is added to the playlist. - * @param response Response object - * @param album Album to queue - * @param song Song to play - */ - public void play(final DataResponse response, final Album album, final Song song, final Context context); - - /** - * Plays all songs from an artist - * @param response Response object - * @param artist Artist whose songs to play - */ - public void play(final DataResponse response, final Artist artist, final Context context); - - /** - * Plays songs of a genre from an artist - * @param response Response object - * @param artist Artist whose songs to play - * @param genre Genre filter - */ - public void play(final DataResponse response, final Artist artist, final Genre genre, final Context context); - - /** - * Starts playing the next media in the current playlist. - * @param response Response object - */ - public void playlistNext(final DataResponse response, final Context context); - - /** - * Returns an array of songs on the playlist. Empty array if nothing is playing. - * @param response Response object - */ - public void getPlaylist(final DataResponse> response, final Context context); - - /** - * Returns the position of the currently playing song in the playlist. First position is 0. - * @param response Response object - */ - public void getPlaylistPosition(final DataResponse response, final Context context); - - /** - * Updates the album object with additional data from the albuminfo table - * @param response Response object - * @param album Album to update - */ - public void updateAlbumInfo(final DataResponse response, final Album album, final Context context); - - /** - * Updates the artist object with additional data from the artistinfo table - * @param response Response object - * @param artist Artist to update - */ - public void updateArtistInfo(final DataResponse response, final Artist artist, final Context context); - - /** - * Put in here everything that has to be cleaned up after leaving an activity. - */ - public void postActivity(); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.Context; + +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Song; + +import java.util.ArrayList; + +/** + * This is the interface between the presentation layer and the business layer. + * All the controller of the presentation layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IMusicManager extends IManager { + + /** + * Gets all albums from database + * + * @param response Response object + */ + public void getCompilations(final DataResponse> response, final Context context); + + /** + * Gets all albums from database + * + * @param response Response object + */ + public void getAlbums(final DataResponse> response, final Context context); + + /** + * SYNCHRONOUSLY gets all albums from database + * + * @return All albums in database + */ + public ArrayList getAlbums(final Context context); + + /** + * Gets all albums of an artist from database + * + * @param response Response object + * @param artist Artist of the albums + */ + public void getAlbums(final DataResponse> response, final Artist artist, final Context context); + + /** + * Gets all albums of a genre from database + * + * @param response Response object + * @param genre Genre of the albums + */ + public void getAlbums(final DataResponse> response, final Genre genre, final Context context); + + /** + * Gets all songs of an album from database + * + * @param response Response object + * @param album Album + */ + public void getSongs(final DataResponse> response, final Album album, final Context context); + + /** + * Gets all songs from an artist from database + * + * @param response Response object + * @param artist Artist + */ + public void getSongs(final DataResponse> response, final Artist artist, final Context context); + + /** + * Gets all songs of a genre from database + * + * @param response Response object + * @param genre Genre + */ + public void getSongs(final DataResponse> response, final Genre genre, final Context context); + + /** + * Gets all artists from database + * + * @param response Response object + */ + public void getArtists(final DataResponse> response, final Context context); + + /** + * Gets all artists with at least one song of a genre. + * + * @param response Response object + * @param genre Genre + */ + public void getArtists(final DataResponse> response, final Genre genre, final Context context); + + /** + * Gets all artists from database + * + * @param response Response object + */ + public void getGenres(final DataResponse> response, final Context context); + + /** + * Adds an album to the current playlist. If current playlist is stopped, + * the album is added to playlist and the first song is selected to play. + * If something is playing already, the album is only queued. + * + * @param response Response object + * @param album Album to add + */ + public void addToPlaylist(final DataResponse response, final Album album, final Context context); + + /** + * Adds all songs of a genre to the current playlist. If current playlist is stopped, + * play is executed. Value is the first song of the added album. + * + * @param response Response object + * @param genre Genre of songs to add + */ + public void addToPlaylist(final DataResponse response, final Genre genre, final Context context); + + /** + * Adds a song to the current playlist. Even if the playlist is empty, only this song will be added. + * + * @param response Response object + * @param song Song to add + */ + public void addToPlaylist(final DataResponse response, final Song song, final Context context); + + /** + * Adds a song to the current playlist. If the playlist is empty, the whole + * album will be added with this song playing, otherwise only this song is + * added. + *

+ * Attention, the response.value result is different as usual: True + * means the whole album was added, false means ony the song. + * + * @param response Response object + * @param album Album to add + * @param song Song to play + */ + public void addToPlaylist(final DataResponse response, final Album album, final Song song, + final Context context); + + /** + * Adds all songs from an artist to the playlist. If current playlist is + * stopped, the all songs of the artist are added to playlist and the first + * song is selected to play. If something is playing already, the songs are + * only queued. + * + * @param response Response object + * @param artist + */ + public void addToPlaylist(final DataResponse response, final Artist artist, final Context context); + + /** + * Adds all songs of a genre from an artist to the playlist. If nothing is playing, + * the first song will be played, otherwise songs are just added to the playlist. + * + * @param response Response object + * @param artist + * @param genre + */ + public void addToPlaylist(final DataResponse response, final Artist artist, final Genre genre, + final Context context); + + /** + * Sets the media at playlist position position to be the next item to be played. + * + * @param response Response object + * @param position Position, starting with 0. + */ + public void setPlaylistSong(final DataResponse response, final int position, final Context context); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param response Response object + * @param position Position to remove, starting with 0. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final int position, final Context context); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final String path, final Context context); + + /** + * Plays an album + * + * @param response Response object + * @param album Album to play + */ + public void play(final DataResponse response, final Album album, final Context context); + + /** + * Plays all songs of a genre + * + * @param response Response object + * @param genre Genre of songs to play + */ + public void play(final DataResponse response, final Genre genre, final Context context); + + /** + * Plays a song + * + * @param response Response object + * @param song Song to play + */ + public void play(final DataResponse response, final Song song, final Context context); + + /** + * Plays a song, but the whole album is added to the playlist. + * + * @param response Response object + * @param album Album to queue + * @param song Song to play + */ + public void play(final DataResponse response, final Album album, final Song song, final Context context); + + /** + * Plays all songs from an artist + * + * @param response Response object + * @param artist Artist whose songs to play + */ + public void play(final DataResponse response, final Artist artist, final Context context); + + /** + * Plays songs of a genre from an artist + * + * @param response Response object + * @param artist Artist whose songs to play + * @param genre Genre filter + */ + public void play(final DataResponse response, final Artist artist, final Genre genre, + final Context context); + + /** + * Starts playing the next media in the current playlist. + * + * @param response Response object + */ + public void playlistNext(final DataResponse response, final Context context); + + /** + * Returns an array of songs on the playlist. Empty array if nothing is playing. + * + * @param response Response object + */ + public void getPlaylist(final DataResponse> response, final Context context); + + /** + * Returns the position of the currently playing song in the playlist. First position is 0. + * + * @param response Response object + */ + public void getPlaylistPosition(final DataResponse response, final Context context); + + /** + * Updates the album object with additional data from the albuminfo table + * + * @param response Response object + * @param album Album to update + */ + public void updateAlbumInfo(final DataResponse response, final Album album, final Context context); + + /** + * Updates the artist object with additional data from the artistinfo table + * + * @param response Response object + * @param artist Artist to update + */ + public void updateArtistInfo(final DataResponse response, final Artist artist, final Context context); + + /** + * Put in here everything that has to be cleaned up after leaving an activity. + */ + public void postActivity(); + } \ No newline at end of file diff --git a/src/org/xbmc/api/business/INotifiableManager.java b/app/src/main/java/org/xbmc/api/business/INotifiableManager.java similarity index 97% rename from src/org/xbmc/api/business/INotifiableManager.java rename to app/src/main/java/org/xbmc/api/business/INotifiableManager.java index 174e8c96..56585b4e 100644 --- a/src/org/xbmc/api/business/INotifiableManager.java +++ b/app/src/main/java/org/xbmc/api/business/INotifiableManager.java @@ -1,34 +1,39 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import org.xbmc.android.remote.business.Command; - -public interface INotifiableManager { - - public void onFinish(DataResponse response); - public void onWrongConnectionState(int state, Command cmd); - public void onError(Exception e); - public void onMessage(String message); - public void onMessage(int code, String message); - public void retryAll(); -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import org.xbmc.android.remote.business.Command; + +public interface INotifiableManager { + + public void onFinish(DataResponse response); + + public void onWrongConnectionState(int state, Command cmd); + + public void onError(Exception e); + + public void onMessage(String message); + + public void onMessage(int code, String message); + + public void retryAll(); +} diff --git a/src/org/xbmc/api/business/ISortableManager.java b/app/src/main/java/org/xbmc/api/business/ISortableManager.java similarity index 96% rename from src/org/xbmc/api/business/ISortableManager.java rename to app/src/main/java/org/xbmc/api/business/ISortableManager.java index 5642e30e..c3f3af2e 100644 --- a/src/org/xbmc/api/business/ISortableManager.java +++ b/app/src/main/java/org/xbmc/api/business/ISortableManager.java @@ -1,41 +1,43 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import android.content.SharedPreferences; - -public interface ISortableManager { - - /** - * Sets the static reference to the preferences object. Used to obtain - * current sort values. - * @param pref - */ - public void setPreferences(SharedPreferences pref); - - /** - * Sets which kind of view is currently active. - * @param sortKey - */ - public void setSortKey(int sortKey); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.SharedPreferences; + +public interface ISortableManager { + + /** + * Sets the static reference to the preferences object. Used to obtain + * current sort values. + * + * @param pref + */ + public void setPreferences(SharedPreferences pref); + + /** + * Sets which kind of view is currently active. + * + * @param sortKey + */ + public void setSortKey(int sortKey); + } \ No newline at end of file diff --git a/src/org/xbmc/api/business/ITvShowManager.java b/app/src/main/java/org/xbmc/api/business/ITvShowManager.java similarity index 87% rename from src/org/xbmc/api/business/ITvShowManager.java rename to app/src/main/java/org/xbmc/api/business/ITvShowManager.java index b3255a88..2d0189eb 100644 --- a/src/org/xbmc/api/business/ITvShowManager.java +++ b/app/src/main/java/org/xbmc/api/business/ITvShowManager.java @@ -1,6 +1,6 @@ package org.xbmc.api.business; -import java.util.ArrayList; +import android.content.Context; import org.xbmc.api.object.Actor; import org.xbmc.api.object.Episode; @@ -8,76 +8,89 @@ import org.xbmc.api.object.Season; import org.xbmc.api.object.TvShow; -import android.content.Context; +import java.util.ArrayList; + +public interface ITvShowManager extends IManager { -public interface ITvShowManager extends IManager{ - public void getTvShows(DataResponse> response, Context context); - public void getTvShowActors(DataResponse> response, Context context) ; + + public void getTvShowActors(DataResponse> response, Context context); + public void getTvShowGenres(DataResponse> response, Context context); + public void getTvShows(DataResponse> response, Genre genre, Context context); + public ArrayList getTvShows(Context context); + public ArrayList getAllSeasons(Context context); + public ArrayList getAllEpisodes(Context context); - + /** * Gets all tv shows with the specified actor - * @param manager + * * @param actor */ public void getTvShows(DataResponse> response, Actor actor, Context context); - + /** * Gets all Episodes for the specified show + * * @param show */ - public void getEpisodes(DataResponse> response, TvShow show, Context context) ; - + public void getEpisodes(DataResponse> response, TvShow show, Context context); + /** * Gets all Episodes for the specified show and season + * * @param response * @param show * @param season * @param context */ - public void getEpisodes(DataResponse> response, TvShow show, Season season, Context context) ; - + public void getEpisodes(DataResponse> response, TvShow show, Season season, Context context); + /** * Gets all Episodes for the specified season + * * @param response * @param season * @param context */ - public void getEpisodes(DataResponse> response, Season season, Context context) ; - + public void getEpisodes(DataResponse> response, Season season, Context context); + /** * Gets all recently added episodes + * * @param response * @param context */ - public void getRecentlyAddedEpisodes(DataResponse> response, Context context) ; - + public void getRecentlyAddedEpisodes(DataResponse> response, Context context); + /** * Gets all seasons for the specified show + * * @param show */ public void getSeasons(DataResponse> response, TvShow show, Context context); - + /** - * Updates the given Episode with + * Updates the given Episode with + * * @param response * @param episode * @param context */ public void updateEpisodeDetails(DataResponse response, Episode episode, Context context); - + /** * Updates the give TvShow + * * @param response * @param show */ public void updateTvShowDetails(DataResponse response, TvShow show, Context context); - + /** * Put in here everything that has to be cleaned up after leaving an activity. */ diff --git a/src/org/xbmc/api/business/IVideoManager.java b/app/src/main/java/org/xbmc/api/business/IVideoManager.java similarity index 89% rename from src/org/xbmc/api/business/IVideoManager.java rename to app/src/main/java/org/xbmc/api/business/IVideoManager.java index 2c37d3ae..612ae33b 100644 --- a/src/org/xbmc/api/business/IVideoManager.java +++ b/app/src/main/java/org/xbmc/api/business/IVideoManager.java @@ -1,146 +1,163 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.business; - -import java.util.ArrayList; - -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.Movie; - -import android.content.Context; - -/** - * This is the interface between the presentation layer and the business layer. - * All the controller of the presentation layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IVideoManager extends IManager { - - /** - * Updates the movie object with additional data (plot, cast, etc) - * @param response Response object - */ - public void updateMovieDetails(final DataResponse response, final Movie movie, final Context context); - - /** - * Gets all movies from database - * @param response Response object - */ - public void getMovies(final DataResponse> response, final Context context); - - /** - * SYNCHRONOUSLY gets all movies from database - * @return All movies in database - */ - public ArrayList getMovies(final Context context); - - /** - * SYNCHRONOUSLY gets all movies from database - * @return Movies in database with offset - */ - public ArrayList getMovies(final Context context, int offset); - - /** - * Gets all movies with an actor from database - * @param response Response object - * @param actor Actor - */ - public void getMovies(final DataResponse> response, final Actor actor, final Context context); - /** - * Gets all movies of a genre from database - * @param response Response object - * @param genre Genre - */ - public void getMovies(final DataResponse> response, final Genre genre, final Context context); - - /** - * Gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. - * @param response Response object - */ - public void getActors(final DataResponse> response, final Context context); - - /** - * SYNCHRONOUSLY gets all actors from database. - * @return All actors - */ - public ArrayList getActors(final Context context); - - /** - * Gets all movie actors from database - * @param response Response object - */ - public void getMovieActors(final DataResponse> response, final Context context); - - /** - * Gets all TV show actors from database - * @param response Response object - */ - public void getTvShowActors(final DataResponse> response, final Context context); - - /** - * Gets all movie genres from database - * @param response Response object - */ - public void getMovieGenres(final DataResponse> response, final Context context); - - /** - * Gets all tv show genres from the database - * @param response Response object - * @param context - */ - public void getTvShowGenres(final DataResponse< ArrayList> response, final Context context); - - /** - * Sets the media at playlist position to be the next item to be played. - * @param response Response object - * @param position Position, starting with 0. - */ - public void setPlaylistVideo(final DataResponse response, final int position, final Context context); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public void removeFromPlaylist(final DataResponse response, final String path, final Context context); - - /** - * Returns an array of videos on the playlist. Empty array if nothing is playing. - * @param response Response object - */ - public void getPlaylist(final DataResponse> response, final Context context); - - /** - * Returns the position of the currently playing video in the playlist. First position is 0. - * @param response Response object - */ - public void getPlaylistPosition(final DataResponse response, final Context context); - - /** - * Put in here everything that has to be cleaned up after leaving an activity. - */ - public void postActivity(); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.business; + +import android.content.Context; + +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.Movie; + +import java.util.ArrayList; + +/** + * This is the interface between the presentation layer and the business layer. + * All the controller of the presentation layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IVideoManager extends IManager { + + /** + * Updates the movie object with additional data (plot, cast, etc) + * + * @param response Response object + */ + public void updateMovieDetails(final DataResponse response, final Movie movie, final Context context); + + /** + * Gets all movies from database + * + * @param response Response object + */ + public void getMovies(final DataResponse> response, final Context context); + + /** + * SYNCHRONOUSLY gets all movies from database + * + * @return All movies in database + */ + public ArrayList getMovies(final Context context); + + /** + * SYNCHRONOUSLY gets all movies from database + * + * @return Movies in database with offset + */ + public ArrayList getMovies(final Context context, int offset); + + /** + * Gets all movies with an actor from database + * + * @param response Response object + * @param actor Actor + */ + public void getMovies(final DataResponse> response, final Actor actor, final Context context); + + /** + * Gets all movies of a genre from database + * + * @param response Response object + * @param genre Genre + */ + public void getMovies(final DataResponse> response, final Genre genre, final Context context); + + /** + * Gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * + * @param response Response object + */ + public void getActors(final DataResponse> response, final Context context); + + /** + * SYNCHRONOUSLY gets all actors from database. + * + * @return All actors + */ + public ArrayList getActors(final Context context); + + /** + * Gets all movie actors from database + * + * @param response Response object + */ + public void getMovieActors(final DataResponse> response, final Context context); + + /** + * Gets all TV show actors from database + * + * @param response Response object + */ + public void getTvShowActors(final DataResponse> response, final Context context); + + /** + * Gets all movie genres from database + * + * @param response Response object + */ + public void getMovieGenres(final DataResponse> response, final Context context); + + /** + * Gets all tv show genres from the database + * + * @param response Response object + * @param context + */ + public void getTvShowGenres(final DataResponse> response, final Context context); + + /** + * Sets the media at playlist position to be the next item to be played. + * + * @param response Response object + * @param position Position, starting with 0. + */ + public void setPlaylistVideo(final DataResponse response, final int position, final Context context); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public void removeFromPlaylist(final DataResponse response, final String path, final Context context); + + /** + * Returns an array of videos on the playlist. Empty array if nothing is playing. + * + * @param response Response object + */ + public void getPlaylist(final DataResponse> response, final Context context); + + /** + * Returns the position of the currently playing video in the playlist. First position is 0. + * + * @param response Response object + */ + public void getPlaylistPosition(final DataResponse response, final Context context); + + /** + * Put in here everything that has to be cleaned up after leaving an activity. + */ + public void postActivity(); + } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IClient.java b/app/src/main/java/org/xbmc/api/data/IClient.java similarity index 95% rename from src/org/xbmc/api/data/IClient.java rename to app/src/main/java/org/xbmc/api/data/IClient.java index 59d82d9c..abbf0e46 100644 --- a/src/org/xbmc/api/data/IClient.java +++ b/app/src/main/java/org/xbmc/api/data/IClient.java @@ -1,42 +1,43 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - -import org.xbmc.api.object.Host; - - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * Common interface for all clients - * - * @author Team XBMC - */ -public interface IClient { - - /** - * Updates host info on the connection. - * @param host - */ - public void setHost(Host host); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + +import org.xbmc.api.object.Host; + + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + *

+ * Common interface for all clients + * + * @author Team XBMC + */ +public interface IClient { + + /** + * Updates host info on the connection. + * + * @param host + */ + public void setHost(Host host); } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IControlClient.java b/app/src/main/java/org/xbmc/api/data/IControlClient.java similarity index 81% rename from src/org/xbmc/api/data/IControlClient.java rename to app/src/main/java/org/xbmc/api/data/IControlClient.java index 37152b74..d9c49f2b 100644 --- a/src/org/xbmc/api/data/IControlClient.java +++ b/app/src/main/java/org/xbmc/api/data/IControlClient.java @@ -1,316 +1,354 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - -import java.io.Serializable; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.type.SeekType; - - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IControlClient extends IClient { - - /** - * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. - * @param manager Manager reference - * @param fileOrFolder - * @return true on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, String fileOrFolder, int playlistType); - - /** - * Starts playing the media file filename . - * @param manager Manager reference - * @param filename File to play - * @return true on success, false otherwise. - */ - public boolean playFile(INotifiableManager manager, String filename, int playlistType); - - /** - * Starts playing/showing the next media/image in the current playlist or, - * if currently showing a slideshow, the slideshow playlist. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean playNext(INotifiableManager manager); - - /** - * Starts playing/showing the previous media/image in the current playlist - * or, if currently showing a slidshow, the slideshow playlist. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean playPrevious(INotifiableManager manager); - - /** - * Pauses the currently playing media. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean pause(INotifiableManager manager); - - /** - * Stops the currently playing media. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean stop(INotifiableManager manager); - - /** - * Start playing the media file at the given URL - * @param manager Manager reference - * @param url An URL pointing to a supported media file - * @return true on success, false otherwise. - */ - public boolean playUrl(INotifiableManager manager, String url); - - /** - * Sets the volume as a percentage of the maximum possible. - * @param manager Manager reference - * @param volume New volume (0-100) - * @return true on success, false otherwise. - */ - public boolean setVolume(INotifiableManager manager, int volume); - - /** - * Seeks to a position. If type is - *

    - *
  • absolute - Sets the playing position of the currently - * playing media as a percentage of the media�s length.
  • - *
  • relative - Adds/Subtracts the current percentage on to - * the current position in the song
  • - *
- * @param manager Manager reference - * @param type Seek type, relative or absolute - * @param progress Progress - * @return true on success, false otherwise. - */ - public boolean seek(INotifiableManager manager, SeekType type, int progress); - - /** - * Send the string text via keys on the virtual keyboard. - * @param manager Manager reference - * @param text The text string to send. - * @return true on success, false otherwise. - */ - public boolean sendText(INotifiableManager manager, String text); - - /** - * Toggles the sound on/off. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean mute(INotifiableManager manager); - - /** - * Retrieves the current playing position of the currently playing media as - * a percentage of the media's length. - * @param manager Manager reference - * @return Percentage (0-100) - */ - public int getPercentage(INotifiableManager manager); - - /** - * Retrieves the current volume setting as a percentage of the maximum - * possible value. - * @param manager Manager reference - * @return Volume (0-100) - */ - public int getVolume(INotifiableManager manager); - - /** - * Navigates... UP! - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean navUp(INotifiableManager manager); - - /** - * Navigates... DOWN! - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean navDown(INotifiableManager manager); - - /** - * Navigates... LEFT! - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean navLeft(INotifiableManager manager); - - /** - * Navigates... RIGHT! - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean navRight(INotifiableManager manager); - - /** - * Selects current item. - * @param manager Manager reference - * @return true on success, false otherwise. - */ - public boolean navSelect(INotifiableManager manager); - - /** - * Takes either "video" or "music" as a parameter to begin updating the - * corresponding database. - * - * TODO For "video" you can additionally specify a specific path to be scanned. - * - * @param manager Manager reference - * @param mediaType Either video or music. - * @return True on success, false otherwise. - */ - public boolean updateLibrary(INotifiableManager manager, String mediaType); - - /** - * Show the picture file filename. - * @param manager Manager reference - * @param filename File to show - * @return true on success, false otherwise. - */ - public boolean showPicture(INotifiableManager manager, String filename); - - /** - * Broadcast a message. Used to test broadcasting feature. - * @param manager Manager reference - * @param message - * @return True on success, false otherwise. - */ - public boolean broadcast(INotifiableManager manager, String message); - - /** - * Returns the current broadcast port number, or 0 if deactivated. - * @param manager Manager reference - * @return Current broadcast port number. - */ - public int getBroadcast(INotifiableManager manager); - - /** - * Sets the brodcast level and port. Level currently only takes three values: - *
    - *
  • 0 - No broadcasts
  • - *
  • 1 - Media playback and startup & shutdown events - *
  • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. - *
- * - * @param manager Manager reference - * @param port Broadcast port - * @param level Broadcast level - * @return True on success, false otherwise. - */ - public boolean setBroadcast(INotifiableManager manager, int port, int level); - - /** - * Returns current play state - * @param manager Manager reference - * @return - */ - public int getPlayState(INotifiableManager manager); - - /** - * Returns the current playlist identifier - * @param manager Manager reference - */ - public int getPlaylistId(INotifiableManager manager); - - /** - * Sets current playlist - * @param manager Manager reference - * @param playlistId Playlist ID ("0" = music, "1" = video) - * @return True on success, false otherwise. - */ - public boolean setCurrentPlaylist(INotifiableManager manager, int playlistId); - - /** - * Sets the current playlist identifier - * @param manager Manager reference - * @param id Playlist identifier - * @return True on success, false otherwise. - */ - public boolean setPlaylistId(INotifiableManager manager, int id); - - /** - * Sets the current playlist position - * @param manager Manager reference - * @param position New playlist position - * @return True on success, false otherwise. - */ - public boolean setPlaylistPos(INotifiableManager manager, int playlistId, int position); - - /** - * Clears a playlist. - * @param manager Manager reference - * @param playlistId Playlist ID to clear (0 = music, 1 = video) - * @return True on success, false otherwise. - */ - public boolean clearPlaylist(INotifiableManager manager, int playlistId); - - /** - * Returns state and type of the media currently playing. - * @return - */ - public ICurrentlyPlaying getCurrentlyPlaying(INotifiableManager manager); - - /** - * Sets the gui setting of XBMC to value - * @param manager - * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings - * @param value the value to set - * @return {@code true} if the value was set successfully - */ - public boolean setGuiSetting(INotifiableManager manager, final int setting, final String value); - - /** - * Data object for "Currently playing" info. - * @TODO rename fields so it doesn't feel wierd using for videos.. - * @TODO move class to objects, this is public, not data.. - * @author Team XBMC - */ - public interface ICurrentlyPlaying extends Serializable { - public int getPlayStatus(); - public int getMediaType(); - public boolean isPlaying(); - public int getPlaylistPosition(); - - public String getFilename(); - public String getTitle(); - - public int getTime(); - public int getDuration(); - public float getPercentage(); - - public String getArtist(); - public String getAlbum(); - - public int getWidth(); - public int getHeight(); - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.type.SeekType; + +import java.io.Serializable; + + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IControlClient extends IClient { + + /** + * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. + * + * @param manager Manager reference + * @param fileOrFolder + * @return true on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, String fileOrFolder, int playlistType); + + /** + * Starts playing the media file filename . + * + * @param manager Manager reference + * @param filename File to play + * @return true on success, false otherwise. + */ + public boolean playFile(INotifiableManager manager, String filename, int playlistType); + + /** + * Starts playing/showing the next media/image in the current playlist or, + * if currently showing a slideshow, the slideshow playlist. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean playNext(INotifiableManager manager); + + /** + * Starts playing/showing the previous media/image in the current playlist + * or, if currently showing a slidshow, the slideshow playlist. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean playPrevious(INotifiableManager manager); + + /** + * Pauses the currently playing media. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean pause(INotifiableManager manager); + + /** + * Stops the currently playing media. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean stop(INotifiableManager manager); + + /** + * Start playing the media file at the given URL + * + * @param manager Manager reference + * @param url An URL pointing to a supported media file + * @return true on success, false otherwise. + */ + public boolean playUrl(INotifiableManager manager, String url); + + /** + * Sets the volume as a percentage of the maximum possible. + * + * @param manager Manager reference + * @param volume New volume (0-100) + * @return true on success, false otherwise. + */ + public boolean setVolume(INotifiableManager manager, int volume); + + /** + * Seeks to a position. If type is + *
    + *
  • absolute - Sets the playing position of the currently + * playing media as a percentage of the media�s length.
  • + *
  • relative - Adds/Subtracts the current percentage on to + * the current position in the song
  • + *
+ * + * @param manager Manager reference + * @param type Seek type, relative or absolute + * @param progress Progress + * @return true on success, false otherwise. + */ + public boolean seek(INotifiableManager manager, SeekType type, int progress); + + /** + * Send the string text via keys on the virtual keyboard. + * + * @param manager Manager reference + * @param text The text string to send. + * @return true on success, false otherwise. + */ + public boolean sendText(INotifiableManager manager, String text); + + /** + * Toggles the sound on/off. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean mute(INotifiableManager manager); + + /** + * Retrieves the current playing position of the currently playing media as + * a percentage of the media's length. + * + * @param manager Manager reference + * @return Percentage (0-100) + */ + public int getPercentage(INotifiableManager manager); + + /** + * Retrieves the current volume setting as a percentage of the maximum + * possible value. + * + * @param manager Manager reference + * @return Volume (0-100) + */ + public int getVolume(INotifiableManager manager); + + /** + * Navigates... UP! + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean navUp(INotifiableManager manager); + + /** + * Navigates... DOWN! + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean navDown(INotifiableManager manager); + + /** + * Navigates... LEFT! + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean navLeft(INotifiableManager manager); + + /** + * Navigates... RIGHT! + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean navRight(INotifiableManager manager); + + /** + * Selects current item. + * + * @param manager Manager reference + * @return true on success, false otherwise. + */ + public boolean navSelect(INotifiableManager manager); + + /** + * Takes either "video" or "music" as a parameter to begin updating the + * corresponding database. + *

+ * TODO For "video" you can additionally specify a specific path to be scanned. + * + * @param manager Manager reference + * @param mediaType Either video or music. + * @return True on success, false otherwise. + */ + public boolean updateLibrary(INotifiableManager manager, String mediaType); + + /** + * Show the picture file filename. + * + * @param manager Manager reference + * @param filename File to show + * @return true on success, false otherwise. + */ + public boolean showPicture(INotifiableManager manager, String filename); + + /** + * Broadcast a message. Used to test broadcasting feature. + * + * @param manager Manager reference + * @param message + * @return True on success, false otherwise. + */ + public boolean broadcast(INotifiableManager manager, String message); + + /** + * Returns the current broadcast port number, or 0 if deactivated. + * + * @param manager Manager reference + * @return Current broadcast port number. + */ + public int getBroadcast(INotifiableManager manager); + + /** + * Sets the brodcast level and port. Level currently only takes three values: + *

    + *
  • 0 - No broadcasts
  • + *
  • 1 - Media playback and startup & shutdown events + *
  • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. + *
+ * + * @param manager Manager reference + * @param port Broadcast port + * @param level Broadcast level + * @return True on success, false otherwise. + */ + public boolean setBroadcast(INotifiableManager manager, int port, int level); + + /** + * Returns current play state + * + * @param manager Manager reference + * @return + */ + public int getPlayState(INotifiableManager manager); + + /** + * Returns the current playlist identifier + * + * @param manager Manager reference + */ + public int getPlaylistId(INotifiableManager manager); + + /** + * Sets current playlist + * + * @param manager Manager reference + * @param playlistId Playlist ID ("0" = music, "1" = video) + * @return True on success, false otherwise. + */ + public boolean setCurrentPlaylist(INotifiableManager manager, int playlistId); + + /** + * Sets the current playlist identifier + * + * @param manager Manager reference + * @param id Playlist identifier + * @return True on success, false otherwise. + */ + public boolean setPlaylistId(INotifiableManager manager, int id); + + /** + * Sets the current playlist position + * + * @param manager Manager reference + * @param position New playlist position + * @return True on success, false otherwise. + */ + public boolean setPlaylistPos(INotifiableManager manager, int playlistId, int position); + + /** + * Clears a playlist. + * + * @param manager Manager reference + * @param playlistId Playlist ID to clear (0 = music, 1 = video) + * @return True on success, false otherwise. + */ + public boolean clearPlaylist(INotifiableManager manager, int playlistId); + + /** + * Returns state and type of the media currently playing. + * + * @return + */ + public ICurrentlyPlaying getCurrentlyPlaying(INotifiableManager manager); + + /** + * Sets the gui setting of XBMC to value + * + * @param manager + * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings + * @param value the value to set + * @return {@code true} if the value was set successfully + */ + public boolean setGuiSetting(INotifiableManager manager, final int setting, final String value); + + /** + * Data object for "Currently playing" info. + * + * @author Team XBMC + * @TODO rename fields so it doesn't feel wierd using for videos.. + * @TODO move class to objects, this is public, not data.. + */ + public interface ICurrentlyPlaying extends Serializable { + public int getPlayStatus(); + + public int getMediaType(); + + public boolean isPlaying(); + + public int getPlaylistPosition(); + + public String getFilename(); + + public String getTitle(); + + public int getTime(); + + public int getDuration(); + + public float getPercentage(); + + public String getArtist(); + + public String getAlbum(); + + public int getWidth(); + + public int getHeight(); + } } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IEventClient.java b/app/src/main/java/org/xbmc/api/data/IEventClient.java similarity index 50% rename from src/org/xbmc/api/data/IEventClient.java rename to app/src/main/java/org/xbmc/api/data/IEventClient.java index 5ab28cfd..e523a475 100644 --- a/src/org/xbmc/api/data/IEventClient.java +++ b/app/src/main/java/org/xbmc/api/data/IEventClient.java @@ -1,148 +1,144 @@ -package org.xbmc.api.data; - -import java.io.IOException; - -/** - * XBMC Event Client Class - * - * Implements an XBMC-Client. This class can be used to implement your own - * application which should act as a Input device for XBMC. Also starts a - * Ping-Thread, which tells the XBMC EventServer that the client is alive. - * Therefore if you close your application you SHOULD call stopClient()! - * - * @author Team XBMC - */ -public interface IEventClient { - - - /** - * Sets the icon using a path name to a image file (png, jpg or gif). - * @param iconPath Path to icon - */ - public void setIcon(String iconPath); - - /** - * Sets the icon from raw data - * @param iconType Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) - * @param iconData The icon itself as a Byte-Array - */ - public void setIcon(byte iconType, byte[] iconData); - - - /** - * Stops the XBMC EventClient (especially the Ping-Thread) - * - * @throws IOException - */ - public void stopClient() throws IOException; - - - /** - * Displays a notification window in XBMC. - * - * @param title Message title - * @param message The actual message - */ - public void sendNotification(String title, String message) throws IOException; - public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException; - - /** - * Sends a Button event - * - * @param code Raw button code (default: 0) - * @param repeat This key press should repeat until released (default: 1) - * Note that queued pressed cannot repeat. - * @param down If this is 1, it implies a press event, 0 implies a - * release event. (default: 1) - * @param queue A queued key press means that the button event is executed - * just once after which the next key press is processed. It - * can be used for macros. Currently there is no support for - * time delays between queued presses. (default: 0) - * @param amount Unimplemented for now; in the future it will be used for - * specifying magnitude of analog key press events - * @param axis - */ - public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) throws IOException; - - /** - * Sends a Button event - * - * @param map_name - * A combination of map_name and button_name refers to a mapping - * in the user's Keymap.xml or Lircmap.xml. map_name can be one - * of the following: - *
    - *
  • KB - Standard keyboard map (<keyboard> section)
  • - *
  • XG - Xbox gamepad map (<gamepad> section)
  • - *
  • R1 - Xbox remote map (<remote> section)
  • - *
  • R2 - Xbox universal remote map (<universalremote> - * section)
  • - *
  • LI:devicename - LIRC remote map where devicename is - * the actual device's name
  • - *
- * @param button_name - * A button name defined in the map specified in map_name. For - * example, if map_name is "KB" refering to the - * section in Keymap.xml then, valid button_names include - * "printscreen", "minus", "x", etc. - * @param repeat - * This key press should repeat until released (default: 1) Note - * that queued pressed cannot repeat. - * @param down - * If this is 1, it implies a press event, 0 implies a release - * event. (default: 1) - * @param queue - * A queued key press means that the button event is executed - * just once after which the next key press is processed. It can - * be used for macros. Currently there is no support for time - * delays between queued presses. (default: 0) - * @param amount - * Unimplemented for now; in the future it will be used for - * specifying magnitude of analog key press events - * @param axis - */ - public void sendButton(String map_name, String button_name, boolean repeat, - boolean down, boolean queue, short amount, byte axis); - - /** - * Sets the mouse position in XBMC - * - * @param x Horizontal position ranging from 0 to 65535 - * @param y Vertical position ranging from 0 to 65535 - */ - public void sendMouse(int x, int y) throws IOException; - - /** - * Sends a ping to the XBMC EventServer - * - * @throws IOException - */ - public void ping() throws IOException; - - /** - * Tells XBMC to log the message to xbmc.log with the loglevel as specified. - * - * @param loglevel - * The log level, follows XBMC standard. - *
    - *
  • 0 = DEBUG
  • - *
  • 1 = INFO
  • - *
  • 2 = NOTICE
  • - *
  • 3 = WARNING
  • - *
  • 4 = ERROR
  • - *
  • 5 = SEVERE
  • - *
- * @param logmessage - * The message to log - */ - public void sendLog(byte loglevel, String logmessage) throws IOException; - - /** - * Tells XBMC to do the action specified, based on the type it knows were it - * needs to be sent. - * - * @param actionmessage Actionmessage (as in scripting/skinning) - */ - public void sendAction(String actionmessage) throws IOException; - +package org.xbmc.api.data; + +import java.io.IOException; + +/** + * XBMC Event Client Class + *

+ * Implements an XBMC-Client. This class can be used to implement your own + * application which should act as a Input device for XBMC. Also starts a + * Ping-Thread, which tells the XBMC EventServer that the client is alive. + * Therefore if you close your application you SHOULD call stopClient()! + * + * @author Team XBMC + */ +public interface IEventClient { + + + /** + * Sets the icon using a path name to a image file (png, jpg or gif). + * + * @param iconPath Path to icon + */ + public void setIcon(String iconPath); + + /** + * Sets the icon from raw data + * + * @param iconType Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon itself as a Byte-Array + */ + public void setIcon(byte iconType, byte[] iconData); + + + /** + * Stops the XBMC EventClient (especially the Ping-Thread) + * + * @throws IOException + */ + public void stopClient() throws IOException; + + + /** + * Displays a notification window in XBMC. + * + * @param title Message title + * @param message The actual message + */ + public void sendNotification(String title, String message) throws IOException; + + public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException; + + /** + * Sends a Button event + * + * @param code Raw button code (default: 0) + * @param repeat This key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down If this is 1, it implies a press event, 0 implies a + * release event. (default: 1) + * @param queue A queued key press means that the button event is executed + * just once after which the next key press is processed. It + * can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount Unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, + byte axis) throws IOException; + + /** + * Sends a Button event + * + * @param map_name A combination of map_name and button_name refers to a mapping + * in the user's Keymap.xml or Lircmap.xml. map_name can be one + * of the following: + *

    + *
  • KB - Standard keyboard map (<keyboard> section)
  • + *
  • XG - Xbox gamepad map (<gamepad> section)
  • + *
  • R1 - Xbox remote map (<remote> section)
  • + *
  • R2 - Xbox universal remote map (<universalremote> + * section)
  • + *
  • LI:devicename - LIRC remote map where devicename is + * the actual device's name
  • + *
+ * @param button_name A button name defined in the map specified in map_name. For + * example, if map_name is "KB" refering to the + * section in Keymap.xml then, valid button_names include + * "printscreen", "minus", "x", etc. + * @param repeat This key press should repeat until released (default: 1) Note + * that queued pressed cannot repeat. + * @param down If this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue A queued key press means that the button event is executed + * just once after which the next key press is processed. It can + * be used for macros. Currently there is no support for time + * delays between queued presses. (default: 0) + * @param amount Unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public void sendButton(String map_name, String button_name, boolean repeat, + boolean down, boolean queue, short amount, byte axis); + + /** + * Sets the mouse position in XBMC + * + * @param x Horizontal position ranging from 0 to 65535 + * @param y Vertical position ranging from 0 to 65535 + */ + public void sendMouse(int x, int y) throws IOException; + + /** + * Sends a ping to the XBMC EventServer + * + * @throws IOException + */ + public void ping() throws IOException; + + /** + * Tells XBMC to log the message to xbmc.log with the loglevel as specified. + * + * @param loglevel The log level, follows XBMC standard. + *
    + *
  • 0 = DEBUG
  • + *
  • 1 = INFO
  • + *
  • 2 = NOTICE
  • + *
  • 3 = WARNING
  • + *
  • 4 = ERROR
  • + *
  • 5 = SEVERE
  • + *
+ * @param logmessage The message to log + */ + public void sendLog(byte loglevel, String logmessage) throws IOException; + + /** + * Tells XBMC to do the action specified, based on the type it knows were it + * needs to be sent. + * + * @param actionmessage Actionmessage (as in scripting/skinning) + */ + public void sendAction(String actionmessage) throws IOException; + } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IInfoClient.java b/app/src/main/java/org/xbmc/api/data/IInfoClient.java similarity index 83% rename from src/org/xbmc/api/data/IInfoClient.java rename to app/src/main/java/org/xbmc/api/data/IInfoClient.java index cb5d9d6e..b1b759bd 100644 --- a/src/org/xbmc/api/data/IInfoClient.java +++ b/app/src/main/java/org/xbmc/api/data/IInfoClient.java @@ -1,125 +1,138 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.FileLocation; -import org.xbmc.api.type.DirectoryMask; - - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IInfoClient extends IClient { - - /** - * Returns the contents of a directory - * @param path Path to the directory - * @param mask Mask to filter - * @param offset Offset (0 for none) - * @param limit Limit (0 for none) - * @return - */ - public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, int offset, int limit, int mediaType); - - /** - * Returns all the contents of a directory - * @param path Path to the directory - * @return - */ - public ArrayList getDirectory(INotifiableManager manager, String path, int mediaType); - - - /** - * Returns all defined shares of a media type - * @param mediaType Media type - * @return - */ - public ArrayList getShares(INotifiableManager manager, int mediaType); - - /** - * Returns URI of the currently playing's thumbnail. - * @return - * @throws MalformedURLException - * @throws URISyntaxException - */ - public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, URISyntaxException; - - /** - * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} - * @param field Field to return - * @return - */ - public String getSystemInfo(INotifiableManager manager, int field); - - /** - * Returns a boolean GUI setting - * @param field - * @return - */ - public boolean getGuiSettingBool(INotifiableManager manager, int field); - - /** - * Returns an integer GUI setting - * @param field - * @return - */ - public int getGuiSettingInt(INotifiableManager manager, int field); - - /** - * Returns a boolean GUI setting - * @param field - * @param value Value - * @return - */ - public boolean setGuiSettingBool(INotifiableManager manager, int field, boolean value); - - /** - * Returns an integer GUI setting - * @param field - * @param value Value - * @return - */ - public boolean setGuiSettingInt(INotifiableManager manager, int field, int value); - - /** - * Returns any music info variable see {@link org.xbmc.http.info.MusicInfo} - * @param field Field to return - * @return - */ - public String getMusicInfo(INotifiableManager manager, int field); - - /** - * Returns any video info variable see {@link org.xbmc.http.info.VideoInfo} - * @param field Field to return - * @return - */ - public String getVideoInfo(INotifiableManager manager, int field); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.FileLocation; +import org.xbmc.api.type.DirectoryMask; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.ArrayList; + + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IInfoClient extends IClient { + + /** + * Returns the contents of a directory + * + * @param path Path to the directory + * @param mask Mask to filter + * @param offset Offset (0 for none) + * @param limit Limit (0 for none) + * @return + */ + public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, + int offset, int limit, int mediaType); + + /** + * Returns all the contents of a directory + * + * @param path Path to the directory + * @return + */ + public ArrayList getDirectory(INotifiableManager manager, String path, int mediaType); + + + /** + * Returns all defined shares of a media type + * + * @param mediaType Media type + * @return + */ + public ArrayList getShares(INotifiableManager manager, int mediaType); + + /** + * Returns URI of the currently playing's thumbnail. + * + * @return + * @throws MalformedURLException + * @throws URISyntaxException + */ + public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, + URISyntaxException; + + /** + * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} + * + * @param field Field to return + * @return + */ + public String getSystemInfo(INotifiableManager manager, int field); + + /** + * Returns a boolean GUI setting + * + * @param field + * @return + */ + public boolean getGuiSettingBool(INotifiableManager manager, int field); + + /** + * Returns an integer GUI setting + * + * @param field + * @return + */ + public int getGuiSettingInt(INotifiableManager manager, int field); + + /** + * Returns a boolean GUI setting + * + * @param field + * @param value Value + * @return + */ + public boolean setGuiSettingBool(INotifiableManager manager, int field, boolean value); + + /** + * Returns an integer GUI setting + * + * @param field + * @param value Value + * @return + */ + public boolean setGuiSettingInt(INotifiableManager manager, int field, int value); + + /** + * Returns any music info variable see {@link org.xbmc.api.info.MusicInfo} + * + * @param field Field to return + * @return + */ + public String getMusicInfo(INotifiableManager manager, int field); + + /** + * Returns any video info variable see {@link org.xbmc.api.info.VideoInfo} + * + * @param field Field to return + * @return + */ + public String getVideoInfo(INotifiableManager manager, int field); + } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IMusicClient.java b/app/src/main/java/org/xbmc/api/data/IMusicClient.java similarity index 84% rename from src/org/xbmc/api/data/IMusicClient.java rename to app/src/main/java/org/xbmc/api/data/IMusicClient.java index 6707584a..3248f8af 100644 --- a/src/org/xbmc/api/data/IMusicClient.java +++ b/app/src/main/java/org/xbmc/api/data/IMusicClient.java @@ -1,321 +1,356 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - -import java.util.ArrayList; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.Album; -import org.xbmc.api.object.Artist; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.object.Song; - -import android.graphics.Bitmap; - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IMusicClient extends IClient { - - // those are the musicdb://n/ keys. - public static final int MUSICDB_GENRE = 1; - public static final int MUSICDB_ARTIST = 2; - public static final int MUSICDB_ALBUM = 3; - public static final int MUSICDB_SONG = 4; - public static final int MUSICDB_TOP100 = 5; - public static final int MUSICDB_RECENTLY_ADDED = 6; - public static final int MUSICDB_RECENTLY_PLAYED = 7; - public static final int MUSICDB_COMPILATION = 8; - public static final int MUSICDB_YEARS = 9; - public static final int MUSICDB_SINGLES = 10; - - /** - * Adds an album to the current playlist. - * @param album Album - * @return True on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, Album album, int sortBy, String sortOrder); - - /** - * Adds all songs from an artist to the current playlist. - * @param artist Artist - * @return True on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); - - /** - * Adds all songs from a genre to the current playlist. - * @param genre Genre - * @return True on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); - - /** - * Adds songs of a genre from an artist to the current playlist. - * @param artist Artist - * @param genre Genre - * @return True on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder); - - /** - * Adds a song to the current playlist. - * @param song Song to add - * @return True on success, false otherwise. - */ - public boolean addToPlaylist(INotifiableManager manager, Song song); - - /** - * Returns how many items are in the playlist. - * @return Number of items in the playlist - */ - public int getPlaylistSize(INotifiableManager manager); - - /** - * Retrieves the currently playing song number in the playlist. - * @return Number of items in the playlist - */ - public int getPlaylistPosition(INotifiableManager manager); - - /** - * Sets the media at playlist position position to be the next item to be played. - * @param position New position, starting with 0. - * @return True on success, false otherwise. - */ - public boolean setPlaylistPosition(INotifiableManager manager, int position); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Position to remove, starting with 0. - * @return True on success, false otherwise. - */ - public boolean removeFromPlaylist(INotifiableManager manager, int position); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public boolean removeFromPlaylist(INotifiableManager manager, String path); - - /** - * Returns the first {@link PLAYLIST_LIMIT} songs of the playlist. - * @return Songs in the playlist. - */ - public ArrayList getPlaylist(INotifiableManager manager); - - /** - * Clears current playlist - * @return True on success, false otherwise. - */ - public boolean clearPlaylist(INotifiableManager manager); - - /** - * Adds a song to the current playlist and plays it. - * @param song Song - * @return True on success, false otherwise. - */ - public boolean play(INotifiableManager manager, Song song); - - /** - * Plays an album. Playlist is previously cleared. - * @param album Album to play - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return True on success, false otherwise. - */ - public boolean play(INotifiableManager manager, Album album, int sortBy, String sortOrder); - - /** - * Plays all songs of a genre. Playlist is previously cleared. - * @param genre Genre - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return True on success, false otherwise. - */ - public boolean play(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); - - /** - * Plays all songs from an artist. Playlist is previously cleared. - * @param artist Artist - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return True on success, false otherwise. - */ - public boolean play(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); - - /** - * Plays songs of a genre from an artist. Playlist is previously cleared. - * @param artist Artist - * @param genre Genre - * @return True on success, false otherwise. - */ - public boolean play(INotifiableManager manager, Artist artist, Genre genre); - - /** - * Starts playing/showing the next media/image in the current playlist - * or, if currently showing a slidshow, the slideshow playlist. - * @return True on success, false otherwise. - */ - public boolean playNext(INotifiableManager manager); - - /** - * Starts playing/showing the previous media/image in the current playlist - * or, if currently showing a slidshow, the slideshow playlist. - * @return True on success, false otherwise. - */ - public boolean playPrev(INotifiableManager manager); - - /** - * Sets the media at playlist position position to be the next item to be - * played. Position starts at 0, so SetPlaylistSong(5) sets the position - * to the 6th song in the playlist. - * @param pos Position - * @return true on success, false otherwise. - */ - public boolean playlistSetSong(INotifiableManager manager, int pos); - - /** - * Gets all albums with given artist IDs - * @param artistIDs Array of artist IDs - * @return All compilation albums - */ - public ArrayList getAlbums(INotifiableManager manager, ArrayList artistIDs); - - /** - * Gets all albums from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All albums - */ - public ArrayList getAlbums(INotifiableManager manager, int sortBy, String sortOrder); - - /** - * Gets all albums of an artist from database - * @param artist Artist - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return Albums with an artist - */ - public ArrayList getAlbums(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); - - /** - * Gets all albums of with at least one song in a genre - * @param genre Genre - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return Albums of a genre - */ - public ArrayList getAlbums(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); - - /** - * Gets all albums from database - * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. - * @return All albums - */ - public ArrayList getArtists(INotifiableManager manager, boolean albumArtistsOnly); - - /** - * Gets all artists with at least one song of a genre. - * @param genre Genre - * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. - * @return Albums with a genre - */ - public ArrayList getArtists(INotifiableManager manager, Genre genre, boolean albumArtistsOnly); - - /** - * Gets all genres from database - * @return All genres - */ - public ArrayList getGenres(INotifiableManager manager); - - /** - * Updates the album object with additional data from the albuminfo table - * @param album - * @return Updated album - */ - public Album updateAlbumInfo(INotifiableManager manager, Album album); - - /** - * Updates the artist object with additional data from the artistinfo table - * @param artist - * @return Updated artist - */ - public Artist updateArtistInfo(INotifiableManager manager, Artist artist); - - /** - * Returns a list containing all tracks of an album. The list is sorted by filename. - * @param album Album - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All tracks of an album - */ - public ArrayList getSongs(INotifiableManager manager, Album album, int sortBy, String sortOrder); - - /** - * Returns a list containing all tracks of an artist. The list is sorted by album name, filename. - * @param artist Artist - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All tracks of the artist - */ - public ArrayList getSongs(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); - - /** - * Returns a list containing all tracks of a genre. The list is sorted by artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All tracks of the genre - */ - public ArrayList getSongs(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); - - /** - * Returns a list containing all tracks of a genre AND and artist. The list is sorted by - * artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All tracks of the genre - */ - public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder); - - /** - * Returns a list containing all artist IDs that stand for "compilation". - * Best case scenario would be only one ID for "Various Artists", though - * there are also just "V.A." or "VA" naming conventions. - * @return List of compilation artist IDs - */ - public ArrayList getCompilationArtistIDs(INotifiableManager manager); - - /** - * Returns album thumbnail as base64-encoded string - * @param album - * @return Base64-encoded content of thumb - */ - public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + +import android.graphics.Bitmap; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.Album; +import org.xbmc.api.object.Artist; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.object.Song; + +import java.util.ArrayList; + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IMusicClient extends IClient { + + // those are the musicdb://n/ keys. + public static final int MUSICDB_GENRE = 1; + public static final int MUSICDB_ARTIST = 2; + public static final int MUSICDB_ALBUM = 3; + public static final int MUSICDB_SONG = 4; + public static final int MUSICDB_TOP100 = 5; + public static final int MUSICDB_RECENTLY_ADDED = 6; + public static final int MUSICDB_RECENTLY_PLAYED = 7; + public static final int MUSICDB_COMPILATION = 8; + public static final int MUSICDB_YEARS = 9; + public static final int MUSICDB_SINGLES = 10; + + /** + * Adds an album to the current playlist. + * + * @param album Album + * @return True on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, Album album, int sortBy, String sortOrder); + + /** + * Adds all songs from an artist to the current playlist. + * + * @param artist Artist + * @return True on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); + + /** + * Adds all songs from a genre to the current playlist. + * + * @param genre Genre + * @return True on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); + + /** + * Adds songs of a genre from an artist to the current playlist. + * + * @param artist Artist + * @param genre Genre + * @return True on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder); + + /** + * Adds a song to the current playlist. + * + * @param song Song to add + * @return True on success, false otherwise. + */ + public boolean addToPlaylist(INotifiableManager manager, Song song); + + /** + * Returns how many items are in the playlist. + * + * @return Number of items in the playlist + */ + public int getPlaylistSize(INotifiableManager manager); + + /** + * Retrieves the currently playing song number in the playlist. + * + * @return Number of items in the playlist + */ + public int getPlaylistPosition(INotifiableManager manager); + + /** + * Sets the media at playlist position position to be the next item to be played. + * + * @param position New position, starting with 0. + * @return True on success, false otherwise. + */ + public boolean setPlaylistPosition(INotifiableManager manager, int position); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param position Position to remove, starting with 0. + * @return True on success, false otherwise. + */ + public boolean removeFromPlaylist(INotifiableManager manager, int position); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public boolean removeFromPlaylist(INotifiableManager manager, String path); + + /** + * Returns the first songs of the playlist. + * + * @return Songs in the playlist. + */ + public ArrayList getPlaylist(INotifiableManager manager); + + /** + * Clears current playlist + * + * @return True on success, false otherwise. + */ + public boolean clearPlaylist(INotifiableManager manager); + + /** + * Adds a song to the current playlist and plays it. + * + * @param song Song + * @return True on success, false otherwise. + */ + public boolean play(INotifiableManager manager, Song song); + + /** + * Plays an album. Playlist is previously cleared. + * + * @param album Album to play + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return True on success, false otherwise. + */ + public boolean play(INotifiableManager manager, Album album, int sortBy, String sortOrder); + + /** + * Plays all songs of a genre. Playlist is previously cleared. + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return True on success, false otherwise. + */ + public boolean play(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); + + /** + * Plays all songs from an artist. Playlist is previously cleared. + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return True on success, false otherwise. + */ + public boolean play(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); + + /** + * Plays songs of a genre from an artist. Playlist is previously cleared. + * + * @param artist Artist + * @param genre Genre + * @return True on success, false otherwise. + */ + public boolean play(INotifiableManager manager, Artist artist, Genre genre); + + /** + * Starts playing/showing the next media/image in the current playlist + * or, if currently showing a slidshow, the slideshow playlist. + * + * @return True on success, false otherwise. + */ + public boolean playNext(INotifiableManager manager); + + /** + * Starts playing/showing the previous media/image in the current playlist + * or, if currently showing a slidshow, the slideshow playlist. + * + * @return True on success, false otherwise. + */ + public boolean playPrev(INotifiableManager manager); + + /** + * Sets the media at playlist position position to be the next item to be + * played. Position starts at 0, so SetPlaylistSong(5) sets the position + * to the 6th song in the playlist. + * + * @param pos Position + * @return true on success, false otherwise. + */ + public boolean playlistSetSong(INotifiableManager manager, int pos); + + /** + * Gets all albums with given artist IDs + * + * @param artistIDs Array of artist IDs + * @return All compilation albums + */ + public ArrayList getAlbums(INotifiableManager manager, ArrayList artistIDs); + + /** + * Gets all albums from database + * + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All albums + */ + public ArrayList getAlbums(INotifiableManager manager, int sortBy, String sortOrder); + + /** + * Gets all albums of an artist from database + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return Albums with an artist + */ + public ArrayList getAlbums(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); + + /** + * Gets all albums of with at least one song in a genre + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return Albums of a genre + */ + public ArrayList getAlbums(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); + + /** + * Gets all albums from database + * + * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. + * @return All albums + */ + public ArrayList getArtists(INotifiableManager manager, boolean albumArtistsOnly); + + /** + * Gets all artists with at least one song of a genre. + * + * @param genre Genre + * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. + * @return Albums with a genre + */ + public ArrayList getArtists(INotifiableManager manager, Genre genre, boolean albumArtistsOnly); + + /** + * Gets all genres from database + * + * @return All genres + */ + public ArrayList getGenres(INotifiableManager manager); + + /** + * Updates the album object with additional data from the albuminfo table + * + * @param album + * @return Updated album + */ + public Album updateAlbumInfo(INotifiableManager manager, Album album); + + /** + * Updates the artist object with additional data from the artistinfo table + * + * @param artist + * @return Updated artist + */ + public Artist updateArtistInfo(INotifiableManager manager, Artist artist); + + /** + * Returns a list containing all tracks of an album. The list is sorted by filename. + * + * @param album Album + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All tracks of an album + */ + public ArrayList getSongs(INotifiableManager manager, Album album, int sortBy, String sortOrder); + + /** + * Returns a list containing all tracks of an artist. The list is sorted by album name, filename. + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All tracks of the artist + */ + public ArrayList getSongs(INotifiableManager manager, Artist artist, int sortBy, String sortOrder); + + /** + * Returns a list containing all tracks of a genre. The list is sorted by artist, album name, filename. + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All tracks of the genre + */ + public ArrayList getSongs(INotifiableManager manager, Genre genre, int sortBy, String sortOrder); + + /** + * Returns a list containing all tracks of a genre AND and artist. The list is sorted by + * artist, album name, filename. + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All tracks of the genre + */ + public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, + String sortOrder); + + /** + * Returns a list containing all artist IDs that stand for "compilation". + * Best case scenario would be only one ID for "Various Artists", though + * there are also just "V.A." or "VA" naming conventions. + * + * @return List of compilation artist IDs + */ + public ArrayList getCompilationArtistIDs(INotifiableManager manager); + + /** + * Returns album thumbnail as base64-encoded string + * + * @return Base64-encoded content of thumb + */ + public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size); + } \ No newline at end of file diff --git a/src/org/xbmc/api/data/IPictureClient.java b/app/src/main/java/org/xbmc/api/data/IPictureClient.java similarity index 96% rename from src/org/xbmc/api/data/IPictureClient.java rename to app/src/main/java/org/xbmc/api/data/IPictureClient.java index 4a22d990..14d9fb90 100644 --- a/src/org/xbmc/api/data/IPictureClient.java +++ b/app/src/main/java/org/xbmc/api/data/IPictureClient.java @@ -1,34 +1,33 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - - - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IPictureClient extends IClient { - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IPictureClient extends IClient { + } \ No newline at end of file diff --git a/src/org/xbmc/api/data/ITvShowClient.java b/app/src/main/java/org/xbmc/api/data/ITvShowClient.java similarity index 82% rename from src/org/xbmc/api/data/ITvShowClient.java rename to app/src/main/java/org/xbmc/api/data/ITvShowClient.java index 86ac11f0..0b087466 100644 --- a/src/org/xbmc/api/data/ITvShowClient.java +++ b/app/src/main/java/org/xbmc/api/data/ITvShowClient.java @@ -1,6 +1,6 @@ package org.xbmc.api.data; -import java.util.ArrayList; +import android.graphics.Bitmap; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.object.Actor; @@ -10,100 +10,121 @@ import org.xbmc.api.object.Season; import org.xbmc.api.object.TvShow; -import android.graphics.Bitmap; +import java.util.ArrayList; public interface ITvShowClient extends IClient { public ArrayList getTvShows(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched); - public ArrayList getTvShowActors(INotifiableManager manager) ; + + public ArrayList getTvShowActors(INotifiableManager manager); + public ArrayList getTvShowGenres(INotifiableManager manager); - + /** * Gets all tv shows with the specified genre + * * @param manager * @param genre * @return */ - public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched); - + public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched); + /** * Gets all tv shows with the specified actor + * * @param manager * @param actor * @return */ - public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched); - + public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched); + /** * Gets all Episodes for the specified show + * * @param manager * @param show * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, boolean hideWatched) ; - + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, + boolean hideWatched); + /** * Gets all Episodes for the specified season + * * @param manager * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, boolean hideWatched) ; - + public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, + boolean hideWatched); + /** * Gets all Episodes for the specified show and season + * * @param manager * @param show * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, String sortOrder, boolean hideWatched) ; - + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, + String sortOrder, boolean hideWatched); + /** * Gets all episodes from all shows + * * @param manager * @return */ - public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched); - + public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched); + /** * Gets recently added episodes + * * @param manager * @return */ - public ArrayList getRecentlyAddedEpisodes(INotifiableManager manager, boolean hideWatched) ; + public ArrayList getRecentlyAddedEpisodes(INotifiableManager manager, boolean hideWatched); + /** * Gets all seasons for the specified show + * * @param manager * @param show * @return */ public ArrayList getSeasons(INotifiableManager manager, TvShow show, boolean hideWatched); - + /** * Gets all seasons from all shows + * * @param manager * @return */ public ArrayList getSeasons(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched); - + /** * Returns a cover as bitmap + * * @param cover * @return Cover */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size); - + /** * Updates the episode with plot and actors + * * @param manager * @param episode * @return */ public Episode updateEpisodeDetails(INotifiableManager manager, Episode episode); - + /** * Updates the show with summary + * * @param manager * @param show * @return diff --git a/src/org/xbmc/api/data/IVideoClient.java b/app/src/main/java/org/xbmc/api/data/IVideoClient.java similarity index 78% rename from src/org/xbmc/api/data/IVideoClient.java rename to app/src/main/java/org/xbmc/api/data/IVideoClient.java index 16a70cb9..027a3425 100644 --- a/src/org/xbmc/api/data/IVideoClient.java +++ b/app/src/main/java/org/xbmc/api/data/IVideoClient.java @@ -1,150 +1,166 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.data; - -import java.util.ArrayList; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.Actor; -import org.xbmc.api.object.Genre; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.object.Movie; - -import android.graphics.Bitmap; - - -/** - * This is the interface between the business layer and the presentation layer. - * All the business layer gets to see is this interface. - * - * @author Team XBMC - */ -public interface IVideoClient extends IClient { - - /** - * Gets all movies from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All movies - */ - public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched); - - /** - * Gets all movies from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @param offset Offset - * @return All movies - */ - public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, boolean hideWatched); - - /** - * Gets all movies with an actor from database - * @param actor Display only movies with this actor. - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All movies with an actor - */ - public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched); - - /** - * Gets all movies of a genre from database - * @param genre Display only movies of this genre. - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return All movies of a genre - */ - public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched); - - /** - * Gets all movies from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. - * @return Updated movie - */ - public Movie updateMovieDetails(INotifiableManager manager, Movie movie); - - /** - * Gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. - * @return All actors - */ - public ArrayList getActors(INotifiableManager manager); - - /** - * Gets all movie actors from database - * @return All movie actors - */ - public ArrayList getMovieActors(INotifiableManager manager); - - /** - * Gets all movie actors from database - * @return All movie actors - */ - public ArrayList getTvShowActors(INotifiableManager manager); - - /** - * Gets all movie genres from database - * @return All movie genres - */ - public ArrayList getMovieGenres(INotifiableManager manager); - - /** - * Gets all tv show genres from the database - * @return All tv show genres - */ - public ArrayList getTvShowGenres(INotifiableManager manager); - - /** - * Returns a cover as bitmap - * @param cover - * @return Cover - */ - public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size); - - /** - * Retrieves the currently playing video number in the playlist. - * @return Number of items in the playlist - */ - public int getPlaylistPosition(INotifiableManager manager); - - /** - * Sets the media at position position to be the next item to be played. - * @param position New position, starting with 0. - * @return True on success, false otherwise. - */ - public boolean setPlaylistPosition(INotifiableManager manager, int position); - - /** - * Returns the first {@link PLAYLIST_LIMIT} videos of the playlist. - * @return Videos in the playlist. - */ - public ArrayList getPlaylist(INotifiableManager manager); - - /** - * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. - * @return True on success, false otherwise. - */ - public boolean removeFromPlaylist(INotifiableManager manager, String path); - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.data; + +import android.graphics.Bitmap; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.Actor; +import org.xbmc.api.object.Genre; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.object.Movie; + +import java.util.ArrayList; + + +/** + * This is the interface between the business layer and the presentation layer. + * All the business layer gets to see is this interface. + * + * @author Team XBMC + */ +public interface IVideoClient extends IClient { + + /** + * Gets all movies from database + * + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All movies + */ + public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched); + + /** + * Gets all movies from database + * + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @param offset Offset + * @return All movies + */ + public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, + boolean hideWatched); + + /** + * Gets all movies with an actor from database + * + * @param actor Display only movies with this actor. + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All movies with an actor + */ + public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched); + + /** + * Gets all movies of a genre from database + * + * @param genre Display only movies of this genre. + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * @return All movies of a genre + */ + public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched); + + /** + * Gets all movies from database + * + * @return Updated movie + */ + public Movie updateMovieDetails(INotifiableManager manager, Movie movie); + + /** + * Gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * + * @return All actors + */ + public ArrayList getActors(INotifiableManager manager); + + /** + * Gets all movie actors from database + * + * @return All movie actors + */ + public ArrayList getMovieActors(INotifiableManager manager); + + /** + * Gets all movie actors from database + * + * @return All movie actors + */ + public ArrayList getTvShowActors(INotifiableManager manager); + + /** + * Gets all movie genres from database + * + * @return All movie genres + */ + public ArrayList getMovieGenres(INotifiableManager manager); + + /** + * Gets all tv show genres from the database + * + * @return All tv show genres + */ + public ArrayList getTvShowGenres(INotifiableManager manager); + + /** + * Returns a cover as bitmap + * + * @param cover + * @return Cover + */ + public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size); + + /** + * Retrieves the currently playing video number in the playlist. + * + * @return Number of items in the playlist + */ + public int getPlaylistPosition(INotifiableManager manager); + + /** + * Sets the media at position position to be the next item to be played. + * + * @param position New position, starting with 0. + * @return True on success, false otherwise. + */ + public boolean setPlaylistPosition(INotifiableManager manager, int position); + + /** + * Returns the first videos of the playlist. + * + * @return Videos in the playlist. + */ + public ArrayList getPlaylist(INotifiableManager manager); + + /** + * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * + * @param path Complete path (including filename) of the media to be removed. + * @return True on success, false otherwise. + */ + public boolean removeFromPlaylist(INotifiableManager manager, String path); + } \ No newline at end of file diff --git a/src/org/xbmc/api/info/FileTypes.java b/app/src/main/java/org/xbmc/api/info/FileTypes.java similarity index 85% rename from src/org/xbmc/api/info/FileTypes.java rename to app/src/main/java/org/xbmc/api/info/FileTypes.java index 9b6a908d..c34fedfd 100644 --- a/src/org/xbmc/api/info/FileTypes.java +++ b/app/src/main/java/org/xbmc/api/info/FileTypes.java @@ -1,113 +1,119 @@ -/* - * Copyright (C) 2005-2011 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.info; - -/** - * Defines known media file types and some helper methods. - * - * @author freezy - */ -public class FileTypes { - - /** - * Audio file extensions - */ - public final static String[] AUDIO = { "ac3", "flac", "m4a", "mp3", "mid", "ogg", "wav" }; - - /** - * Playlist file extensions - */ - public final static String[] PLAYLIST = { "m3u", "pls" }; - - /** - * Video extensions - */ - public final static String[] VIDEO = { "avi", "flv", "mkv", "mov", "mp4", "mpg", "mpeg", "ts", "wmv", "vob" }; - - /** - * Image extensions - */ - public final static String[] PICTURE = { "bmp", "gif", "jpeg", "jpg", "png", "tbn" }; - - /** - * Returns true if extensions is of type audio. - * @param extension Extension to check, without "." - * @return true if audio extension, false otherwise. - */ - public static boolean isAudio(String extension) { - return is(AUDIO, extension); - } - - /** - * Returns true if extensions is of type audio. - * @param extension Extension to check, without "." - * @return true if audio extension, false otherwise. - */ - public static boolean isAudioOrPlaylist(String extension) { - return is(AUDIO, extension) || is(PLAYLIST, extension); - } - - /** - * Returns true if extensions is of type video. - * @param extension Extension to check, without "." - * @return true if video extension, false otherwise. - */ - public static boolean isVideo(String extension) { - return is(VIDEO, extension); - } - - /** - * Returns true if extensions is of type playlist. - * @param extension Extension to check, without "." - * @return true if playlist extension, false otherwise. - */ - public static boolean isPicture(String extension) { - return is(PICTURE, extension); - } - - /** - * Returns true if extensions is of type picture. - * @param extension Extension to check, without "." - * @return true if picture extension, false otherwise. - */ - public static boolean isPlaylist(String extension) { - return is(PLAYLIST, extension); - } - - /** - * Returns the file extension of a file name or path in lower case. - * @param filenameOrPath File name or path - * @return File extension without "." - */ - public static String getExtension(String filenameOrPath) { - return filenameOrPath.substring(filenameOrPath.lastIndexOf(".") + 1).toLowerCase(); - } - - private static boolean is(String[] arr, String extension) { - for (String audioExt : arr) { - if (audioExt.equals(extension)) { - return true; - } - } - return false; - } -} +/* + * Copyright (C) 2005-2011 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +/** + * Defines known media file types and some helper methods. + * + * @author freezy + */ +public class FileTypes { + + /** + * Audio file extensions + */ + public final static String[] AUDIO = {"ac3", "flac", "m4a", "mp3", "mid", "ogg", "wav"}; + + /** + * Playlist file extensions + */ + public final static String[] PLAYLIST = {"m3u", "pls"}; + + /** + * Video extensions + */ + public final static String[] VIDEO = {"avi", "flv", "mkv", "mov", "mp4", "mpg", "mpeg", "ts", "wmv", "vob"}; + + /** + * Image extensions + */ + public final static String[] PICTURE = {"bmp", "gif", "jpeg", "jpg", "png", "tbn"}; + + /** + * Returns true if extensions is of type audio. + * + * @param extension Extension to check, without "." + * @return true if audio extension, false otherwise. + */ + public static boolean isAudio(String extension) { + return is(AUDIO, extension); + } + + /** + * Returns true if extensions is of type audio. + * + * @param extension Extension to check, without "." + * @return true if audio extension, false otherwise. + */ + public static boolean isAudioOrPlaylist(String extension) { + return is(AUDIO, extension) || is(PLAYLIST, extension); + } + + /** + * Returns true if extensions is of type video. + * + * @param extension Extension to check, without "." + * @return true if video extension, false otherwise. + */ + public static boolean isVideo(String extension) { + return is(VIDEO, extension); + } + + /** + * Returns true if extensions is of type playlist. + * + * @param extension Extension to check, without "." + * @return true if playlist extension, false otherwise. + */ + public static boolean isPicture(String extension) { + return is(PICTURE, extension); + } + + /** + * Returns true if extensions is of type picture. + * + * @param extension Extension to check, without "." + * @return true if picture extension, false otherwise. + */ + public static boolean isPlaylist(String extension) { + return is(PLAYLIST, extension); + } + + /** + * Returns the file extension of a file name or path in lower case. + * + * @param filenameOrPath File name or path + * @return File extension without "." + */ + public static String getExtension(String filenameOrPath) { + return filenameOrPath.substring(filenameOrPath.lastIndexOf(".") + 1).toLowerCase(); + } + + private static boolean is(String[] arr, String extension) { + for (String audioExt : arr) { + if (audioExt.equals(extension)) { + return true; + } + } + return false; + } +} diff --git a/app/src/main/java/org/xbmc/api/info/GuiActions.java b/app/src/main/java/org/xbmc/api/info/GuiActions.java new file mode 100644 index 00000000..615678a0 --- /dev/null +++ b/app/src/main/java/org/xbmc/api/info/GuiActions.java @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +public abstract class GuiActions { + + public static final int ACTION_NONE = 0; + public static final int ACTION_MOVE_LEFT = 1; + public static final int ACTION_MOVE_RIGHT = 2; + public static final int ACTION_MOVE_UP = 3; + public static final int ACTION_MOVE_DOWN = 4; + public static final int ACTION_PAGE_UP = 5; + public static final int ACTION_PAGE_DOWN = 6; + public static final int ACTION_SELECT_ITEM = 7; + public static final int ACTION_HIGHLIGHT_ITEM = 8; + public static final int ACTION_PARENT_DIR = 9; + public static final int ACTION_PREVIOUS_MENU = 10; + public static final int ACTION_SHOW_INFO = 11; + + public static final int ACTION_PAUSE = 12; + public static final int ACTION_STOP = 13; + public static final int ACTION_NEXT_ITEM = 14; + public static final int ACTION_PREV_ITEM = 15; + public static final int ACTION_FORWARD = 16; // Can be used to specify specific action in a window, + // Playback control is handled in ACTION_PLAYER_* + public static final int ACTION_REWIND = 17; // Can be used to specify specific action in a window, + // Playback control is handled in ACTION_PLAYER_* + + public static final int ACTION_SHOW_GUI = 18; // toggle between GUI and movie or GUI and visualisation. + public static final int ACTION_ASPECT_RATIO = 19; // toggle quick-access zoom modes. Can b used in videoFullScreen + // .zml window id=2005 + public static final int ACTION_STEP_FORWARD = 20; // seek +1% in the movie. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_STEP_BACK = 21; // seek -1% in the movie. Can b used in videoFullScreen.xml window + // id=2005 + public static final int ACTION_BIG_STEP_FORWARD = 22; // seek +10% in the movie. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_BIG_STEP_BACK = 23; // seek -10% in the movie. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_SHOW_OSD = 24; // show/hide OSD. Can b used in videoFullScreen.xml window id=2005 + public static final int ACTION_SHOW_SUBTITLES = 25; // turn subtitles on/off. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_NEXT_SUBTITLE = 26; // switch to next subtitle of movie. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_SHOW_CODEC = 27; // show information about file. Can b used in videoFullScreen.xml + // window id=2005 and in slideshow.xml window id=2007 + public static final int ACTION_NEXT_PICTURE = 28; // show next picture of slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_PREV_PICTURE = 29; // show previous picture of slideshow. Can b used in slideshow + // .xml window id=2007 + public static final int ACTION_ZOOM_OUT = 30; // zoom in picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_IN = 31; // zoom out picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_TOGGLE_SOURCE_DEST = 32; // used to toggle between source view and destination view + // . Can be used in myfiles.xml window id=3 + public static final int ACTION_SHOW_PLAYLIST = 33; // used to toggle between current view and playlist view. Can b + // used in all mymusic xml files + public static final int ACTION_QUEUE_ITEM = 34; // used to queue a item to the playlist. Can b used in all mymusic + // xml files + public static final int ACTION_REMOVE_ITEM = 35; // not used anymore + public static final int ACTION_SHOW_FULLSCREEN = 36; // not used anymore + public static final int ACTION_ZOOM_LEVEL_NORMAL = 37; // zoom 1x picture during slideshow. Can b used in + // slideshow.xml window id=2007 + public static final int ACTION_ZOOM_LEVEL_1 = 38; // zoom 2x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_2 = 39; // zoom 3x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_3 = 40; // zoom 4x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_4 = 41; // zoom 5x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_5 = 42; // zoom 6x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_6 = 43; // zoom 7x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_7 = 44; // zoom 8x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_8 = 45; // zoom 9x picture during slideshow. Can b used in slideshow.xml + // window id=2007 + public static final int ACTION_ZOOM_LEVEL_9 = 46; // zoom 10x picture during slideshow. Can b used in slideshow + // .xml window id=2007 + + public static final int ACTION_CALIBRATE_SWAP_ARROWS = 47; // select next arrow. Can b used in: + // settingsScreenCalibration.xml windowid=11 + public static final int ACTION_CALIBRATE_RESET = 48; // reset calibration to defaults. Can b used in: + // settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10 + public static final int ACTION_ANALOG_MOVE = 49; // analog thumbstick move. Can b used in: slideshow.xml window + // id=2007/settingsScreenCalibration.xml windowid=11/settingsUICalibration.xml windowid=10 + public static final int ACTION_ROTATE_PICTURE = 50; // rotate current picture during slideshow. Can b used in + // slideshow.xml window id=2007 + public static final int ACTION_CLOSE_DIALOG = 51; // action for closing the dialog. Can b used in any dialog + public static final int ACTION_SUBTITLE_DELAY_MIN = 52; // Decrease subtitle/movie Delay. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_SUBTITLE_DELAY_PLUS = 53; // Increase subtitle/movie Delay. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_AUDIO_DELAY_MIN = 54; // Increase avsync delay. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_AUDIO_DELAY_PLUS = 55; // Decrease avsync delay. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_AUDIO_NEXT_LANGUAGE = 56; // Select next language in movie. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_CHANGE_RESOLUTION = 57; // switch 2 next resolution. Can b used during screen + // calibration settingsScreenCalibration.xml windowid=11 + + public static final int REMOTE_0 = 58; // remote keys 0-9. are used by multiple windows + public static final int REMOTE_1 = 59; // for example in videoFullScreen.xml window id=2005 you can + public static final int REMOTE_2 = 60; // enter time (mmss) to jump to particular point in the movie + public static final int REMOTE_3 = 61; + public static final int REMOTE_4 = 62; // with spincontrols you can enter 3digit number to quickly set + public static final int REMOTE_5 = 63; // spincontrol to desired value + public static final int REMOTE_6 = 64; + public static final int REMOTE_7 = 65; + public static final int REMOTE_8 = 66; + public static final int REMOTE_9 = 67; + + public static final int ACTION_PLAY = 68; // Unused at the moment + public static final int ACTION_OSD_SHOW_LEFT = 69; // Move left in OSD. Can b used in videoFullScreen.xml window + // id=2005 + public static final int ACTION_OSD_SHOW_RIGHT = 70; // Move right in OSD. Can b used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_OSD_SHOW_UP = 71; // Move up in OSD. Can b used in videoFullScreen.xml window + // id=2005 + public static final int ACTION_OSD_SHOW_DOWN = 72; // Move down in OSD. Can b used in videoFullScreen.xml window + // id=2005 + public static final int ACTION_OSD_SHOW_SELECT = 73; // toggle/select option in OSD. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_OSD_SHOW_VALUE_PLUS = 74; // increase value of current option in OSD. Can b used + // in videoFullScreen.xml window id=2005 + public static final int ACTION_OSD_SHOW_VALUE_MIN = 75; // decrease value of current option in OSD. Can b used in + // videoFullScreen.xml window id=2005 + public static final int ACTION_SMALL_STEP_BACK = 76; // jumps a few seconds back during playback of movie. Can b + // used in videoFullScreen.xml window id=2005 + + public static final int ACTION_PLAYER_FORWARD = 77; // FF in current file played. global action, + // can be used anywhere + public static final int ACTION_PLAYER_REWIND = 78; // RW in current file played. global action, + // can be used anywhere + public static final int ACTION_PLAYER_PLAY = 79; // Play current song. Unpauses song and sets playspeed to 1x. + // global action, can be used anywhere + + public static final int ACTION_DELETE_ITEM = 80; // delete current selected item. Can be used in myfiles.xml + // window id=3 and in myvideoTitle.xml window id=25 + public static final int ACTION_COPY_ITEM = 81; // copy current selected item. Can be used in myfiles.xml window + // id=3 + public static final int ACTION_MOVE_ITEM = 82; // move current selected item. Can be used in myfiles.xml window + // id=3 + public static final int ACTION_SHOW_MPLAYER_OSD = 83; // toggles mplayers OSD. Can be used in videofullscreen.xml + // window id=2005 + public static final int ACTION_OSD_HIDESUBMENU = 84; // removes an OSD sub menu. Can be used in videoOSD.xml + // window id=2901 + public static final int ACTION_TAKE_SCREENSHOT = 85; // take a screenshot + public static final int ACTION_RENAME_ITEM = 87; // rename item + + public static final int ACTION_VOLUME_UP = 88; + public static final int ACTION_VOLUME_DOWN = 89; + public static final int ACTION_MUTE = 91; + + public static final int ACTION_MOUSE = 90; + + public static final int ACTION_MOUSE_CLICK = 100; + public static final int ACTION_MOUSE_LEFT_CLICK = 100; + public static final int ACTION_MOUSE_RIGHT_CLICK = 101; + public static final int ACTION_MOUSE_MIDDLE_CLICK = 102; + public static final int ACTION_MOUSE_XBUTTON1_CLICK = 103; + public static final int ACTION_MOUSE_XBUTTON2_CLICK = 104; + + public static final int ACTION_MOUSE_DOUBLE_CLICK = 105; + public static final int ACTION_MOUSE_LEFT_DOUBLE_CLICK = 105; + public static final int ACTION_MOUSE_RIGHT_DOUBLE_CLICK = 106; + public static final int ACTION_MOUSE_MIDDLE_DOUBLE_CLICK = 107; + public static final int ACTION_MOUSE_XBUTTON1_DOUBLE_CLICK = 108; + public static final int ACTION_MOUSE_XBUTTON2_DOUBLE_CLICK = 109; + + public static final int ACTION_BACKSPACE = 110; + public static final int ACTION_SCROLL_UP = 111; + public static final int ACTION_SCROLL_DOWN = 112; + public static final int ACTION_ANALOG_FORWARD = 113; + public static final int ACTION_ANALOG_REWIND = 114; + + public static final int ACTION_MOVE_ITEM_UP = 115; // move item up in playlist + public static final int ACTION_MOVE_ITEM_DOWN = 116; // move item down in playlist + public static final int ACTION_CONTEXT_MENU = 117; // pops up the context menu + + + // stuff for virtual keyboard shortcuts + public static final int ACTION_SHIFT = 118; + public static final int ACTION_SYMBOLS = 119; + public static final int ACTION_CURSOR_LEFT = 120; + public static final int ACTION_CURSOR_RIGHT = 121; + + public static final int ACTION_BUILT_IN_FUNCTION = 122; + + public static final int ACTION_SHOW_OSD_TIME = 123; // displays current time, can be used in videoFullScreen.xml + // window id=2005 + public static final int ACTION_ANALOG_SEEK_FORWARD = 124; // seeks forward, and displays the seek bar. + public static final int ACTION_ANALOG_SEEK_BACK = 125; // seeks backward, and displays the seek bar. + + public static final int ACTION_VIS_PRESET_SHOW = 126; + public static final int ACTION_VIS_PRESET_LIST = 127; + public static final int ACTION_VIS_PRESET_NEXT = 128; + public static final int ACTION_VIS_PRESET_PREV = 129; + public static final int ACTION_VIS_PRESET_LOCK = 130; + public static final int ACTION_VIS_PRESET_RANDOM = 131; + public static final int ACTION_VIS_RATE_PRESET_PLUS = 132; + public static final int ACTION_VIS_RATE_PRESET_MINUS = 133; + + public static final int ACTION_SHOW_VIDEOMENU = 134; + public static final int ACTION_ENTER = 135; + + public static final int ACTION_INCREASE_RATING = 136; + public static final int ACTION_DECREASE_RATING = 137; + + public static final int ACTION_NEXT_SCENE = 138; // switch to next scene/cutpoint in movie + public static final int ACTION_PREV_SCENE = 139; // switch to previous scene/cutpoint in movie + + public static final int ACTION_NEXT_LETTER = 140; // jump through a list or container by letter + public static final int ACTION_PREV_LETTER = 141; + + public static final int ACTION_JUMP_SMS2 = 142; // jump direct to a particular letter using SMS-style input + public static final int ACTION_JUMP_SMS3 = 143; + public static final int ACTION_JUMP_SMS4 = 144; + public static final int ACTION_JUMP_SMS5 = 145; + public static final int ACTION_JUMP_SMS6 = 146; + public static final int ACTION_JUMP_SMS7 = 147; + public static final int ACTION_JUMP_SMS8 = 148; + public static final int ACTION_JUMP_SMS9 = 149; + + public static final int ACTION_FILTER_CLEAR = 150; + public static final int ACTION_FILTER_SMS2 = 151; + public static final int ACTION_FILTER_SMS3 = 152; + public static final int ACTION_FILTER_SMS4 = 153; + public static final int ACTION_FILTER_SMS5 = 154; + public static final int ACTION_FILTER_SMS6 = 155; + public static final int ACTION_FILTER_SMS7 = 156; + public static final int ACTION_FILTER_SMS8 = 157; + public static final int ACTION_FILTER_SMS9 = 158; + + public static final int ACTION_FIRST_PAGE = 159; + public static final int ACTION_LAST_PAGE = 160; + + public static final int ACTION_AUDIO_DELAY = 161; + public static final int ACTION_SUBTITLE_DELAY = 162; + + public static final int ACTION_PASTE = 180; + public static final int ACTION_NEXT_CONTROL = 181; + public static final int ACTION_PREV_CONTROL = 182; + public static final int ACTION_CHANNEL_SWITCH = 183; + + public static final int ACTION_TOGGLE_FULLSCREEN = 199; // switch 2 desktop resolution + public static final int ACTION_TOGGLE_WATCHED = 200; // Toggle watched status (videos) + public static final int ACTION_SCAN_ITEM = 201; // scan item + public static final int ACTION_TOGGLE_DIGITAL_ANALOG = 202; // switch digital <-> analog + public static final int ACTION_RELOAD_KEYMAPS = 203; // reloads CButtonTranslator's keymaps + public static final int ACTION_GUIPROFILE_BEGIN = 204; // start the GUIControlProfiler running +} \ No newline at end of file diff --git a/src/org/xbmc/api/info/GuiSettings.java b/app/src/main/java/org/xbmc/api/info/GuiSettings.java similarity index 78% rename from src/org/xbmc/api/info/GuiSettings.java rename to app/src/main/java/org/xbmc/api/info/GuiSettings.java index 1f77fb0b..1fc62ee2 100644 --- a/src/org/xbmc/api/info/GuiSettings.java +++ b/app/src/main/java/org/xbmc/api/info/GuiSettings.java @@ -22,33 +22,12 @@ package org.xbmc.api.info; public class GuiSettings { - - public static class Services { - public static final int EVENTSERVER_ENABLED = 1; - public static final int EVENTSERVER_ENABLED_ALL = 2; - public static final int EVENTSERVER_PORT = 3; - - public static final int EVENT_SERVER_INITIAL_DELAY = 795; - public static final int EVENT_SERVER_CONTINUOUS_DELAY = 796; - - private static final String NAME_PREFIX = "services."; - - } - - public static class MusicLibrary { - - public static final int LIBARY_ENABLED = 418; - public static final int SHOW_COMPLATION_ARTISTS = 13414; - - private static final String NAME_PREFIX = "musiclibrary."; - - } public static String getName(int name) { switch (name) { - case MusicLibrary.LIBARY_ENABLED: + case MusicLibrary.LIBARY_ENABLED: return MusicLibrary.NAME_PREFIX + "enabled"; - case MusicLibrary.SHOW_COMPLATION_ARTISTS: + case MusicLibrary.SHOW_COMPLATION_ARTISTS: return MusicLibrary.NAME_PREFIX + "showcompilationartists"; case Services.EVENTSERVER_ENABLED: return Services.NAME_PREFIX + "esenabled"; @@ -56,53 +35,74 @@ public static String getName(int name) { return Services.NAME_PREFIX + "esallinterfaces"; case Services.EVENTSERVER_PORT: return Services.NAME_PREFIX + "esport"; - case Services.EVENT_SERVER_INITIAL_DELAY: + case Services.EVENT_SERVER_INITIAL_DELAY: return Services.NAME_PREFIX + "esinitialdelay"; - case Services.EVENT_SERVER_CONTINUOUS_DELAY: + case Services.EVENT_SERVER_CONTINUOUS_DELAY: return Services.NAME_PREFIX + "escontinuousdelay"; } return null; } - + public static String getType(int name) { switch (name) { // boolean - case MusicLibrary.LIBARY_ENABLED: + case MusicLibrary.LIBARY_ENABLED: case MusicLibrary.SHOW_COMPLATION_ARTISTS: case Services.EVENTSERVER_ENABLED: case Services.EVENTSERVER_ENABLED_ALL: return "1"; - + // String case Services.EVENTSERVER_PORT: return "3"; - + // int - case Services.EVENT_SERVER_INITIAL_DELAY: + case Services.EVENT_SERVER_INITIAL_DELAY: case Services.EVENT_SERVER_CONTINUOUS_DELAY: return "0"; } return null; } - + public static int getTypeInt(int name) { switch (name) { - // boolean - case MusicLibrary.LIBARY_ENABLED: - case MusicLibrary.SHOW_COMPLATION_ARTISTS: - case Services.EVENTSERVER_ENABLED: - case Services.EVENTSERVER_ENABLED_ALL: - return 1; - - // String - case Services.EVENTSERVER_PORT: - return 3; - - // int - case Services.EVENT_SERVER_INITIAL_DELAY: - case Services.EVENT_SERVER_CONTINUOUS_DELAY: - return 0; + // boolean + case MusicLibrary.LIBARY_ENABLED: + case MusicLibrary.SHOW_COMPLATION_ARTISTS: + case Services.EVENTSERVER_ENABLED: + case Services.EVENTSERVER_ENABLED_ALL: + return 1; + + // String + case Services.EVENTSERVER_PORT: + return 3; + + // int + case Services.EVENT_SERVER_INITIAL_DELAY: + case Services.EVENT_SERVER_CONTINUOUS_DELAY: + return 0; + } + return -1; } - return -1; + + public static class Services { + public static final int EVENTSERVER_ENABLED = 1; + public static final int EVENTSERVER_ENABLED_ALL = 2; + public static final int EVENTSERVER_PORT = 3; + + public static final int EVENT_SERVER_INITIAL_DELAY = 795; + public static final int EVENT_SERVER_CONTINUOUS_DELAY = 796; + + private static final String NAME_PREFIX = "services."; + + } + + public static class MusicLibrary { + + public static final int LIBARY_ENABLED = 418; + public static final int SHOW_COMPLATION_ARTISTS = 13414; + + private static final String NAME_PREFIX = "musiclibrary."; + } } \ No newline at end of file diff --git a/app/src/main/java/org/xbmc/api/info/MusicInfo.java b/app/src/main/java/org/xbmc/api/info/MusicInfo.java new file mode 100644 index 00000000..2078cace --- /dev/null +++ b/app/src/main/java/org/xbmc/api/info/MusicInfo.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +public class MusicInfo { + public static final int MUSICPLAYER_TITLE = 200; + public static final int MUSICPLAYER_ALBUM = 201; + public static final int MUSICPLAYER_ARTIST = 202; + public static final int MUSICPLAYER_GENRE = 203; + public static final int MUSICPLAYER_YEAR = 204; + public static final int MUSICPLAYER_DURATION = 205; + public static final int MUSICPLAYER_TRACK_NUMBER = 208; + public static final int MUSICPLAYER_COVER = 210; + public static final int MUSICPLAYER_BITRATE = 211; + public static final int MUSICPLAYER_PLAYLISTLEN = 212; + public static final int MUSICPLAYER_PLAYLISTPOS = 213; + public static final int MUSICPLAYER_CHANNELS = 214; + public static final int MUSICPLAYER_BITSPERSAMPLE = 215; + public static final int MUSICPLAYER_SAMPLERATE = 216; + public static final int MUSICPLAYER_CODEC = 217; + public static final int MUSICPLAYER_DISC_NUMBER = 218; + public static final int MUSICPLAYER_RATING = 219; + public static final int MUSICPLAYER_COMMENT = 220; + public static final int MUSICPLAYER_LYRICS = 221; + public static final int MUSICPLAYER_HASPREVIOUS = 222; + public static final int MUSICPLAYER_HASNEXT = 223; + public static final int MUSICPLAYER_EXISTS = 224; + public static final int MUSICPLAYER_PLAYLISTPLAYING = 225; +} \ No newline at end of file diff --git a/src/org/xbmc/api/info/PlayStatus.java b/app/src/main/java/org/xbmc/api/info/PlayStatus.java similarity index 92% rename from src/org/xbmc/api/info/PlayStatus.java rename to app/src/main/java/org/xbmc/api/info/PlayStatus.java index c727af3a..979235cc 100644 --- a/src/org/xbmc/api/info/PlayStatus.java +++ b/app/src/main/java/org/xbmc/api/info/PlayStatus.java @@ -1,49 +1,49 @@ -/* -$ * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.info; - -/** - * Describes a play status, which can be: - *
    - *
  • Stopped
  • - *
  • Paused
  • - *
  • Playing
  • - *
- * - * @author Team XBMC - */ -public abstract class PlayStatus { - public static final int UNKNOWN = -1; - public static final int STOPPED = 2; - public static final int PAUSED = 0; - public static final int PLAYING = 1; - - public static int parse(String response) { - if (response.contains("PlayStatus:Paused") || response.equals("Paused")) { - return PlayStatus.PAUSED; - } else if (response.contains("PlayStatus:Playing") || response.equals("Playing")) { - return PlayStatus.PLAYING; - } else { - return PlayStatus.STOPPED; - } - } +/* +$ * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +/** + * Describes a play status, which can be: + *
    + *
  • Stopped
  • + *
  • Paused
  • + *
  • Playing
  • + *
+ * + * @author Team XBMC + */ +public abstract class PlayStatus { + public static final int UNKNOWN = -1; + public static final int STOPPED = 2; + public static final int PAUSED = 0; + public static final int PLAYING = 1; + + public static int parse(String response) { + if (response.contains("PlayStatus:Paused") || response.equals("Paused")) { + return PlayStatus.PAUSED; + } else if (response.contains("PlayStatus:Playing") || response.equals("Playing")) { + return PlayStatus.PLAYING; + } else { + return PlayStatus.STOPPED; + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/xbmc/api/info/SystemInfo.java b/app/src/main/java/org/xbmc/api/info/SystemInfo.java new file mode 100644 index 00000000..2196afd4 --- /dev/null +++ b/app/src/main/java/org/xbmc/api/info/SystemInfo.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +public class SystemInfo { + public static final int SYSTEM_TEMPERATURE_UNITS = 106; + public static final int SYSTEM_PROGRESS_BAR = 107; + public static final int SYSTEM_LANGUAGE = 108; + public static final int SYSTEM_TIME = 110; + public static final int SYSTEM_DATE = 111; + public static final int SYSTEM_CPU_TEMPERATURE = 112; + public static final int SYSTEM_GPU_TEMPERATURE = 113; + public static final int SYSTEM_FAN_SPEED = 114; + public static final int SYSTEM_FREE_SPACE_C = 115; + // public static final int SYSTEM_FREE_SPACE_D = 116; // 116 is reserved for space on D + public static final int SYSTEM_FREE_SPACE_E = 117; + public static final int SYSTEM_FREE_SPACE_F = 118; + public static final int SYSTEM_FREE_SPACE_G = 119; + public static final int SYSTEM_BUILD_VERSION = 120; + public static final int SYSTEM_BUILD_DATE = 121; + public static final int SYSTEM_ETHERNET_LINK_ACTIVE = 122; + public static final int SYSTEM_FPS = 123; + public static final int SYSTEM_ALWAYS_TRUE = 125; // useful for true, + // to fade in a control + public static final int SYSTEM_ALWAYS_FALSE = 126; // used for false, + // to fade out a control (ie not particularly useful!) + public static final int SYSTEM_MEDIA_DVD = 127; + public static final int SYSTEM_DVDREADY = 128; + public static final int SYSTEM_HAS_ALARM = 129; + public static final int SYSTEM_SCREEN_MODE = 132; + public static final int SYSTEM_SCREEN_WIDTH = 133; + public static final int SYSTEM_SCREEN_HEIGHT = 134; + public static final int SYSTEM_CURRENT_WINDOW = 135; + public static final int SYSTEM_CURRENT_CONTROL = 136; + public static final int SYSTEM_DVD_LABEL = 138; + public static final int SYSTEM_HAS_DRIVE_F = 139; + public static final int SYSTEM_HASLOCKS = 140; + public static final int SYSTEM_ISMASTER = 141; + public static final int SYSTEM_TRAYOPEN = 142; + public static final int SYSTEM_ALARM_POS = 144; + public static final int SYSTEM_LOGGEDON = 145; + public static final int SYSTEM_PROFILENAME = 146; + public static final int SYSTEM_PROFILETHUMB = 147; + public static final int SYSTEM_HAS_LOGINSCREEN = 148; + public static final int SYSTEM_HAS_DRIVE_G = 149; + public static final int SYSTEM_HDD_SMART = 150; + public static final int SYSTEM_HDD_TEMPERATURE = 151; + public static final int SYSTEM_HDD_MODEL = 152; + public static final int SYSTEM_HDD_SERIAL = 153; + public static final int SYSTEM_HDD_FIRMWARE = 154; + public static final int SYSTEM_HDD_PASSWORD = 156; + public static final int SYSTEM_HDD_LOCKSTATE = 157; + public static final int SYSTEM_HDD_LOCKKEY = 158; + public static final int SYSTEM_INTERNET_STATE = 159; + public static final int NETWORK_MAC_ADDRESS = 191; +} diff --git a/app/src/main/java/org/xbmc/api/info/VideoInfo.java b/app/src/main/java/org/xbmc/api/info/VideoInfo.java new file mode 100644 index 00000000..cdb60df9 --- /dev/null +++ b/app/src/main/java/org/xbmc/api/info/VideoInfo.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.info; + +public class VideoInfo { + public static final int VIDEOPLAYER_TITLE = 250; + public static final int VIDEOPLAYER_GENRE = 251; + public static final int VIDEOPLAYER_DIRECTOR = 252; + public static final int VIDEOPLAYER_YEAR = 253; + public static final int VIDEOPLAYER_COVER = 258; + public static final int VIDEOPLAYER_USING_OVERLAYS = 259; + public static final int VIDEOPLAYER_ISFULLSCREEN = 260; + public static final int VIDEOPLAYER_HASMENU = 261; + public static final int VIDEOPLAYER_PLAYLISTLEN = 262; + public static final int VIDEOPLAYER_PLAYLISTPOS = 263; + public static final int VIDEOPLAYER_EVENT = 264; + public static final int VIDEOPLAYER_ORIGINALTITLE = 265; + public static final int VIDEOPLAYER_PLOT = 266; + public static final int VIDEOPLAYER_PLOT_OUTLINE = 267; + public static final int VIDEOPLAYER_EPISODE = 268; + public static final int VIDEOPLAYER_SEASON = 269; + public static final int VIDEOPLAYER_RATING = 270; + public static final int VIDEOPLAYER_TVSHOW = 271; + public static final int VIDEOPLAYER_PREMIERED = 272; + public static final int VIDEOPLAYER_CONTENT = 273; + public static final int VIDEOPLAYER_STUDIO = 274; + public static final int VIDEOPLAYER_MPAA = 275; + public static final int VIDEOPLAYER_CAST = 276; + public static final int VIDEOPLAYER_CAST_AND_ROLE = 277; + public static final int VIDEOPLAYER_ARTIST = 278; + public static final int VIDEOPLAYER_ALBUM = 279; + public static final int VIDEOPLAYER_WRITER = 280; + public static final int VIDEOPLAYER_TAGLINE = 281; + public static final int VIDEOPLAYER_HAS_INFO = 282; + public static final int VIDEOPLAYER_TOP250 = 283; + public static final int VIDEOPLAYER_RATING_AND_VOTES = 284; + public static final int VIDEOPLAYER_TRAILER = 285; + public static final int VIDEOPLAYER_VIDEO_CODEC = 286; + public static final int VIDEOPLAYER_VIDEO_RESOLUTION = 287; + public static final int VIDEOPLAYER_AUDIO_CODEC = 288; + public static final int VIDEOPLAYER_AUDIO_CHANNELS = 289; +} \ No newline at end of file diff --git a/src/org/xbmc/api/object/Actor.java b/app/src/main/java/org/xbmc/api/object/Actor.java similarity index 99% rename from src/org/xbmc/api/object/Actor.java rename to app/src/main/java/org/xbmc/api/object/Actor.java index f66b683e..bc3d21ee 100644 --- a/src/org/xbmc/api/object/Actor.java +++ b/app/src/main/java/org/xbmc/api/object/Actor.java @@ -26,41 +26,45 @@ /** * Actor is (for now) a rip-off of artist. It's the same thing named differently for movies. - * + * * @author Team XBMC */ public class Actor extends Artist { - + public final static String THUMB_PREFIX = "special://profile/Thumbnails/"; + private static final long serialVersionUID = -7026393902334967838L; + public String role = null; public Actor(int id, String name, String artUrl) { super(id, name, artUrl); } - + public Actor(int id, String name, String artUrl, String role) { super(id, name, artUrl); this.role = role; } - + + public static String getThumbUri(ICoverArt cover) { + final String hex = Crc32.formatAsHexLowerCase(cover.getCrc()); + return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".tbn"; + } + /** * Composes the complete path to the artist's thumbnail + * * @return Path to thumbnail */ public String getThumbUri() { return getThumbUri(this); } - - public static String getThumbUri(ICoverArt cover) { - final String hex = Crc32.formatAsHexLowerCase(cover.getCrc()); - return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".tbn"; - } - + public int getMediaType() { return MediaType.VIDEO; } - + /** * Returns the CRC of the artist on which the thumb name is based upon. + * * @return 8-char CRC32 */ public long getCrc() { @@ -69,8 +73,4 @@ public long getCrc() { } return thumbID; } - - public String role = null; - - private static final long serialVersionUID = -7026393902334967838L; } \ No newline at end of file diff --git a/src/org/xbmc/api/object/Album.java b/app/src/main/java/org/xbmc/api/object/Album.java similarity index 90% rename from src/org/xbmc/api/object/Album.java rename to app/src/main/java/org/xbmc/api/object/Album.java index 5e13adb6..184455ee 100644 --- a/src/org/xbmc/api/object/Album.java +++ b/app/src/main/java/org/xbmc/api/object/Album.java @@ -21,15 +21,15 @@ package org.xbmc.api.object; -import java.io.Serializable; - import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.io.Serializable; + /** * The album class keeps the basic album information from the album table * as well some of the extended info from the albuminfo table. - * + * * @author freezy */ public class Album implements ICoverArt, Serializable, INamedResource { @@ -38,13 +38,52 @@ public class Album implements ICoverArt, Serializable, INamedResource { * Points to where the album thumbs are stored */ public final static String THUMB_PREFIX = "special://profile/Thumbnails/"; + private static final long serialVersionUID = 4779827915067184250L; + /** + * Database ID + */ + public int id; + /** + * Album name + */ + public String name; + /** + * Artist name + */ + public String artist; + /** + * Year published + */ + public int year = -1; + public String thumbPath; + /** + * Local path of the album + */ + public String localPath; + /** + * Rating + */ + public int rating = -1; + /** + * Genres, separated by " / " + */ + public String genres = null; + /** + * Music label + */ + public String label = null; + /** + * Save this once it's calculated + */ + public long thumbID = 0; /** * Constructor - * @param id Database ID - * @param name Album name - * @param artist Artist - * @param year Year + * + * @param id Database ID + * @param name Album name + * @param artist Artist + * @param year Year */ public Album(int id, String name, String artist, int year) { this.id = id; @@ -67,7 +106,21 @@ public Album(int id, String name, String artist, int year, String thumbPath) { } } } - + + public static String getThumbUri(ICoverArt cover) { + return cover.getThumbUrl(); + } + + public static String getFallbackThumbUri(ICoverArt cover) { + final int crc = cover.getFallbackCrc(); + if (crc != 0) { + final String hex = Crc32.formatAsHexLowerCase(crc); + return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".tbn"; + } else { + return null; + } + } + public int getMediaType() { return MediaType.MUSIC; } @@ -75,44 +128,33 @@ public int getMediaType() { public String getShortName() { return this.name; } - + /** * Composes the complete path to the album's thumbnail + * * @return Path to thumbnail */ public String getThumbUri() { return getThumbUri(this); } - - public static String getThumbUri(ICoverArt cover) { - return cover.getThumbUrl(); - } - - public static String getFallbackThumbUri(ICoverArt cover) { - final int crc = cover.getFallbackCrc(); - if (crc != 0) { - final String hex = Crc32.formatAsHexLowerCase(crc); - return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".tbn"; - } else { - return null; - } - } - + public String getThumbUrl() { return thumbPath; } - + /** * Returns the CRC of the album on which the thumb name is based upon. + * * @return CRC32 */ public long getCrc() { return thumbID; } - + /** * If no album thumb CRC is found, try to get the thumb of the album's * directory. + * * @return 0-char CRC32 */ public int getFallbackCrc() { @@ -123,42 +165,46 @@ public int getFallbackCrc() { return 0; } } - + /** * Returns database ID. + * * @return */ public int getId() { return this.id; } - + /** * Returns database ID. + * * @return */ public String getName() { return toString(); } - + /** * Returns local path name + * * @return */ public String getPath() { return localPath; } - + /** - * Returns true if the album is a compilation, false otherwise. + * Returns true if the album is a compilation, false otherwise. + * * @return True if compilation ("Various Artists"), false otherwise. */ public boolean isVA() { - return artist.equalsIgnoreCase("Various Artists") - || artist.equalsIgnoreCase("VariousArtists") - || artist.equalsIgnoreCase("VA") - || artist.equalsIgnoreCase("V A") - || artist.equalsIgnoreCase("V.A.") - || artist.equalsIgnoreCase("V. A."); + return artist.equalsIgnoreCase("Various Artists") + || artist.equalsIgnoreCase("VariousArtists") + || artist.equalsIgnoreCase("VA") + || artist.equalsIgnoreCase("V A") + || artist.equalsIgnoreCase("V.A.") + || artist.equalsIgnoreCase("V. A."); } /** @@ -167,47 +213,5 @@ public boolean isVA() { public String toString() { return "[" + this.id + "] " + this.name + " (" + this.artist + ")"; } - - /** - * Database ID - */ - public int id; - /** - * Album name - */ - public String name; - /** - * Artist name - */ - public String artist; - /** - * Year published - */ - public int year = -1; - - public String thumbPath; - /** - * Local path of the album - */ - public String localPath; - - /** - * Rating - */ - public int rating = -1; - /** - * Genres, separated by " / " - */ - public String genres = null; - /** - * Music label - */ - public String label = null; - /** - * Save this once it's calculated - */ - public long thumbID = 0; - - private static final long serialVersionUID = 4779827915067184250L; } diff --git a/src/org/xbmc/api/object/Artist.java b/app/src/main/java/org/xbmc/api/object/Artist.java similarity index 96% rename from src/org/xbmc/api/object/Artist.java rename to app/src/main/java/org/xbmc/api/object/Artist.java index d7413723..b3fe7806 100644 --- a/src/org/xbmc/api/object/Artist.java +++ b/app/src/main/java/org/xbmc/api/object/Artist.java @@ -21,13 +21,14 @@ package org.xbmc.api.object; -import java.io.Serializable; import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.io.Serializable; + /** * Not very much going on, artist is basically a name. - * + * * @author Team XBMC */ public class Artist implements ICoverArt, Serializable, INamedResource { @@ -37,18 +38,62 @@ public class Artist implements ICoverArt, Serializable, INamedResource { * Points to where the artist thumbs are stored */ public final static String THUMB_PREFIX = "special://profile/Thumbnails/"; + private static final long serialVersionUID = 9073064679039418773L; + /** + * Database ID + */ + public int id; + /** + * Artist name + */ + public String name; + /** + * Born + */ + public String born = null; + /** + * Formed + */ + public String formed = null; + /** + * Genres, separated by " / " + */ + public String genres = null; + /** + * Moods + */ + public String moods = null; + /** + * Styles + */ + public String styles = null; + /** + * Biography + */ + public String biography = null; + public String arturl = null; + public long thumbID = 0; /** * Constructor - * @param id Database ID - * @param name Artist name + * + * @param id Database ID + * @param name Artist name */ public Artist(int id, String name, String arturl) { this.id = id; this.name = name; this.arturl = arturl; } - + + public static String getThumbUri(ICoverArt cover) { + return cover.getThumbUrl(); + } + + public static String getFallbackThumbUri(ICoverArt cover) { + return null; + } + public int getMediaType() { return MediaType.MUSIC; } @@ -56,29 +101,23 @@ public int getMediaType() { public String getShortName() { return this.name; } - + /** * Composes the complete path to the artist's thumbnail + * * @return Path to thumbnail */ public String getThumbUri() { return getThumbUri(this); } - - public static String getThumbUri(ICoverArt cover) { - return cover.getThumbUrl(); - } - - public static String getFallbackThumbUri(ICoverArt cover) { - return null; - } - - public String getThumbUrl(){ + + public String getThumbUrl() { return arturl; } - + /** * Returns the CRC of the artist on which the thumb name is based upon. + * * @return 8-char CRC32 */ public long getCrc() { @@ -94,23 +133,25 @@ public long getCrc() { public int getFallbackCrc() { return 0; } - + /** * Returns database ID. + * * @return */ public int getId() { return id; } - + /** * Returns database ID. + * * @return */ public String getName() { return this.name; } - + /** * Actors/artists don't have no paths */ @@ -118,51 +159,11 @@ public String getPath() { return ""; } - /** * Something descriptive */ public String toString() { return "[" + this.id + "] " + this.name; } - - /** - * Database ID - */ - public int id; - /** - * Artist name - */ - public String name; - /** - * Born - */ - public String born = null; - /** - * Formed - */ - public String formed = null; - /** - * Genres, separated by " / " - */ - public String genres = null; - /** - * Moods - */ - public String moods = null; - /** - * Styles - */ - public String styles = null; - /** - * Biography - */ - public String biography = null; - - public String arturl = null; - - public long thumbID = 0; - - private static final long serialVersionUID = 9073064679039418773L; } diff --git a/src/org/xbmc/api/object/Episode.java b/app/src/main/java/org/xbmc/api/object/Episode.java similarity index 82% rename from src/org/xbmc/api/object/Episode.java rename to app/src/main/java/org/xbmc/api/object/Episode.java index 59031ada..072f324f 100644 --- a/src/org/xbmc/api/object/Episode.java +++ b/app/src/main/java/org/xbmc/api/object/Episode.java @@ -21,30 +21,27 @@ package org.xbmc.api.object; -import java.util.ArrayList; - import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.util.ArrayList; + public class Episode implements ICoverArt { - + public final static String TAG = "Episode"; - + private static final long serialVersionUID = 5317212562013683169L; /** * Database primary key */ public int id; - /** * Local path of this episode (without file name) */ public String localPath; - /** * File name of this episode */ public String fileName; - /** * Title of this episode */ @@ -62,30 +59,26 @@ public class Episode implements ICoverArt { */ public String writer; public String firstAired; - /** * Number of watched, -1 if not set. */ public int numWatched = -1; public String director; public int season; - /** * Number of this episode within the season */ public int episode; - /** * Title of the TV Show */ public String showTitle; - public String artUrl; - public ArrayList actors = null; - + public Episode(int id, String title, String plot, double rating, String writer, String firstAired, - int numWatched, String director, int season, int episode, String localPath, String fileName, String showTitle, String artUrl) { + int numWatched, String director, int season, int episode, String localPath, String fileName, + String showTitle, String artUrl) { this.id = id; this.title = title; this.plot = plot; @@ -101,21 +94,21 @@ public Episode(int id, String title, String plot, double rating, String writer, this.fileName = fileName; this.artUrl = artUrl; } - - public String getThumbUrl(){ + + public String getThumbUrl() { return artUrl; } public long getCrc() { - return Crc32.computeLowerCase(artUrl); + return Crc32.computeLowerCase(artUrl); } /** * Returns CRC for episode thumb. From FileItem.cpp(2597): *
 	 * 	CStdString strCRC;
-	 *	strCRC.Format("%sepisode%i",GetVideoInfoTag()->m_strFileNameAndPath.c_str(),GetVideoInfoTag()->m_iEpisode);
-	 *	return GetCachedThumb(strCRC,g_settings.GetVideoThumbFolder(),true);
+	 * 	strCRC.Format("%sepisode%i",GetVideoInfoTag()->m_strFileNameAndPath.c_str(),GetVideoInfoTag()->m_iEpisode);
+	 * 	return GetCachedThumb(strCRC,g_settings.GetVideoThumbFolder(),true);
 	 * 
*/ public int getFallbackCrc() { @@ -131,7 +124,7 @@ public int getMediaType() { } public String getName() { - if(season == 0) + if (season == 0) return "Special " + episode + ": " + title; else return season + "x" + episode + ": " + title; @@ -139,16 +132,15 @@ public String getName() { /** * Returns the path XBMC needs to play the episode. This can either - * localPath + filename or filename only (in case of stacks) + * localPath + filename or filename only (in case of stacks) + * * @return */ public String getPath() { - if (fileName.contains("://")) { - return fileName; - } - else { - return localPath + fileName; - } + if (fileName.contains("://")) { + return fileName; + } else { + return localPath + fileName; + } } - private static final long serialVersionUID = 5317212562013683169L; } diff --git a/src/org/xbmc/api/object/FileLocation.java b/app/src/main/java/org/xbmc/api/object/FileLocation.java similarity index 93% rename from src/org/xbmc/api/object/FileLocation.java rename to app/src/main/java/org/xbmc/api/object/FileLocation.java index 7252636a..551d1337 100644 --- a/src/org/xbmc/api/object/FileLocation.java +++ b/app/src/main/java/org/xbmc/api/object/FileLocation.java @@ -1,23 +1,24 @@ package org.xbmc.api.object; -import java.net.URLDecoder; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - import org.xbmc.api.info.FileTypes; import org.xbmc.api.type.MediaType; import org.xbmc.httpapi.Connection; +import java.net.URLDecoder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class FileLocation implements INamedResource { - + public String name, path, displayPath; public boolean isDirectory; public boolean isArchive = false; public boolean isMultipath = false; public int mediaType = 0; - + /** * Class constructor with already parsed data + * * @param name Display name * @param path Path incl filename */ @@ -27,23 +28,20 @@ public FileLocation(String name, String path) { isDirectory = path.endsWith("/") || path.endsWith("\\"); isArchive = isDirectory && path.startsWith("rar://") || path.startsWith("zip://"); isMultipath = path.startsWith("multipath://"); - + if (path.contains("://")) { displayPath = name + "/"; // displayPath = URLDecoder.decode(path).replaceAll("\\\\", "/"); } else { displayPath = path.replaceAll("\\\\", "/"); } - + setMediaType(); } - - public String getShortName(){ - return this.name; - } - + /** * Parses name and path from raw line. + * * @param line raw line, either path only or name and path, separated by Connection.VALUE_SEP. */ public FileLocation(String line) { @@ -61,15 +59,15 @@ public FileLocation(String line) { isDirectory = trimmed.endsWith("/"); path = line; if (isDirectory) { - trimmed = trimmed.substring(0, trimmed.lastIndexOf("/")); + trimmed = trimmed.substring(0, trimmed.lastIndexOf("/")); } name = trimmed.substring(trimmed.lastIndexOf("/") + 1); } - + if (path.endsWith(".m3u") || path.endsWith(".pls")) { isDirectory = false; } - + // treat archives specially if (path.startsWith("rar://") || path.startsWith("zip://")) { final String decoded; @@ -82,18 +80,20 @@ public FileLocation(String line) { } name = decoded.substring(decoded.lastIndexOf("/") + 1); displayPath = URLDecoder.decode(path).replaceAll("\\\\", "/"); - - // parse and beautify shoutcast urls + + // parse and beautify shoutcast urls } else if (path.startsWith("shout://")) { displayPath = "Shoutcast"; - Pattern pattern = Pattern.compile(".*shoutcast\\.com[^\\?]+\\?genre=([^\\\\]+).*", Pattern.CASE_INSENSITIVE); + Pattern pattern = Pattern.compile(".*shoutcast\\.com[^\\?]+\\?genre=([^\\\\]+).*", + Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(path); if (matcher.matches()) { name = matcher.group(1); displayPath = "Shoutcast - " + name; path = path.substring(0, path.length() - 1); } else { - pattern = Pattern.compile(".*shoutcast\\.com.*tunein-station\\.pls\\?id=([0-9]+)", Pattern.CASE_INSENSITIVE); + pattern = Pattern.compile(".*shoutcast\\.com.*tunein-station\\.pls\\?id=([0-9]+)", + Pattern.CASE_INSENSITIVE); matcher = pattern.matcher(path); if (matcher.matches()) { name = "Station #" + matcher.group(1); @@ -102,8 +102,8 @@ public FileLocation(String line) { mediaType = MediaType.MUSIC; } } - - // parse and beautify last.fm urls + + // parse and beautify last.fm urls } else if (path.startsWith("lastfm://")) { if (path.equals("lastfm://")) { displayPath = name; @@ -129,13 +129,17 @@ public FileLocation(String line) { displayPath = name + "/"; // displayPath = URLDecoder.decode(path).replaceAll("\\\\", "/"); isMultipath = true; - + } else { displayPath = path.replaceAll("\\\\", "/"); } setMediaType(); } - + + public String getShortName() { + return this.name; + } + private void setMediaType() { final String ext = path.substring(path.lastIndexOf(".") + 1).toLowerCase(); if (FileTypes.isAudioOrPlaylist(ext)) { @@ -144,6 +148,6 @@ private void setMediaType() { this.mediaType = MediaType.VIDEO; } else if (FileTypes.isPicture(ext)) { this.mediaType = MediaType.PICTURES; - } + } } } \ No newline at end of file diff --git a/src/org/xbmc/api/object/Genre.java b/app/src/main/java/org/xbmc/api/object/Genre.java similarity index 94% rename from src/org/xbmc/api/object/Genre.java rename to app/src/main/java/org/xbmc/api/object/Genre.java index 07d4cf43..deb1898e 100644 --- a/src/org/xbmc/api/object/Genre.java +++ b/app/src/main/java/org/xbmc/api/object/Genre.java @@ -24,19 +24,28 @@ import java.io.Serializable; - /** * Genre is basically a name and an ID. Can be a music genre or a movie/tvshow genre. - * + * * @author Team XBMC */ public class Genre implements Serializable, INamedResource { + private static final long serialVersionUID = 9073064679039418773L; + /** + * Database ID + */ + public int id; + /** + * Genre name + */ + public String name; + /** * Constructor - * @param id Database ID - * @param name Album name - * @param artist Artist + * + * @param id Database ID + * @param name Album name */ public Genre(int id, String name) { this.id = id; @@ -45,6 +54,7 @@ public Genre(int id, String name) { /** * Returns database ID. + * * @return */ public int getId() { @@ -57,19 +67,8 @@ public int getId() { public String toString() { return "[" + this.id + "] " + this.name; } - - /** - * Database ID - */ - public int id; - /** - * Genre name - */ - public String name; - + public String getShortName() { return this.name; } - - private static final long serialVersionUID = 9073064679039418773L; } diff --git a/src/org/xbmc/api/object/Host.java b/app/src/main/java/org/xbmc/api/object/Host.java similarity index 95% rename from src/org/xbmc/api/object/Host.java rename to app/src/main/java/org/xbmc/api/object/Host.java index 7349f5d9..403838d6 100644 --- a/src/org/xbmc/api/object/Host.java +++ b/app/src/main/java/org/xbmc/api/object/Host.java @@ -1,133 +1,130 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.object; - -import java.io.Serializable; - -import org.json.JSONException; -import org.json.JSONObject; - -import android.util.Log; - -/** - * Just a data container for connection data of an XBMC instance - * - * @author Team XBMC - */ -public class Host implements Serializable { - private static final String TAG = "Host"; - - public static final int DEFAULT_HTTP_PORT = 8080; - public static final int DEFAULT_EVENTSERVER_PORT = 9777; - public static final int DEFAULT_TIMEOUT = 5000; - public static final int DEFAULT_WOL_WAIT = 40; - public static final int DEFAULT_WOL_PORT = 9; - - /** - * Database ID - */ - public int id; - /** - * Name (description/label) of the host - */ - public String name; - /** - * IP address or host name of the host - */ - public String addr; - /** - * HTTP API Port - */ - public int port = DEFAULT_HTTP_PORT; - /** - * User name of in case of HTTP authentication - */ - public String user; - /** - * Password of in case of HTTP authentication - */ - public String pass; - /** - * Event server port - */ - public int esPort = DEFAULT_EVENTSERVER_PORT; - /** - * TCP socket read timeout in milliseconds - */ - public int timeout = DEFAULT_TIMEOUT; - /** - * If this host is only available through wifi - */ - public boolean wifi_only = false; - /** - * If wifi only is true there might be an access point specified to connect to - */ - public String access_point; - /** - * The MAC address of this host - */ - public String mac_addr; - /** - * The time to wait after sending WOL - */ - public int wol_wait = DEFAULT_WOL_WAIT; - /** - * The port to send the WOL to - */ - public int wol_port = DEFAULT_WOL_PORT; - - /** - * Something readable - */ - public String toString() { - return addr + ":" + port; - } - - public String getSummary() { - return toString(); - } - - public String toJson() { - try { - JSONObject json = new JSONObject(); - json.put("name", name); - json.put("addr", addr); - json.put("port", port); - json.put("user", user); - json.put("pass", pass); - json.put("esPort", esPort); - json.put("timeout", timeout); - json.put("wifi_only", wifi_only); - json.put("access_point", access_point); - json.put("mac_addr", mac_addr); - json.put("wol_wait", wol_wait); - json.put("wol_port", wol_port); - return json.toString(); - } catch (JSONException e) { - Log.e(TAG, "Error in toJson", e); - return ""; - } - } - - private static final long serialVersionUID = 7886482294339161092L; - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.object; + +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.Serializable; + +/** + * Just a data container for connection data of an XBMC instance + * + * @author Team XBMC + */ +public class Host implements Serializable { + public static final int DEFAULT_HTTP_PORT = 8080; + /** + * HTTP API Port + */ + public int port = DEFAULT_HTTP_PORT; + public static final int DEFAULT_EVENTSERVER_PORT = 9777; + /** + * Event server port + */ + public int esPort = DEFAULT_EVENTSERVER_PORT; + public static final int DEFAULT_TIMEOUT = 5000; + /** + * TCP socket read timeout in milliseconds + */ + public int timeout = DEFAULT_TIMEOUT; + public static final int DEFAULT_WOL_WAIT = 40; + /** + * The time to wait after sending WOL + */ + public int wol_wait = DEFAULT_WOL_WAIT; + public static final int DEFAULT_WOL_PORT = 9; + /** + * The port to send the WOL to + */ + public int wol_port = DEFAULT_WOL_PORT; + private static final String TAG = "Host"; + private static final long serialVersionUID = 7886482294339161092L; + /** + * Database ID + */ + public int id; + /** + * Name (description/label) of the host + */ + public String name; + /** + * IP address or host name of the host + */ + public String addr; + /** + * User name of in case of HTTP authentication + */ + public String user; + /** + * Password of in case of HTTP authentication + */ + public String pass; + /** + * If this host is only available through wifi + */ + public boolean wifi_only = false; + /** + * If wifi only is true there might be an access point specified to connect to + */ + public String access_point; + /** + * The MAC address of this host + */ + public String mac_addr; + + /** + * Something readable + */ + public String toString() { + return addr + ":" + port; + } + + public String getSummary() { + return toString(); + } + + public String toJson() { + try { + JSONObject json = new JSONObject(); + json.put("name", name); + json.put("addr", addr); + json.put("port", port); + json.put("user", user); + json.put("pass", pass); + json.put("esPort", esPort); + json.put("timeout", timeout); + json.put("wifi_only", wifi_only); + json.put("access_point", access_point); + json.put("mac_addr", mac_addr); + json.put("wol_wait", wol_wait); + json.put("wol_port", wol_port); + return json.toString(); + } catch (JSONException e) { + Log.e(TAG, "Error in toJson", e); + return ""; + } + } + } \ No newline at end of file diff --git a/src/org/xbmc/api/object/ICoverArt.java b/app/src/main/java/org/xbmc/api/object/ICoverArt.java similarity index 97% rename from src/org/xbmc/api/object/ICoverArt.java rename to app/src/main/java/org/xbmc/api/object/ICoverArt.java index 71416de1..a060f4f0 100644 --- a/src/org/xbmc/api/object/ICoverArt.java +++ b/app/src/main/java/org/xbmc/api/object/ICoverArt.java @@ -1,34 +1,40 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.object; - -import java.io.Serializable; - -public interface ICoverArt extends Serializable { - public int getId(); - public int getMediaType(); - public int getFallbackCrc(); - public long getCrc(); - public String getPath(); - public String getName(); - public String getThumbUrl(); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.object; + +import java.io.Serializable; + +public interface ICoverArt extends Serializable { + public int getId(); + + public int getMediaType(); + + public int getFallbackCrc(); + + public long getCrc(); + + public String getPath(); + + public String getName(); + + public String getThumbUrl(); } \ No newline at end of file diff --git a/src/org/xbmc/api/object/INamedResource.java b/app/src/main/java/org/xbmc/api/object/INamedResource.java similarity index 100% rename from src/org/xbmc/api/object/INamedResource.java rename to app/src/main/java/org/xbmc/api/object/INamedResource.java diff --git a/src/org/xbmc/api/object/Movie.java b/app/src/main/java/org/xbmc/api/object/Movie.java similarity index 91% rename from src/org/xbmc/api/object/Movie.java rename to app/src/main/java/org/xbmc/api/object/Movie.java index c2963a49..a5dd6098 100644 --- a/src/org/xbmc/api/object/Movie.java +++ b/app/src/main/java/org/xbmc/api/object/Movie.java @@ -21,31 +21,109 @@ package org.xbmc.api.object; -import java.io.Serializable; -import java.util.ArrayList; - import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.io.Serializable; +import java.util.ArrayList; + /** * Stores what we can get from the movieview table. - * + * * @author Team XBMC */ public class Movie implements ICoverArt, Serializable, INamedResource { - + /** * Points to where the movie thumbs are stored */ public final static String THUMB_PREFIX = "special://profile/Thumbnails/"; + private static final long serialVersionUID = 4779827915067184250L; + /** + * Movie title + */ + public final String title; + /** + * Director(s), can be several separated by " / " + */ + public final String director; + /** + * Runtime, can be several also, separated by " | " + */ + public final String runtime; + /** + * Genre(s), can be several, normally separated by " / " + */ + public final String genres; + /** + * Year released, -1 if unknown + */ + public final int year; + /** + * Local path of the movie (without file name) + */ + public final String localPath; + /** + * File name of the movie + */ + public final String filename; + /** + * Number of watched, -1 if not set. + */ + public final int numWatched; + /** + * Database ID + */ + private final int id; + /** + * The movie's imdbId + */ + private final String imdbId; + /** + * Rating + */ + public double rating = 0.0; + /** + * URL to the trailer, if available. + */ + public String trailerUrl = null; + /** + * Movie plot + */ + public String plot = null; + /** + * Movie's tagline + */ + public String tagline = null; + /** + * Number of votes, -1 if not set. + */ + public int numVotes = -1; + /** + * Parental Rating with description (e.g.: "Rated R for strong violence, sexuality, drug use and language.") + */ + public String rated = null; + /** + * Studio + */ + public String studio = null; + /** + * List of actors; + */ + public ArrayList actors = null; + public String artUrl; + /** + * Save this once it's calculated + */ + public long thumbID = 0L; /** * Constructor - * @param id Database ID - * @param name Album name - * @param artist Artist + * + * @param id Database ID */ - public Movie(int id, String title, int year, String path, String filename, String director, String runtime, String genres, double rating, int numWatched, String imdbId, String artUrl) { + public Movie(int id, String title, int year, String path, String filename, String director, String runtime, + String genres, double rating, int numWatched, String imdbId, String artUrl) { this.id = id; this.title = title; this.year = year; @@ -56,17 +134,27 @@ public Movie(int id, String title, int year, String path, String filename, Strin this.localPath = path; this.filename = filename; this.numWatched = numWatched; - this.imdbId=imdbId; - this.artUrl=artUrl; + this.imdbId = imdbId; + this.artUrl = artUrl; + } + + public static String getThumbUri(ICoverArt cover) { + return cover.getThumbUrl(); } - + + public static String getFallbackThumbUri(ICoverArt cover) { + final String hex = Crc32.formatAsHexLowerCase(cover.getCrc()); + return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".jpg"; + } + public int getMediaType() { return MediaType.VIDEO_MOVIE; } - + /** * Returns the path XBMC needs to play the movie. This can either - * localPath + filename or filename only (in case of stacks) + * localPath + filename or filename only (in case of stacks) + * * @return */ public String getPath() { @@ -80,36 +168,30 @@ public String getPath() { public String getShortName() { return this.title; } - + /** * Composes the complete path to the movie's thumbnail + * * @return Path to thumbnail */ public String getThumbUri() { return getThumbUri(this); } - - public static String getThumbUri(ICoverArt cover) { - return cover.getThumbUrl(); - } - - public static String getFallbackThumbUri(ICoverArt cover) { - final String hex = Crc32.formatAsHexLowerCase(cover.getCrc()); - return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".jpg"; - } - + /** * Returns the CRC of the movie on which the thumb name is based upon. + * * @return CRC32 */ public long getCrc() { thumbID = Crc32.computeLowerCase(artUrl); return thumbID; } - + /** * If no album thumb CRC is found, try to get the thumb of the album's * directory. + * * @return 0-char CRC32 */ public int getFallbackCrc() { @@ -119,127 +201,41 @@ public int getFallbackCrc() { return 0; } } - + public String getThumbUrl() { return artUrl; } - + /** * Returns database ID. + * * @return */ public int getId() { return this.id; } - + /** * @return The Movie's IMDbId */ - public String getIMDbId(){ + public String getIMDbId() { return this.imdbId; } - + /** * Returns database ID. + * * @return */ public String getName() { return title + " (" + year + ")"; } - + /** * Something descriptive */ public String toString() { return "[" + id + "] " + title + " (" + year + ")"; } - - /** - * Database ID - */ - private final int id; - /** - * Movie title - */ - public final String title; - /** - * Director(s), can be several separated by " / " - */ - public final String director; - /** - * Runtime, can be several also, separated by " | " - */ - public final String runtime; - /** - * Genre(s), can be several, normally separated by " / " - */ - public final String genres; - /** - * Year released, -1 if unknown - */ - public final int year; - - /** - * Local path of the movie (without file name) - */ - public final String localPath; - - /** - * File name of the movie - */ - public final String filename; - - /** - * Rating - */ - public double rating = 0.0; - - /** - * URL to the trailer, if available. - */ - public String trailerUrl = null; - /** - * Movie plot - */ - public String plot = null; - /** - * Movie's tagline - */ - public String tagline = null; - /** - * Number of votes, -1 if not set. - */ - public int numVotes = -1; - /** - * Parental Rating with description (e.g.: "Rated R for strong violence, sexuality, drug use and language.") - */ - public String rated = null; - /** - * Studio - */ - public String studio = null; - - /** - * Number of watched, -1 if not set. - */ - public final int numWatched; - - /** - * List of actors; - */ - public ArrayList actors = null; - - /** - * The movie's imdbId - */ - private final String imdbId; - - public String artUrl; - /** - * Save this once it's calculated - */ - public long thumbID = 0L; - - private static final long serialVersionUID = 4779827915067184250L; } diff --git a/src/org/xbmc/api/object/Season.java b/app/src/main/java/org/xbmc/api/object/Season.java similarity index 96% rename from src/org/xbmc/api/object/Season.java rename to app/src/main/java/org/xbmc/api/object/Season.java index 799bc2a0..d5bd8e37 100644 --- a/src/org/xbmc/api/object/Season.java +++ b/app/src/main/java/org/xbmc/api/object/Season.java @@ -21,19 +21,19 @@ package org.xbmc.api.object; -import java.io.Serializable; -import java.util.List; - import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.io.Serializable; +import java.util.List; + public class Season implements Serializable, ICoverArt { + private static final long serialVersionUID = -7652780720536304140L; public final int number; public final boolean watched; public final TvShow show; public final String artUrl; - public List episodes = null; public Season(int number, boolean watched, TvShow show, String artUrl) { @@ -43,16 +43,14 @@ public Season(int number, boolean watched, TvShow show, String artUrl) { this.artUrl = artUrl; } - private static final long serialVersionUID = -7652780720536304140L; - - public String getThumbUrl(){ + public String getThumbUrl() { return artUrl; } public long getCrc() { // FileItem.cpp(1185) // BGetCachedThumb("season"+seasonPath+GetLabel(),g_settings.GetVideoThumbFolder(),true); - return Crc32.computeLowerCase(artUrl); + return Crc32.computeLowerCase(artUrl); } public int getFallbackCrc() { diff --git a/src/org/xbmc/api/object/Song.java b/app/src/main/java/org/xbmc/api/object/Song.java similarity index 87% rename from src/org/xbmc/api/object/Song.java rename to app/src/main/java/org/xbmc/api/object/Song.java index f6e349ce..b96f66d0 100644 --- a/src/org/xbmc/api/object/Song.java +++ b/app/src/main/java/org/xbmc/api/object/Song.java @@ -20,32 +20,78 @@ */ package org.xbmc.api.object; -import java.net.URLDecoder; -import java.util.Formatter; import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.net.URLDecoder; +import java.util.Formatter; + /** * The song class contains everything to know about a song. It's basically a * data container with some smallish formatting methods - * + * * @author Team XBMC */ public class Song implements ICoverArt, INamedResource { - + + private static final long serialVersionUID = 911367816075830385L; + /** + * Database ID + */ + public int id; + /** + * Song title + */ + public String title; + /** + * Song artist + */ + public String artist; + /** + * Song album (null if single) + */ + public String album; + /** + * Track number + */ + public int track; + /** + * Disc number + */ + public int disc; + /** + * Song duration in seconds + */ + public int duration; + /** + * Absolute path from XBMC (incl filename) + */ + public String path; + /** + * Filename of song + */ + public String filename; + public String thumbPath; + /** + * CRC of the thumb + */ + public long thumbID = 0; + /** * Constructor - * @param title Song title - * @param artist Song artist - * @param album Song artist - * @param track XBMC track number format (first 2 bytes = disc, last 2 bytes = track) - * @param duration Duration in seconds - * @param path Path to song (without filename) - * @param filename Filename + * + * @param title Song title + * @param artist Song artist + * @param album Song artist + * @param track XBMC track number format (first 2 bytes = disc, last 2 bytes = track) + * @param duration Duration in seconds + * @param path Path to song (without filename) + * @param filename Filename */ - public Song(int id, String title, String artist, String album, int track, int duration, String path, String filename, String thumbPath) { + public Song(int id, String title, String artist, String album, int track, int duration, String path, + String filename, String thumbPath) { this.id = id; this.title = title; this.artist = artist; @@ -64,32 +110,25 @@ public Song(int id, String title, String artist, String album, int track, int du } } } - - /** - * Returns the duration in a nice format ([h:]mm:ss) - * @return Formatted duration - */ - public String getDuration() { - return getDuration(duration); - } - + /** * Returns a formatted string (MM:SS) for a number of seconds. + * * @param d Number of seconds * @return Formatted time */ public static String getDuration(int d) { StringBuilder sb = new StringBuilder(); if (d > 3600) { - sb.append((int)d / 3600); + sb.append((int) d / 3600); sb.append(":"); d %= 3600; } - int min = (int)d / 60; + int min = (int) d / 60; Formatter f = new Formatter(); if (sb.length() > 0) { // sb.append(f.format("%02d", min)); - if(min < 10) + if (min < 10) sb.append(0); sb.append(min); sb.append(":"); @@ -101,6 +140,15 @@ public static String getDuration(int d) { return sb.toString(); } + /** + * Returns the duration in a nice format ([h:]mm:ss) + * + * @return Formatted duration + */ + public String getDuration() { + return getDuration(duration); + } + /** * Something readable */ @@ -110,81 +158,38 @@ public String toString() { /** * Returns the CRC of the song. + * * @return CRC32 */ public long getCrc() { return thumbID; } - + public int getId() { return id; } - + public String getName() { return title; } + public String getPath() { return path; } + public String getShortName() { return getName(); } public int getFallbackCrc() { return 0; - } - + } + public int getMediaType() { return MediaType.MUSIC; } - - public String getThumbUrl(){ + + public String getThumbUrl() { return thumbPath; } - - /** - * Database ID - */ - public int id; - /** - * Song title - */ - public String title; - /** - * Song artist - */ - public String artist; - /** - * Song album (null if single) - */ - public String album; - - /** - * Track number - */ - public int track; - /** - * Disc number - */ - public int disc; - /** - * Song duration in seconds - */ - public int duration; - /** - * Absolute path from XBMC (incl filename) - */ - public String path; - /** - * Filename of song - */ - public String filename; - - public String thumbPath; - /** - * CRC of the thumb - */ - public long thumbID = 0; - - private static final long serialVersionUID = 911367816075830385L; } \ No newline at end of file diff --git a/src/org/xbmc/api/object/TvShow.java b/app/src/main/java/org/xbmc/api/object/TvShow.java similarity index 91% rename from src/org/xbmc/api/object/TvShow.java rename to app/src/main/java/org/xbmc/api/object/TvShow.java index 1533f75f..53ee50c2 100644 --- a/src/org/xbmc/api/object/TvShow.java +++ b/app/src/main/java/org/xbmc/api/object/TvShow.java @@ -1,11 +1,10 @@ package org.xbmc.api.object; -import java.net.URLDecoder; -import java.util.List; - import org.xbmc.android.util.Crc32; import org.xbmc.api.type.MediaType; +import java.util.List; + public class TvShow implements ICoverArt, INamedResource { public final static String TAG = "TvShow"; @@ -13,17 +12,30 @@ public class TvShow implements ICoverArt, INamedResource { * Points to where the movie thumbs are stored */ public final static String THUMB_PREFIX = "special://profile/Thumbnails/"; - + private static final long serialVersionUID = -902152099894950269L; /** * Save this once it's calculated */ public long thumbID = 0L; - public List seasons = null; public List actors = null; - - public TvShow(int id, String title, String summary, double rating, String firstAired, - String genre, String contentRating, String network, String path, int numEpisodes, int watchedEpisodes, boolean watched, String artUrl) { + public int id; + public String title; + public String summary; + public double rating = 0.0; + public String firstAired; + public String contentRating; + public String network; + public String genre; + public String path; + public int numEpisodes; + public int watchedEpisodes; + public boolean watched; + public String artUrl; + + public TvShow(int id, String title, String summary, double rating, String firstAired, + String genre, String contentRating, String network, String path, int numEpisodes, + int watchedEpisodes, boolean watched, String artUrl) { this.id = id; this.title = title; this.summary = summary; @@ -39,22 +51,10 @@ public TvShow(int id, String title, String summary, double rating, String firstA this.artUrl = artUrl; } - public String getShortName() { - return title; - } - - /** - * Composes the complete path to the album's thumbnail - * @return Path to thumbnail - */ - public String getThumbUri() { - return getThumbUri(this); - } - public static String getThumbUri(ICoverArt cover) { return cover.getThumbUrl(); } - + public static String getFallbackThumbUri(ICoverArt cover) { final String hex; if (cover.getMediaType() == MediaType.VIDEO_TVEPISODE) { @@ -65,6 +65,19 @@ public static String getFallbackThumbUri(ICoverArt cover) { return THUMB_PREFIX + hex.charAt(0) + "/" + hex + ".jpg"; } + public String getShortName() { + return title; + } + + /** + * Composes the complete path to the album's thumbnail + * + * @return Path to thumbnail + */ + public String getThumbUri() { + return getThumbUri(this); + } + public long getCrc() { if (thumbID == 0L) { thumbID = Crc32.computeLowerCase(artUrl); @@ -87,15 +100,15 @@ public int getMediaType() { public String getName() { return title; } - + public String getPath() { return path; } - + public String getThumbUrl() { return artUrl; } - + /** * Something descriptive */ @@ -103,20 +116,4 @@ public String toString() { return "[" + id + "] " + title; } - public int id; - public String title; - public String summary; - public double rating = 0.0; - public String firstAired; - public String contentRating; - public String network; - public String genre; - public String path; - public int numEpisodes; - public int watchedEpisodes; - public boolean watched; - public String artUrl; - - private static final long serialVersionUID = -902152099894950269L; - } diff --git a/src/org/xbmc/api/presentation/INotifiableController.java b/app/src/main/java/org/xbmc/api/presentation/INotifiableController.java similarity index 97% rename from src/org/xbmc/api/presentation/INotifiableController.java rename to app/src/main/java/org/xbmc/api/presentation/INotifiableController.java index 4b9dd2c3..1f9b447a 100644 --- a/src/org/xbmc/api/presentation/INotifiableController.java +++ b/app/src/main/java/org/xbmc/api/presentation/INotifiableController.java @@ -1,32 +1,35 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.api.presentation; - -import org.xbmc.android.remote.business.Command; -import org.xbmc.api.business.INotifiableManager; - -public interface INotifiableController { - public void onWrongConnectionState(int state, INotifiableManager manager, Command source); - public void onError(Exception e); - public void onMessage(String message); - public void runOnUI(Runnable action); +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.api.presentation; + +import org.xbmc.android.remote.business.Command; +import org.xbmc.api.business.INotifiableManager; + +public interface INotifiableController { + public void onWrongConnectionState(int state, INotifiableManager manager, Command source); + + public void onError(Exception e); + + public void onMessage(String message); + + public void runOnUI(Runnable action); } \ No newline at end of file diff --git a/src/org/xbmc/api/type/CacheType.java b/app/src/main/java/org/xbmc/api/type/CacheType.java similarity index 99% rename from src/org/xbmc/api/type/CacheType.java rename to app/src/main/java/org/xbmc/api/type/CacheType.java index f1499dd5..d2f557e0 100644 --- a/src/org/xbmc/api/type/CacheType.java +++ b/app/src/main/java/org/xbmc/api/type/CacheType.java @@ -22,9 +22,9 @@ package org.xbmc.api.type; public abstract class CacheType { - + public static final int MEMORY = 1; public static final int SDCARD = 2; public static final int NETWORK = 3; - + } \ No newline at end of file diff --git a/src/org/xbmc/api/type/DirectoryMask.java b/app/src/main/java/org/xbmc/api/type/DirectoryMask.java similarity index 85% rename from src/org/xbmc/api/type/DirectoryMask.java rename to app/src/main/java/org/xbmc/api/type/DirectoryMask.java index 67a9469d..8cf4da2f 100644 --- a/src/org/xbmc/api/type/DirectoryMask.java +++ b/app/src/main/java/org/xbmc/api/type/DirectoryMask.java @@ -27,19 +27,19 @@ public enum DirectoryMask { All, Music, Video; - + public String toString() { switch (this) { - case Directories: - return "*"; - case AllFiles: - return "*.*"; - case Music: - return "music"; - case Video: - return "video"; - default: - return "/"; + case Directories: + return "*"; + case AllFiles: + return "*.*"; + case Music: + return "music"; + case Video: + return "video"; + default: + return "/"; } } } diff --git a/src/org/xbmc/api/type/ListType.java b/app/src/main/java/org/xbmc/api/type/ListType.java similarity index 99% rename from src/org/xbmc/api/type/ListType.java rename to app/src/main/java/org/xbmc/api/type/ListType.java index a616e6fd..c15ee3a5 100644 --- a/src/org/xbmc/api/type/ListType.java +++ b/app/src/main/java/org/xbmc/api/type/ListType.java @@ -28,7 +28,7 @@ public enum ListType { songs, compilations, years; - + public String getSingular() { switch (this) { case genres: diff --git a/src/org/xbmc/api/type/LogType.java b/app/src/main/java/org/xbmc/api/type/LogType.java similarity index 100% rename from src/org/xbmc/api/type/LogType.java rename to app/src/main/java/org/xbmc/api/type/LogType.java diff --git a/src/org/xbmc/api/type/MediaType.java b/app/src/main/java/org/xbmc/api/type/MediaType.java similarity index 89% rename from src/org/xbmc/api/type/MediaType.java rename to app/src/main/java/org/xbmc/api/type/MediaType.java index fee44477..316ebfe2 100644 --- a/src/org/xbmc/api/type/MediaType.java +++ b/app/src/main/java/org/xbmc/api/type/MediaType.java @@ -22,7 +22,7 @@ package org.xbmc.api.type; public abstract class MediaType { - + public static final int UNKNOWN = -1; public static final int MUSIC = 1; public static final int VIDEO = 2; @@ -31,7 +31,7 @@ public abstract class MediaType { public static final int VIDEO_TVSEASON = 23; public static final int VIDEO_TVEPISODE = 24; public static final int PICTURES = 3; - + public static String getName(int type) { switch (type) { case MUSIC: @@ -48,26 +48,27 @@ public static String getName(int type) { return ""; } } - + public static int getPlaylistType(int type) { switch (type) { - case MUSIC: - return 0; - case VIDEO: - case VIDEO_MOVIE: - case VIDEO_TVSHOW: - case VIDEO_TVSEASON: - case VIDEO_TVEPISODE: - return 1; - case PICTURES: - return 2; - default: - return 0; + case MUSIC: + return 0; + case VIDEO: + case VIDEO_MOVIE: + case VIDEO_TVSHOW: + case VIDEO_TVSEASON: + case VIDEO_TVEPISODE: + return 1; + case PICTURES: + return 2; + default: + return 0; } } - + /** * Returns all media types. + * * @return */ public static int[] getTypes() { @@ -77,7 +78,7 @@ public static int[] getTypes() { types[2] = PICTURES; return types; } - + public static String getArtFolder(int type) { switch (type) { case MUSIC: @@ -86,7 +87,7 @@ public static String getArtFolder(int type) { case VIDEO_MOVIE: case VIDEO_TVSHOW: case VIDEO_TVSEASON: - case VIDEO_TVEPISODE: + case VIDEO_TVEPISODE: return "/Video"; case PICTURES: return "/Pictures"; @@ -94,5 +95,5 @@ public static String getArtFolder(int type) { return ""; } } - + } \ No newline at end of file diff --git a/src/org/xbmc/api/type/SeekType.java b/app/src/main/java/org/xbmc/api/type/SeekType.java similarity index 100% rename from src/org/xbmc/api/type/SeekType.java rename to app/src/main/java/org/xbmc/api/type/SeekType.java diff --git a/src/org/xbmc/api/type/SortType.java b/app/src/main/java/org/xbmc/api/type/SortType.java similarity index 99% rename from src/org/xbmc/api/type/SortType.java rename to app/src/main/java/org/xbmc/api/type/SortType.java index 9b985881..24f9b069 100644 --- a/src/org/xbmc/api/type/SortType.java +++ b/app/src/main/java/org/xbmc/api/type/SortType.java @@ -22,10 +22,10 @@ package org.xbmc.api.type; public abstract class SortType { - + public static final String ORDER_ASC = "ASC"; public static final String ORDER_DESC = "DESC"; - + public static final int ALBUM = 1; public static final int ARTIST = 2; public static final int TITLE = 3; @@ -37,6 +37,6 @@ public abstract class SortType { public static final int EPISODE_TITLE = 9; public static final int EPISODE_RATING = 10; public static final int DATE_ADDED = 11; - + public static final int DONT_SORT = -1; } \ No newline at end of file diff --git a/src/org/xbmc/api/type/ThumbSize.java b/app/src/main/java/org/xbmc/api/type/ThumbSize.java similarity index 60% rename from src/org/xbmc/api/type/ThumbSize.java rename to app/src/main/java/org/xbmc/api/type/ThumbSize.java index 8bf41a5d..693ba76e 100644 --- a/src/org/xbmc/api/type/ThumbSize.java +++ b/app/src/main/java/org/xbmc/api/type/ThumbSize.java @@ -26,68 +26,68 @@ /** * Defines a thumb size. Sizes are: *
    - *
  • SMALL
  • - *
  • MEDIUM
  • - *
  • BIG
  • + *
  • SMALL
  • + *
  • MEDIUM
  • + *
  • BIG
  • *
- * + * * @author Team XBMC */ public abstract class ThumbSize { - + public static final double POSTER_AR = 1.4799154334038054968287526427061; public static final double LANDSCAPE_AR = 0.5625; public static final double BANNER_AR = 0.1846965699208443; public static final double FULL_AR = 0.75; - + public static final int SMALL = 1; public static final int MEDIUM = 2; public static final int BIG = 3; public static final int SCREENWIDTH = 4; public static final int SCREENHEIGHT = 5; - + public static final float PIXEL_SCALE = Resources.getSystem().getDisplayMetrics().density; public static float SCREEN_SCALE = 1; - + public static int PIXELS_WIDTH = 0; public static int PIXELS_HEIGHT = 0; - + public static String getDir(int size) { switch (size) { - case SMALL: - return "/small"; - case MEDIUM: - return "/medium"; - case BIG: - return "/original"; - default: - return ""; + case SMALL: + return "/small"; + case MEDIUM: + return "/medium"; + case BIG: + return "/original"; + default: + return ""; } } - + public static void setScreenSize(int width, int height) { PIXELS_WIDTH = width; PIXELS_HEIGHT = height; - SCREEN_SCALE = (((float)(width < height ? width : height)) / PIXEL_SCALE) / (float)320; + SCREEN_SCALE = (((float) (width < height ? width : height)) / PIXEL_SCALE) / (float) 320; } - + public static int getPixel(int size, boolean fixedSize) { return getPixel(size, fixedSize ? 1 : SCREEN_SCALE); } - + public static int getPixel(int size) { return getPixel(size, SCREEN_SCALE); } private static int getPixel(int size, float screenScale) { - + switch (size) { case SMALL: - return (int)(50 * PIXEL_SCALE * screenScale); + return (int) (50 * PIXEL_SCALE * screenScale); case MEDIUM: - return (int)(105 * PIXEL_SCALE * screenScale); + return (int) (105 * PIXEL_SCALE * screenScale); case BIG: - return (int)(400 * PIXEL_SCALE * screenScale); + return (int) (400 * PIXEL_SCALE * screenScale); case SCREENWIDTH: return PIXELS_WIDTH; case SCREENHEIGHT: @@ -96,14 +96,15 @@ private static int getPixel(int size, float screenScale) { return 0; } } - + public static int scale(int pixel) { - return Math.round((float)pixel * PIXEL_SCALE); + return Math.round((float) pixel * PIXEL_SCALE); } - + /** - * Returns target dimensions of a bitmap. These are the dimensions the + * Returns target dimensions of a bitmap. These are the dimensions the * picture will finally be cropped to. + * * @param size Which size * @param mediaType Which media type * @param x Current image width @@ -112,50 +113,55 @@ public static int scale(int pixel) { */ public static Dimension getTargetDimension(int size, int mediaType, int x, int y) { switch (mediaType) { - default: - case MediaType.PICTURES: - case MediaType.MUSIC: // always square - return new Dimension(getPixel(size), getPixel(size)); - case MediaType.VIDEO: - case MediaType.VIDEO_MOVIE: - case MediaType.VIDEO_TVEPISODE: - case MediaType.VIDEO_TVSEASON: - case MediaType.VIDEO_TVSHOW: - final double ar = ((double)x) / ((double)y); - if (ar > 0.95 && ar < 1.05) { // square - return new Dimension(getPixel(size), getPixel(size), Dimension.SQUARE); - } else if (ar < 1) { // portrait - return new Dimension(getPixel(size), (int)(POSTER_AR * getPixel(size)), Dimension.PORTRAIT); - } else if (ar < 1.5) { // landscape 4:3 - return new Dimension((int)((double)getPixel(size) / FULL_AR), getPixel(size), Dimension.LANDSCAPE); - } else if (ar < 2) { // landscape 16:9 - return new Dimension((int)((double)getPixel(size) / LANDSCAPE_AR), getPixel(size), Dimension.LANDSCAPE); - } else if (ar > 5) { // wide banner + default: + case MediaType.PICTURES: + case MediaType.MUSIC: // always square + return new Dimension(getPixel(size), getPixel(size)); + case MediaType.VIDEO: + case MediaType.VIDEO_MOVIE: + case MediaType.VIDEO_TVEPISODE: + case MediaType.VIDEO_TVSEASON: + case MediaType.VIDEO_TVSHOW: + final double ar = ((double) x) / ((double) y); + if (ar > 0.95 && ar < 1.05) { // square + return new Dimension(getPixel(size), getPixel(size), Dimension.SQUARE); + } else if (ar < 1) { // portrait + return new Dimension(getPixel(size), (int) (POSTER_AR * getPixel(size)), Dimension.PORTRAIT); + } else if (ar < 1.5) { // landscape 4:3 + return new Dimension((int) ((double) getPixel(size) / FULL_AR), getPixel(size), + Dimension.LANDSCAPE); + } else if (ar < 2) { // landscape 16:9 + return new Dimension((int) ((double) getPixel(size) / LANDSCAPE_AR), getPixel(size), + Dimension.LANDSCAPE); + } else if (ar > 5) { // wide banner /* special case: * - small: banner width = screen width * - medium: banner width = screen height (for landscape display) * - large: 758x140 (original) - */ - switch (size) { - case ThumbSize.SMALL: - return new Dimension(getPixel(ThumbSize.SCREENWIDTH), (int)((double)getPixel(ThumbSize.SCREENWIDTH) * BANNER_AR), Dimension.BANNER); - case ThumbSize.MEDIUM: - return new Dimension(getPixel(ThumbSize.SCREENHEIGHT), (int)((double)getPixel(ThumbSize.SCREENHEIGHT) * BANNER_AR), Dimension.BANNER); - default: - case ThumbSize.BIG: - return new Dimension(758, 140, Dimension.BANNER); + */ + switch (size) { + case ThumbSize.SMALL: + return new Dimension(getPixel(ThumbSize.SCREENWIDTH), (int) ((double) getPixel(ThumbSize + .SCREENWIDTH) * BANNER_AR), Dimension.BANNER); + case ThumbSize.MEDIUM: + return new Dimension(getPixel(ThumbSize.SCREENHEIGHT), (int) ((double) getPixel(ThumbSize + .SCREENHEIGHT) * BANNER_AR), Dimension.BANNER); + default: + case ThumbSize.BIG: + return new Dimension(758, 140, Dimension.BANNER); + } + } else { // anything weird between wide banner and landscape 16:9 + return new Dimension((int) ((double) getPixel(size) / LANDSCAPE_AR), getPixel(size), + Dimension.UNKNOWN); } - } else { // anything weird between wide banner and landscape 16:9 - return new Dimension((int)((double)getPixel(size) / LANDSCAPE_AR), getPixel(size), Dimension.UNKNOWN); - } } } - + public static int[] values() { - int[] values = { BIG, MEDIUM, SMALL }; + int[] values = {BIG, MEDIUM, SMALL}; return values; } - + public static class Dimension { public static final int UNKNOWN = 0; public static final int PORTRAIT = 1; @@ -163,17 +169,21 @@ public static class Dimension { public static final int LANDSCAPE = 3; public static final int BANNER = 4; public int x, y, format; + Dimension(int x, int y, int format) { this(x, y); this.format = format; } + Dimension(int x, int y) { this.x = x; this.y = y; } + public String toString() { return "(" + x + "x" + y + ")"; } + public boolean equals(Dimension dim) { return dim.x == x && dim.y == y; } diff --git a/src/org/xbmc/eventclient/ButtonCodes.java b/app/src/main/java/org/xbmc/eventclient/ButtonCodes.java similarity index 98% rename from src/org/xbmc/eventclient/ButtonCodes.java rename to app/src/main/java/org/xbmc/eventclient/ButtonCodes.java index ad278aa4..fcd01c5d 100644 --- a/src/org/xbmc/eventclient/ButtonCodes.java +++ b/app/src/main/java/org/xbmc/eventclient/ButtonCodes.java @@ -1,180 +1,180 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.eventclient; - -/** - * Remote control and keyboard strings, taken from xbmc/ButtonTranslator.cpp - * - * @author Team XBMC - */ -public final class ButtonCodes { - - public static final String REMOTE_LEFT = "left"; - public static final String REMOTE_RIGHT = "right"; - public static final String REMOTE_UP = "up"; - public static final String REMOTE_DOWN = "down"; - public static final String REMOTE_SELECT = "select"; - public static final String REMOTE_BACK = "back"; - public static final String REMOTE_MENU = "menu"; - public static final String REMOTE_INFO = "info"; - public static final String REMOTE_DISPLAY = "display"; - public static final String REMOTE_TITLE = "title"; - public static final String REMOTE_PLAY = "play"; - public static final String REMOTE_PAUSE = "pause"; - public static final String REMOTE_REVERSE = "reverse"; - public static final String REMOTE_FORWARD = "forward"; - public static final String REMOTE_SKIP_PLUS = "skipplus"; - public static final String REMOTE_SKIP_MINUS = "skipminus"; - public static final String REMOTE_STOP = "stop"; - public static final String REMOTE_0 = "zero"; - public static final String REMOTE_1 = "one"; - public static final String REMOTE_2 = "two"; - public static final String REMOTE_3 = "three"; - public static final String REMOTE_4 = "four"; - public static final String REMOTE_5 = "five"; - public static final String REMOTE_6 = "six"; - public static final String REMOTE_7 = "seven"; - public static final String REMOTE_8 = "eight"; - public static final String REMOTE_9 = "nine"; - // additional keys from the media center extender for xbox remote - public static final String REMOTE_POWER = "power"; - public static final String REMOTE_MY_TV = "mytv"; - public static final String REMOTE_MY_MUSIC = "mymusic"; - public static final String REMOTE_MY_PICTURES = "mypictures"; - public static final String REMOTE_MY_VIDEOS = "myvideo"; - public static final String REMOTE_RECORD = "record"; - public static final String REMOTE_START = "start"; - public static final String REMOTE_VOLUME_PLUS = "volumeplus"; - public static final String REMOTE_VOLUME_MINUS = "volumeminus"; - public static final String REMOTE_CHANNEL_PLUS = "channelplus"; - public static final String REMOTE_CHANNEL_MINUS = "channelminus"; - public static final String REMOTE_PAGE_PLUS = "pageplus"; - public static final String REMOTE_PAGE_MINUS = "pageminus"; - public static final String REMOTE_MUTE = "mute"; - public static final String REMOTE_RECORDED_TV = "recordedtv"; - public static final String REMOTE_GUIDE = "guide"; - public static final String REMOTE_LIVE_TV = "livetv"; - public static final String REMOTE_STAR = "star"; - public static final String REMOTE_HASH = "hash"; - public static final String REMOTE_CLEAR = "clear"; - public static final String REMOTE_ENTER = "enter"; - public static final String REMOTE_XBOX = "xbox"; - - public static final String KEYBOARD_RETURN = "return"; - public static final String KEYBOARD_ENTER = "enter"; - public static final String KEYBOARD_ESCAPE = "escape"; - public static final String KEYBOARD_ESC = "esc"; - public static final String KEYBOARD_TAB = "tab"; - public static final String KEYBOARD_SPACE = "space"; - public static final String KEYBOARD_LEFT = "left"; - public static final String KEYBOARD_RIGHT = "right"; - public static final String KEYBOARD_UP = "up"; - public static final String KEYBOARD_DOWN = "down"; - public static final String KEYBOARD_INSERT = "insert"; - public static final String KEYBOARD_DELETE = "delete"; - public static final String KEYBOARD_HOME = "home"; - public static final String KEYBOARD_END = "end"; - public static final String KEYBOARD_F1 = "f1"; - public static final String KEYBOARD_F2 = "f2"; - public static final String KEYBOARD_F3 = "f3"; - public static final String KEYBOARD_F4 = "f4"; - public static final String KEYBOARD_F5 = "f5"; - public static final String KEYBOARD_F6 = "f6"; - public static final String KEYBOARD_F7 = "f7"; - public static final String KEYBOARD_F8 = "f8"; - public static final String KEYBOARD_F9 = "f9"; - public static final String KEYBOARD_F10 = "f10"; - public static final String KEYBOARD_F11 = "f11"; - public static final String KEYBOARD_F12 = "f12"; - public static final String KEYBOARD_NUMPAD_ZERO = "numpadzero"; - public static final String KEYBOARD_NUMPAD_1 = "numpadone"; - public static final String KEYBOARD_NUMPAD_2 = "numpadtwo"; - public static final String KEYBOARD_NUMPAD_3 = "numpadthree"; - public static final String KEYBOARD_NUMPAD_4 = "numpadfour"; - public static final String KEYBOARD_NUMPAD_5 = "numpadfive"; - public static final String KEYBOARD_NUMPAD_6 = "numpadsix"; - public static final String KEYBOARD_NUMPAD_7 = "numpadseven"; - public static final String KEYBOARD_NUMPAD_8 = "numpadeight"; - public static final String KEYBOARD_NUMPAD_9 = "numpadnine"; - public static final String KEYBOARD_NUMPAD_TIMES = "numpadtimes"; - public static final String KEYBOARD_NUMPAD_PLUS = "numpadplus"; - public static final String KEYBOARD_NUMPAD_MINUS = "numpadminus"; - public static final String KEYBOARD_NUMPAD_PERIOD = "numpadperiod"; - public static final String KEYBOARD_NUMPAD_DIVIDE = "numpaddivide"; - public static final String KEYBOARD_PAGEUP = "pageup"; - public static final String KEYBOARD_PAGEDOWN = "pagedown"; - public static final String KEYBOARD_PRINTSCREEN = "printscreen"; - public static final String KEYBOARD_BACKSPACE = "backspace"; - public static final String KEYBOARD_MENU = "menu"; - public static final String KEYBOARD_PAUSE = "pause"; - public static final String KEYBOARD_LEFTSHIFT = "leftshift"; - public static final String KEYBOARD_RIGHTSHIFT = "rightshift"; - public static final String KEYBOARD_LEFTCTRL = "leftctrl"; - public static final String KEYBOARD_RIGHTCTRL = "rightctrl"; - public static final String KEYBOARD_LEFTALT = "leftalt"; - public static final String KEYBOARD_RIGHTALT = "rightalt"; - public static final String KEYBOARD_LEFTWINDOWS = "leftwindows"; - public static final String KEYBOARD_RIGHTWINDOWS = "rightwindows"; - public static final String KEYBOARD_CAPSLOCK = "capslock"; - public static final String KEYBOARD_NUMLOCK = "numlock"; - public static final String KEYBOARD_SCROLLLOCK = "scrolllock"; - public static final String KEYBOARD_SEMICOLON = "semicolon"; - public static final String KEYBOARD_COLON = "colon"; - public static final String KEYBOARD_EQUALS = "equals"; - public static final String KEYBOARD_PLUS = "plus"; - public static final String KEYBOARD_COMMA = "comma"; - public static final String KEYBOARD_LESSTHAN = "lessthan"; - public static final String KEYBOARD_MINUS = "minus"; - public static final String KEYBOARD_UNDERLINE = "underline"; - public static final String KEYBOARD_PERIOD = "period"; - public static final String KEYBOARD_GREATERTHAN = "greaterthan"; - public static final String KEYBOARD_FORWARDSLASH = "forwardslash"; - public static final String KEYBOARD_QUESTIONMARK = "questionmark"; - public static final String KEYBOARD_LEFTQUOTE = "leftquote"; - public static final String KEYBOARD_TILDE = "tilde"; - public static final String KEYBOARD_OPENSQUAREBRACKET = "opensquarebracket"; - public static final String KEYBOARD_OPENBRACE = "openbrace"; - public static final String KEYBOARD_BACKSLASH = "backslash"; - public static final String KEYBOARD_PIPE = "pipe"; - public static final String KEYBOARD_CLOSESQUAREBRACKET = "closesquarebracket"; - public static final String KEYBOARD_CLOSEBRACE = "closebrace"; - public static final String KEYBOARD_QUOTE = "quote"; - public static final String KEYBOARD_DOUBLEQUOTE = "doublequote"; - public static final String KEYBOARD_LAUNCH_MAIL = "launch_mail"; - public static final String KEYBOARD_BROWSER_HOME = "browser_home"; - public static final String KEYBOARD_BROWSER_FAVORITES = "browser_favorites"; - public static final String KEYBOARD_BROWSER_REFRESH = "browser_refresh"; - public static final String KEYBOARD_BROWSER_SEARCH = "browser_search"; - public static final String KEYBOARD_LAUNCH_APP1_PC_ICON = "launch_app1_pc_icon"; - public static final String KEYBOARD_LAUNCH_MEDIA_SELECT = "launch_media_select"; - public static final String KEYBOARD_PLAY_PAUSE = "play_pause"; - public static final String KEYBOARD_STOP = "stop"; - public static final String KEYBOARD_VOLUME_UP = "volume_up"; - public static final String KEYBOARD_VOLUME_MUTE = "volume_mute"; - public static final String KEYBOARD_VOLUME_DOWN = "volume_down"; - public static final String KEYBOARD_PREV_TRACK = "prev_track"; - public static final String KEYBOARD_NEXT_TRACK = "next_track"; - - public static final String GAMEPAD_LEFT_ANALOG_TRIGGER = "leftanalogtrigger"; - public static final String GAMEPAD_RIGHT_ANALOG_TRIGGER = "rightanalogtrigger"; - +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.eventclient; + +/** + * Remote control and keyboard strings, taken from xbmc/ButtonTranslator.cpp + * + * @author Team XBMC + */ +public final class ButtonCodes { + + public static final String REMOTE_LEFT = "left"; + public static final String REMOTE_RIGHT = "right"; + public static final String REMOTE_UP = "up"; + public static final String REMOTE_DOWN = "down"; + public static final String REMOTE_SELECT = "select"; + public static final String REMOTE_BACK = "back"; + public static final String REMOTE_MENU = "menu"; + public static final String REMOTE_INFO = "info"; + public static final String REMOTE_DISPLAY = "display"; + public static final String REMOTE_TITLE = "title"; + public static final String REMOTE_PLAY = "play"; + public static final String REMOTE_PAUSE = "pause"; + public static final String REMOTE_REVERSE = "reverse"; + public static final String REMOTE_FORWARD = "forward"; + public static final String REMOTE_SKIP_PLUS = "skipplus"; + public static final String REMOTE_SKIP_MINUS = "skipminus"; + public static final String REMOTE_STOP = "stop"; + public static final String REMOTE_0 = "zero"; + public static final String REMOTE_1 = "one"; + public static final String REMOTE_2 = "two"; + public static final String REMOTE_3 = "three"; + public static final String REMOTE_4 = "four"; + public static final String REMOTE_5 = "five"; + public static final String REMOTE_6 = "six"; + public static final String REMOTE_7 = "seven"; + public static final String REMOTE_8 = "eight"; + public static final String REMOTE_9 = "nine"; + // additional keys from the media center extender for xbox remote + public static final String REMOTE_POWER = "power"; + public static final String REMOTE_MY_TV = "mytv"; + public static final String REMOTE_MY_MUSIC = "mymusic"; + public static final String REMOTE_MY_PICTURES = "mypictures"; + public static final String REMOTE_MY_VIDEOS = "myvideo"; + public static final String REMOTE_RECORD = "record"; + public static final String REMOTE_START = "start"; + public static final String REMOTE_VOLUME_PLUS = "volumeplus"; + public static final String REMOTE_VOLUME_MINUS = "volumeminus"; + public static final String REMOTE_CHANNEL_PLUS = "channelplus"; + public static final String REMOTE_CHANNEL_MINUS = "channelminus"; + public static final String REMOTE_PAGE_PLUS = "pageplus"; + public static final String REMOTE_PAGE_MINUS = "pageminus"; + public static final String REMOTE_MUTE = "mute"; + public static final String REMOTE_RECORDED_TV = "recordedtv"; + public static final String REMOTE_GUIDE = "guide"; + public static final String REMOTE_LIVE_TV = "livetv"; + public static final String REMOTE_STAR = "star"; + public static final String REMOTE_HASH = "hash"; + public static final String REMOTE_CLEAR = "clear"; + public static final String REMOTE_ENTER = "enter"; + public static final String REMOTE_XBOX = "xbox"; + + public static final String KEYBOARD_RETURN = "return"; + public static final String KEYBOARD_ENTER = "enter"; + public static final String KEYBOARD_ESCAPE = "escape"; + public static final String KEYBOARD_ESC = "esc"; + public static final String KEYBOARD_TAB = "tab"; + public static final String KEYBOARD_SPACE = "space"; + public static final String KEYBOARD_LEFT = "left"; + public static final String KEYBOARD_RIGHT = "right"; + public static final String KEYBOARD_UP = "up"; + public static final String KEYBOARD_DOWN = "down"; + public static final String KEYBOARD_INSERT = "insert"; + public static final String KEYBOARD_DELETE = "delete"; + public static final String KEYBOARD_HOME = "home"; + public static final String KEYBOARD_END = "end"; + public static final String KEYBOARD_F1 = "f1"; + public static final String KEYBOARD_F2 = "f2"; + public static final String KEYBOARD_F3 = "f3"; + public static final String KEYBOARD_F4 = "f4"; + public static final String KEYBOARD_F5 = "f5"; + public static final String KEYBOARD_F6 = "f6"; + public static final String KEYBOARD_F7 = "f7"; + public static final String KEYBOARD_F8 = "f8"; + public static final String KEYBOARD_F9 = "f9"; + public static final String KEYBOARD_F10 = "f10"; + public static final String KEYBOARD_F11 = "f11"; + public static final String KEYBOARD_F12 = "f12"; + public static final String KEYBOARD_NUMPAD_ZERO = "numpadzero"; + public static final String KEYBOARD_NUMPAD_1 = "numpadone"; + public static final String KEYBOARD_NUMPAD_2 = "numpadtwo"; + public static final String KEYBOARD_NUMPAD_3 = "numpadthree"; + public static final String KEYBOARD_NUMPAD_4 = "numpadfour"; + public static final String KEYBOARD_NUMPAD_5 = "numpadfive"; + public static final String KEYBOARD_NUMPAD_6 = "numpadsix"; + public static final String KEYBOARD_NUMPAD_7 = "numpadseven"; + public static final String KEYBOARD_NUMPAD_8 = "numpadeight"; + public static final String KEYBOARD_NUMPAD_9 = "numpadnine"; + public static final String KEYBOARD_NUMPAD_TIMES = "numpadtimes"; + public static final String KEYBOARD_NUMPAD_PLUS = "numpadplus"; + public static final String KEYBOARD_NUMPAD_MINUS = "numpadminus"; + public static final String KEYBOARD_NUMPAD_PERIOD = "numpadperiod"; + public static final String KEYBOARD_NUMPAD_DIVIDE = "numpaddivide"; + public static final String KEYBOARD_PAGEUP = "pageup"; + public static final String KEYBOARD_PAGEDOWN = "pagedown"; + public static final String KEYBOARD_PRINTSCREEN = "printscreen"; + public static final String KEYBOARD_BACKSPACE = "backspace"; + public static final String KEYBOARD_MENU = "menu"; + public static final String KEYBOARD_PAUSE = "pause"; + public static final String KEYBOARD_LEFTSHIFT = "leftshift"; + public static final String KEYBOARD_RIGHTSHIFT = "rightshift"; + public static final String KEYBOARD_LEFTCTRL = "leftctrl"; + public static final String KEYBOARD_RIGHTCTRL = "rightctrl"; + public static final String KEYBOARD_LEFTALT = "leftalt"; + public static final String KEYBOARD_RIGHTALT = "rightalt"; + public static final String KEYBOARD_LEFTWINDOWS = "leftwindows"; + public static final String KEYBOARD_RIGHTWINDOWS = "rightwindows"; + public static final String KEYBOARD_CAPSLOCK = "capslock"; + public static final String KEYBOARD_NUMLOCK = "numlock"; + public static final String KEYBOARD_SCROLLLOCK = "scrolllock"; + public static final String KEYBOARD_SEMICOLON = "semicolon"; + public static final String KEYBOARD_COLON = "colon"; + public static final String KEYBOARD_EQUALS = "equals"; + public static final String KEYBOARD_PLUS = "plus"; + public static final String KEYBOARD_COMMA = "comma"; + public static final String KEYBOARD_LESSTHAN = "lessthan"; + public static final String KEYBOARD_MINUS = "minus"; + public static final String KEYBOARD_UNDERLINE = "underline"; + public static final String KEYBOARD_PERIOD = "period"; + public static final String KEYBOARD_GREATERTHAN = "greaterthan"; + public static final String KEYBOARD_FORWARDSLASH = "forwardslash"; + public static final String KEYBOARD_QUESTIONMARK = "questionmark"; + public static final String KEYBOARD_LEFTQUOTE = "leftquote"; + public static final String KEYBOARD_TILDE = "tilde"; + public static final String KEYBOARD_OPENSQUAREBRACKET = "opensquarebracket"; + public static final String KEYBOARD_OPENBRACE = "openbrace"; + public static final String KEYBOARD_BACKSLASH = "backslash"; + public static final String KEYBOARD_PIPE = "pipe"; + public static final String KEYBOARD_CLOSESQUAREBRACKET = "closesquarebracket"; + public static final String KEYBOARD_CLOSEBRACE = "closebrace"; + public static final String KEYBOARD_QUOTE = "quote"; + public static final String KEYBOARD_DOUBLEQUOTE = "doublequote"; + public static final String KEYBOARD_LAUNCH_MAIL = "launch_mail"; + public static final String KEYBOARD_BROWSER_HOME = "browser_home"; + public static final String KEYBOARD_BROWSER_FAVORITES = "browser_favorites"; + public static final String KEYBOARD_BROWSER_REFRESH = "browser_refresh"; + public static final String KEYBOARD_BROWSER_SEARCH = "browser_search"; + public static final String KEYBOARD_LAUNCH_APP1_PC_ICON = "launch_app1_pc_icon"; + public static final String KEYBOARD_LAUNCH_MEDIA_SELECT = "launch_media_select"; + public static final String KEYBOARD_PLAY_PAUSE = "play_pause"; + public static final String KEYBOARD_STOP = "stop"; + public static final String KEYBOARD_VOLUME_UP = "volume_up"; + public static final String KEYBOARD_VOLUME_MUTE = "volume_mute"; + public static final String KEYBOARD_VOLUME_DOWN = "volume_down"; + public static final String KEYBOARD_PREV_TRACK = "prev_track"; + public static final String KEYBOARD_NEXT_TRACK = "next_track"; + + public static final String GAMEPAD_LEFT_ANALOG_TRIGGER = "leftanalogtrigger"; + public static final String GAMEPAD_RIGHT_ANALOG_TRIGGER = "rightanalogtrigger"; + } \ No newline at end of file diff --git a/src/org/xbmc/eventclient/EventClient.java b/app/src/main/java/org/xbmc/eventclient/EventClient.java similarity index 70% rename from src/org/xbmc/eventclient/EventClient.java rename to app/src/main/java/org/xbmc/eventclient/EventClient.java index 35326745..069f56ce 100644 --- a/src/org/xbmc/eventclient/EventClient.java +++ b/app/src/main/java/org/xbmc/eventclient/EventClient.java @@ -1,27 +1,28 @@ package org.xbmc.eventclient; -import java.io.FileInputStream; -import java.io.IOException; -import java.net.InetAddress; +import android.util.Log; import org.xbmc.api.data.IEventClient; -import android.util.Log; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.InetAddress; /** * XBMC Event Client Class - * + *

* Implements an XBMC-Client. This class can be used to implement your own * application which should act as a Input device for XBMC. Also starts a * Ping-Thread, which tells the XBMC EventServer that the client is alive. * Therefore if you close your application you SHOULD call stopClient()! - * + *

* 03.09.2009 freezy changed class name and member variables - * + * * @author Stefan Agner */ public class EventClient implements IEventClient { - + + private static final String TAG = "EventClient"; private final String mDeviceName; private boolean mHasIcon = false; private PingThread mPingThread; @@ -29,9 +30,7 @@ public class EventClient implements IEventClient { private byte[] mIconData; private InetAddress mHostAddress; private int mHostPort; - - private static final String TAG = "EventClient"; - + /** * Creates an empty instance but doesn't start it. */ @@ -42,10 +41,10 @@ public EventClient(String deviceName) { /** * Starts a XBMC EventClient without an icon. - * - * @param hostAddress Address of the Host running XBMC - * @param hostPort Port of the Host running XBMC (default 9777) - * @param deviceName Name of the Device + * + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device * @throws IOException */ public EventClient(InetAddress hostAddress, int hostPort, String deviceName) { @@ -56,11 +55,11 @@ public EventClient(InetAddress hostAddress, int hostPort, String deviceName) { /** * Starts a XBMC EventClient. - * - * @param hostAddress Address of the Host running XBMC - * @param hostPort Port of the Host running XBMC (default 9777) - * @param deviceName Name of the Device - * @param iconFile Path to the Iconfile (PNG, JPEG or GIF) + * + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @param iconFile Path to the Iconfile (PNG, JPEG or GIF) * @throws IOException */ public EventClient(InetAddress hostAddress, int hostPort, String deviceName, String iconFile) { @@ -69,26 +68,27 @@ public EventClient(InetAddress hostAddress, int hostPort, String deviceName, Str setIcon(iconFile); startClient(hostAddress, hostPort); } - + /** * Starts a XBMC EventClient. - * - * @param hostAddress Address of the Host running XBMC - * @param hostPort Port of the Host running XBMC (default 9777) - * @param deviceName Name of the Device - * @param iconType Type of the icon file (see Packet.ICON_PNG, - * Packet.ICON_JPEG or Packet.ICON_GIF) - * @param iconData The icon itself as a Byte-Array + * + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) + * @param deviceName Name of the Device + * @param iconType Type of the icon file (see Packet.ICON_PNG, + * Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon itself as a Byte-Array * @throws IOException */ public EventClient(InetAddress hostAddress, int hostPort, String deviceName, byte iconType, byte[] iconData) { - Log.i(TAG, "EventClient(" + hostAddress + ", " + hostPort + ", " + deviceName + ", " + iconType + ", " + iconData + ")"); + Log.i(TAG, "EventClient(" + hostAddress + ", " + hostPort + ", " + deviceName + ", " + iconType + ", " + + "" + iconData + ")"); mDeviceName = deviceName; setIcon(iconType, iconData); startClient(hostAddress, hostPort); } - + public void setHost(InetAddress addr, int port) { if (addr != null) { Log.e(TAG, "Setting mHostAddress = " + addr.getHostAddress()); @@ -109,9 +109,10 @@ public void setHost(InetAddress addr, int port) { mHostAddress = null; } } - + /** * Sets the icon using a path name to a image file (png, jpg or gif). + * * @param iconPath Path to icon */ public void setIcon(String iconPath) { @@ -139,9 +140,10 @@ public void setIcon(String iconPath) { mHasIcon = true; setIcon(iconType, iconData); } - + /** * Sets the icon from raw data + * * @param iconType Type of the icon file (see Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) * @param iconData The icon itself as a Byte-Array */ @@ -152,13 +154,13 @@ public void setIcon(byte iconType, byte[] iconData) { /** * Starts a XBMC EventClient. - * - * @param hostAddress Address of the Host running XBMC - * @param hostPort Port of the Host running XBMC (default 9777) + * + * @param hostAddress Address of the Host running XBMC + * @param hostPort Port of the Host running XBMC (default 9777) * @throws IOException */ private void startClient(InetAddress hostAddress, int hostPort) { - + Log.i(TAG, "Starting new EventClient at " + hostAddress + ":" + hostPort); // Save host address and port @@ -181,7 +183,7 @@ private void startClient(InetAddress hostAddress, int hostPort) { /** * Stops the XBMC EventClient (especially the Ping-Thread) - * + * * @throws IOException */ public void stopClient() throws IOException { @@ -190,18 +192,18 @@ public void stopClient() throws IOException { // Stop Ping-Thread... mPingThread.giveup(); mPingThread.interrupt(); - + PacketBYE p = new PacketBYE(); p.send(mHostAddress, mHostPort); } } - + /** * Displays a notification window in XBMC. - * - * @param title Message title - * @param message The actual message + * + * @param title Message title + * @param message The actual message */ public void sendNotification(String title, String message) throws IOException { final InetAddress addr = mHostAddress; @@ -214,7 +216,7 @@ public void sendNotification(String title, String message) throws IOException { p.send(addr, mHostPort); } } - + public void sendNotification(String title, String message, byte icontype, byte[] icondata) throws IOException { final InetAddress addr = mHostAddress; if (addr != null) { @@ -225,21 +227,22 @@ public void sendNotification(String title, String message, byte icontype, byte[] /** * Sends a Button event - * + * * @param code Raw button code (default: 0) - * @param repeat This key press should repeat until released (default: 1) + * @param repeat This key press should repeat until released (default: 1) * Note that queued pressed cannot repeat. - * @param down If this is 1, it implies a press event, 0 implies a + * @param down If this is 1, it implies a press event, 0 implies a * release event. (default: 1) * @param queue A queued key press means that the button event is executed - * just once after which the next key press is processed. It - * can be used for macros. Currently there is no support for + * just once after which the next key press is processed. It + * can be used for macros. Currently there is no support for * time delays between queued presses. (default: 0) * @param amount Unimplemented for now; in the future it will be used for * specifying magnitude of analog key press events * @param axis */ - public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) throws IOException { + public void sendButton(short code, boolean repeat, boolean down, boolean queue, short amount, + byte axis) throws IOException { final InetAddress addr = mHostAddress; if (addr != null) { PacketBUTTON p = new PacketBUTTON(code, repeat, down, queue, amount, axis); @@ -249,46 +252,42 @@ public void sendButton(short code, boolean repeat, boolean down, boolean queue, /** * Sends a Button event - * - * @param map_name - * A combination of map_name and button_name refers to a mapping - * in the user's Keymap.xml or Lircmap.xml. map_name can be one - * of the following: - *

    - *
  • KB - Standard keyboard map (<keyboard> section)
  • - *
  • XG - Xbox gamepad map (<gamepad> section)
  • - *
  • R1 - Xbox remote map (<remote> section)
  • - *
  • R2 - Xbox universal remote map (<universalremote> - * section)
  • - *
  • LI:devicename - LIRC remote map where devicename is - * the actual device's name
  • - *
- * @param button_name - * A button name defined in the map specified in map_name. For - * example, if map_name is "KB" refering to the - * section in Keymap.xml then, valid button_names include - * "printscreen", "minus", "x", etc. - * @param repeat - * This key press should repeat until released (default: 1) Note - * that queued pressed cannot repeat. - * @param down - * If this is 1, it implies a press event, 0 implies a release - * event. (default: 1) - * @param queue - * A queued key press means that the button event is executed - * just once after which the next key press is processed. It can - * be used for macros. Currently there is no support for time - * delays between queued presses. (default: 0) - * @param amount - * Unimplemented for now; in the future it will be used for - * specifying magnitude of analog key press events + * + * @param map_name A combination of map_name and button_name refers to a mapping + * in the user's Keymap.xml or Lircmap.xml. map_name can be one + * of the following: + *
    + *
  • KB - Standard keyboard map (<keyboard> section)
  • + *
  • XG - Xbox gamepad map (<gamepad> section)
  • + *
  • R1 - Xbox remote map (<remote> section)
  • + *
  • R2 - Xbox universal remote map (<universalremote> + * section)
  • + *
  • LI:devicename - LIRC remote map where devicename is + * the actual device's name
  • + *
+ * @param button_name A button name defined in the map specified in map_name. For + * example, if map_name is "KB" refering to the + * section in Keymap.xml then, valid button_names include + * "printscreen", "minus", "x", etc. + * @param repeat This key press should repeat until released (default: 1) Note + * that queued pressed cannot repeat. + * @param down If this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue A queued key press means that the button event is executed + * just once after which the next key press is processed. It can + * be used for macros. Currently there is no support for time + * delays between queued presses. (default: 0) + * @param amount Unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events * @param axis */ - public void sendButton(String map_name, String button_name, boolean repeat, boolean down, boolean queue, short amount, byte axis) { + public void sendButton(String map_name, String button_name, boolean repeat, boolean down, boolean queue, + short amount, byte axis) { final InetAddress addr = mHostAddress; if (addr != null) { - Log.i(TAG, "sendButton(" + map_name + ", \"" + button_name + "\", " + (repeat ? "rep, " : "nonrep, ") + (down ? "down)" : "up)")); + Log.i(TAG, "sendButton(" + map_name + ", \"" + button_name + "\", " + (repeat ? "rep, " : "nonrep, " + + "") + (down ? "down)" : "up)")); PacketBUTTON p = new PacketBUTTON(map_name, button_name, repeat, down, queue, amount, axis); p.send(addr, mHostPort); } else { @@ -298,9 +297,9 @@ public void sendButton(String map_name, String button_name, boolean repeat, bool /** * Sets the mouse position in XBMC - * - * @param x Horizontal position ranging from 0 to 65535 - * @param y Vertical position ranging from 0 to 65535 + * + * @param x Horizontal position ranging from 0 to 65535 + * @param y Vertical position ranging from 0 to 65535 */ public void sendMouse(int x, int y) throws IOException { final InetAddress addr = mHostAddress; @@ -312,7 +311,7 @@ public void sendMouse(int x, int y) throws IOException { /** * Sends a ping to the XBMC EventServer - * + * * @throws IOException */ public void ping() throws IOException { @@ -325,19 +324,17 @@ public void ping() throws IOException { /** * Tells XBMC to log the message to xbmc.log with the loglevel as specified. - * - * @param loglevel - * The log level, follows XBMC standard. - *
    - *
  • 0 = DEBUG
  • - *
  • 1 = INFO
  • - *
  • 2 = NOTICE
  • - *
  • 3 = WARNING
  • - *
  • 4 = ERROR
  • - *
  • 5 = SEVERE
  • - *
- * @param logmessage - * The message to log + * + * @param loglevel The log level, follows XBMC standard. + *
    + *
  • 0 = DEBUG
  • + *
  • 1 = INFO
  • + *
  • 2 = NOTICE
  • + *
  • 3 = WARNING
  • + *
  • 4 = ERROR
  • + *
  • 5 = SEVERE
  • + *
+ * @param logmessage The message to log */ public void sendLog(byte loglevel, String logmessage) throws IOException { final InetAddress addr = mHostAddress; @@ -350,7 +347,7 @@ public void sendLog(byte loglevel, String logmessage) throws IOException { /** * Tells XBMC to do the action specified, based on the type it knows were it * needs to be sent. - * + * * @param actionmessage Actionmessage (as in scripting/skinning) */ public void sendAction(String actionmessage) throws IOException { @@ -364,7 +361,7 @@ public void sendAction(String actionmessage) throws IOException { /** * Implements a PingThread which tells XBMC EventServer that the Client is * alive (this should be done at least every 60 seconds! - * + * * @author Stefan Agner */ private static class PingThread extends Thread { @@ -383,7 +380,7 @@ public PingThread(InetAddress hostAddress, int hostPort, int sleepTime) { public void giveup() { mGiveup = true; } - + public void setHost(InetAddress addr, int port) { mHostAddress = addr; mHostPort = port; diff --git a/src/org/xbmc/eventclient/Packet.java b/app/src/main/java/org/xbmc/eventclient/Packet.java similarity index 70% rename from src/org/xbmc/eventclient/Packet.java rename to app/src/main/java/org/xbmc/eventclient/Packet.java index 1296a952..874770df 100644 --- a/src/org/xbmc/eventclient/Packet.java +++ b/app/src/main/java/org/xbmc/eventclient/Packet.java @@ -1,12 +1,13 @@ package org.xbmc.eventclient; + +import android.util.Log; + import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; -import android.util.Log; - /** * XBMC Event Client Class *

@@ -35,7 +36,7 @@ * - Generic packet structure (maximum 1024 bytes per packet) * - Header is 32 bytes long, so 992 bytes available for payload * - large payloads can be split into multiple packets using H4 and H5 - * H5 should contain total no. of packets in such a case + * H5 should contain total no. of packets in such a case * - H6 contains length of P1, which is limited to 992 bytes * - if H5 is 0 or 1, then H4 will be ignored (single packet msg) * - H7 must be set to zeros for now @@ -54,98 +55,119 @@ * | -P1 payload | - * ----------------------------- *

- * @author Stefan Agner * + * @author Stefan Agner */ public abstract class Packet { - + + public final static byte ICON_NONE = 0x00; + public final static byte ICON_JPEG = 0x01; + public final static byte ICON_PNG = 0x02; + public final static byte ICON_GIF = 0x03; + protected final static byte PT_HELO = 0x01; + protected final static byte PT_BYE = 0x02; + protected final static byte PT_BUTTON = 0x03; + protected final static byte PT_MOUSE = 0x04; + protected final static byte PT_PING = 0x05; + protected final static byte PT_BROADCAST = 0x06; + protected final static byte PT_NOTIFICATION = 0x07; + protected final static byte PT_BLOB = 0x08; + protected final static byte PT_LOG = 0x09; + protected final static byte PT_ACTION = 0x0A; + protected final static byte PT_DEBUG = (byte) 0xFF; private final static String TAG = Packet.class.getSimpleName(); - + private final static short MAX_PACKET_SIZE = 1024; + private final static short HEADER_SIZE = 32; + private final static short MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; + private static int uid = (int) (Math.random() * Integer.MAX_VALUE); private byte[] sig; private byte[] payload = new byte[0]; private byte minver; private byte majver; - - private short packettype; - - - private final static short MAX_PACKET_SIZE = 1024; - private final static short HEADER_SIZE = 32; - private final static short MAX_PAYLOAD_SIZE = MAX_PACKET_SIZE - HEADER_SIZE; + private short packettype; - protected final static byte PT_HELO = 0x01; - protected final static byte PT_BYE = 0x02; - protected final static byte PT_BUTTON = 0x03; - protected final static byte PT_MOUSE = 0x04; - protected final static byte PT_PING = 0x05; - protected final static byte PT_BROADCAST = 0x06; - protected final static byte PT_NOTIFICATION = 0x07; - protected final static byte PT_BLOB = 0x08; - protected final static byte PT_LOG = 0x09; - protected final static byte PT_ACTION = 0x0A; - protected final static byte PT_DEBUG = (byte)0xFF; - - public final static byte ICON_NONE = 0x00; - public final static byte ICON_JPEG = 0x01; - public final static byte ICON_PNG = 0x02; - public final static byte ICON_GIF = 0x03; - - private static int uid = (int)(Math.random()*Integer.MAX_VALUE); - /** * This is an Abstract class and cannot be instanced. Please use one of the Packet implementation Classes - * (PacketXXX). - * + * (PacketXXX). + *

* Implements an XBMC Event Client Packet. Type is to be specified at creation time, Payload can be added * with the various appendPayload methods. Packet can be sent through UDP-Socket with method "send". - * @param packettype Type of Packet (PT_XXX) + * + * @param packettype Type of Packet (PT_XXX) */ - protected Packet(short packettype) - { - sig = new byte[] {'X', 'B', 'M', 'C' }; - minver = 0; - majver = 2; - this.packettype = packettype; + protected Packet(short packettype) { + sig = new byte[]{'X', 'B', 'M', 'C'}; + minver = 0; + majver = 2; + this.packettype = packettype; } /** - * Appends a String to the payload (terminated with 0x00) + * Helper Method to convert an integer to a Byte array + * + * @param value + * @return Byte-Array + */ + private static final byte[] intToByteArray(int value) { + return new byte[]{ + (byte) (value >>> 24), + (byte) (value >>> 16), + (byte) (value >>> 8), + (byte) value}; + } + + /** + * Helper Method to convert an short to a Byte array + * + * @param value + * @return Byte-Array + */ + private static final byte[] shortToByteArray(short value) { + return new byte[]{ + (byte) (value >>> 8), + (byte) value}; + } + + /** + * Appends a String to the payload (terminated with 0x00) + * * @param payload Payload as String */ - protected void appendPayload(String payload) - { + protected void appendPayload(String payload) { byte[] payloadarr = payload.getBytes(); int oldpayloadsize = this.payload.length; byte[] oldpayload = this.payload; - this.payload = new byte[oldpayloadsize+payloadarr.length+1]; // Create new Array with more place (+1 for string terminator) + this.payload = new byte[oldpayloadsize + payloadarr.length + 1]; // Create new Array with more place (+1 for + // string terminator) System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize); System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length); } /** * Appends a single Byte to the payload + * * @param payload Payload */ - protected void appendPayload(byte payload) - { - appendPayload(new byte[] { payload }); + protected void appendPayload(byte payload) { + appendPayload(new byte[]{payload}); } /** * Appends a Byte-Array to the payload + * * @param payloadarr Payload */ - protected void appendPayload(byte[] payloadarr) - { + protected void appendPayload(byte[] payloadarr) { int oldpayloadsize = this.payload.length; byte[] oldpayload = this.payload; - this.payload = new byte[oldpayloadsize+payloadarr.length]; + this.payload = new byte[oldpayloadsize + payloadarr.length]; System.arraycopy(oldpayload, 0, this.payload, 0, oldpayloadsize); System.arraycopy(payloadarr, 0, this.payload, oldpayloadsize, payloadarr.length); } /** * Appends an integer to the payload + * * @param i Payload */ protected void appendPayload(int i) { @@ -154,30 +176,31 @@ protected void appendPayload(int i) { /** * Appends a short to the payload + * * @param s Payload */ protected void appendPayload(short s) { appendPayload(shortToByteArray(s)); } - + /** * Get Number of Packets which will be sent with current Payload... + * * @return Number of Packets */ - public int getNumPackets() - { - return (int)((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); + public int getNumPackets() { + return (int) ((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); } - + /** * Get Header for a specific Packet in this sequence... - * @param seq Current sequence number - * @param maxseq Maximal sequence number + * + * @param seq Current sequence number + * @param maxseq Maximal sequence number * @param actpayloadsize Payloadsize of this packet * @return Byte-Array with Header information (currently 32-Byte long, see HEADER_SIZE) */ - private byte[] getHeader(int seq, int maxseq, short actpayloadsize) - { + private byte[] getHeader(int seq, int maxseq, short actpayloadsize) { byte[] header = new byte[HEADER_SIZE]; System.arraycopy(sig, 0, header, 0, 4); header[4] = majver; @@ -194,45 +217,45 @@ private byte[] getHeader(int seq, int maxseq, short actpayloadsize) System.arraycopy(uid, 0, header, 18, 4); byte[] reserved = new byte[10]; System.arraycopy(reserved, 0, header, 22, 10); - + return header; } - + /** * Generates the whole UDP-Message with Header and Payload of a specific Packet in sequence + * * @param seq Current sequence number * @return Byte-Array with UDP-Message */ - private byte[] getUDPMessage(int seq) - { - int maxseq = (int)((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); - if(seq > maxseq) + private byte[] getUDPMessage(int seq) { + int maxseq = (int) ((payload.length + (MAX_PAYLOAD_SIZE - 1)) / MAX_PAYLOAD_SIZE); + if (seq > maxseq) return null; - + short actpayloadsize; - - if(seq == maxseq) - actpayloadsize = (short)(payload.length%MAX_PAYLOAD_SIZE); - + + if (seq == maxseq) + actpayloadsize = (short) (payload.length % MAX_PAYLOAD_SIZE); + else - actpayloadsize = (short)MAX_PAYLOAD_SIZE; + actpayloadsize = (short) MAX_PAYLOAD_SIZE; + + byte[] pack = new byte[HEADER_SIZE + actpayloadsize]; - byte[] pack = new byte[HEADER_SIZE+actpayloadsize]; - System.arraycopy(getHeader(seq, maxseq, actpayloadsize), 0, pack, 0, HEADER_SIZE); - System.arraycopy(payload, (seq-1)*MAX_PAYLOAD_SIZE, pack, HEADER_SIZE, actpayloadsize); - + System.arraycopy(payload, (seq - 1) * MAX_PAYLOAD_SIZE, pack, HEADER_SIZE, actpayloadsize); + return pack; } - + /** * Sends this packet to the EventServer - * @param adr Address of the EventServer + * + * @param adr Address of the EventServer * @param port Port of the EventServer * @throws IOException */ - public void send(final InetAddress adr, final int port) - { + public void send(final InetAddress adr, final int port) { new Thread() { @Override public void run() { @@ -245,11 +268,10 @@ public void run() { Log.e(TAG, "Error opening data socket: " + e.getMessage(), e); return; } - + try { // For each Packet in Sequence... - for(int seq=1;seq<=maxseq;seq++) - { + for (int seq = 1; seq <= maxseq; seq++) { // Get Message and send them... byte[] pack = getUDPMessage(seq); DatagramPacket p = new DatagramPacket(pack, pack.length); @@ -267,30 +289,6 @@ public void run() { } }.start(); } - - /** - * Helper Method to convert an integer to a Byte array - * @param value - * @return Byte-Array - */ - private static final byte[] intToByteArray(int value) { - return new byte[] { - (byte)(value >>> 24), - (byte)(value >>> 16), - (byte)(value >>> 8), - (byte)value}; - } - /** - * Helper Method to convert an short to a Byte array - * @param value - * @return Byte-Array - */ - private static final byte[] shortToByteArray(short value) { - return new byte[] { - (byte)(value >>> 8), - (byte)value}; - } - } diff --git a/src/org/xbmc/eventclient/PacketACTION.java b/app/src/main/java/org/xbmc/eventclient/PacketACTION.java similarity index 81% rename from src/org/xbmc/eventclient/PacketACTION.java rename to app/src/main/java/org/xbmc/eventclient/PacketACTION.java index ae633c78..fc49df8b 100644 --- a/src/org/xbmc/eventclient/PacketACTION.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketACTION.java @@ -1,24 +1,25 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. * The idea is that this will be as in scripting/skining and keymapping, just triggered from afar. - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketACTION extends Packet { - + public final static byte ACTION_EXECBUILTIN = 0x01; - public final static byte ACTION_BUTTON = 0x02; + public final static byte ACTION_BUTTON = 0x02; + - /** * An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * * @param actionmessage Actionmessage (as in scripting/skinning) */ - public PacketACTION(String actionmessage) - { + public PacketACTION(String actionmessage) { super(PT_ACTION); byte actiontype = ACTION_EXECBUILTIN; appendPayload(actionmessage, actiontype); @@ -26,17 +27,16 @@ public PacketACTION(String actionmessage) /** * An ACTION packet tells XBMC to do the action specified, based on the type it knows were it needs to be sent. + * * @param actionmessage Actionmessage (as in scripting/skinning) - * @param actiontype Actiontype (ACTION_EXECBUILTIN or ACTION_BUTTON) + * @param actiontype Actiontype (ACTION_EXECBUILTIN or ACTION_BUTTON) */ - public PacketACTION(String actionmessage, byte actiontype) - { + public PacketACTION(String actionmessage, byte actiontype) { super(PT_ACTION); appendPayload(actionmessage, actiontype); } - - private void appendPayload(String actionmessage, byte actiontype) - { + + private void appendPayload(String actionmessage, byte actiontype) { appendPayload(actiontype); appendPayload(actionmessage); } diff --git a/app/src/main/java/org/xbmc/eventclient/PacketBUTTON.java b/app/src/main/java/org/xbmc/eventclient/PacketBUTTON.java new file mode 100644 index 00000000..6f8b4a40 --- /dev/null +++ b/app/src/main/java/org/xbmc/eventclient/PacketBUTTON.java @@ -0,0 +1,142 @@ +package org.xbmc.eventclient; + +/** + * XBMC Event Client Class + *

+ * A button packet send a key press or release event to XBMC + * + * @author Stefan Agner + */ +public class PacketBUTTON extends Packet { + + protected final static byte BT_USE_NAME = 0x01; + protected final static byte BT_DOWN = 0x02; + protected final static byte BT_UP = 0x04; + protected final static byte BT_USE_AMOUNT = 0x08; + protected final static byte BT_QUEUE = 0x10; + protected final static byte BT_NO_REPEAT = 0x20; + protected final static byte BT_VKEY = 0x40; + protected final static byte BT_AXIS = (byte) 0x80; + protected final static byte BT_AXISSINGLE = (byte) 0x100; + + /** + * A button packet send a key press or release event to XBMC + * + * @param code raw button code (default: 0) + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public PacketBUTTON(short code, boolean repeat, boolean down, boolean queue, short amount, byte axis) { + super(PT_BUTTON); + String map_name = ""; + String button_name = ""; + short flags = 0; + appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags); + } + + /** + * A button packet send a key press or release event to XBMC + * + * @param map_name a combination of map_name and button_name refers to a + * mapping in the user's Keymap.xml or Lircmap.xml. + * map_name can be one of the following: + *

    + *
  • "KB" => standard keyboard map ( section )
  • + *
  • "XG" => xbox gamepad map ( section )
  • + *
  • "R1" => xbox remote map ( section )
  • + *
  • "R2" => xbox universal remote map ( section )
  • + *
  • "LI:devicename" => LIRC remote map where 'devicename' is the + * actual device's name
+ * @param button_name a button name defined in the map specified in map_name. + * For example, if map_name is "KB" refering to the section in Keymap.xml + * then, valid button_names include "printscreen", "minus", "x", etc. + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + */ + public PacketBUTTON(String map_name, String button_name, boolean repeat, boolean down, boolean queue, + short amount, byte axis) { + super(PT_BUTTON); + short code = 0; + short flags = BT_USE_NAME; + appendPayload(code, map_name, button_name, repeat, down, queue, amount, axis, flags); + } + + /** + * Appends Payload for a Button Packet (this method is used by the different Constructors of this Packet) + * + * @param code raw button code (default: 0) + * @param map_name a combination of map_name and button_name refers to a + * mapping in the user's Keymap.xml or Lircmap.xml. + * map_name can be one of the following: + *
    + *
  • "KB" => standard keyboard map ( section )
  • + *
  • "XG" => xbox gamepad map ( section )
  • + *
  • "R1" => xbox remote map ( section )
  • + *
  • "R2" => xbox universal remote map ( section )
  • + *
  • "LI:devicename" => LIRC remote map where 'devicename' is the + * actual device's name
+ * @param button_name a button name defined in the map specified in map_name. + * For example, if map_name is "KB" refering to the section in Keymap.xml + * then, valid button_names include "printscreen", "minus", "x", etc. + * @param repeat this key press should repeat until released (default: 1) + * Note that queued pressed cannot repeat. + * @param down if this is 1, it implies a press event, 0 implies a release + * event. (default: 1) + * @param queue a queued key press means that the button event is + * executed just once after which the next key press is processed. + * It can be used for macros. Currently there is no support for + * time delays between queued presses. (default: 0) + * @param amount unimplemented for now; in the future it will be used for + * specifying magnitude of analog key press events + * @param axis + * @param flags Packet specific flags + */ + private void appendPayload(short code, String map_name, String button_name, boolean repeat, boolean down, + boolean queue, short amount, byte axis, short flags) { + if (amount > 0) + flags |= BT_USE_AMOUNT; + else + amount = 0; + + if (down) + flags |= BT_DOWN; + else + flags |= BT_UP; + + if (!repeat) + flags |= BT_NO_REPEAT; + + if (queue) + flags |= BT_QUEUE; + + if (axis == 1) + flags |= BT_AXISSINGLE; + else if (axis == 2) + flags |= BT_AXIS; + + + appendPayload(code); + appendPayload(flags); + appendPayload(amount); + appendPayload(map_name); + appendPayload(button_name); + } +} diff --git a/src/org/xbmc/eventclient/PacketBYE.java b/app/src/main/java/org/xbmc/eventclient/PacketBYE.java similarity index 76% rename from src/org/xbmc/eventclient/PacketBYE.java rename to app/src/main/java/org/xbmc/eventclient/PacketBYE.java index 8c831b1a..d6a6feb5 100644 --- a/src/org/xbmc/eventclient/PacketBYE.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketBYE.java @@ -1,19 +1,18 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* A BYE packet terminates the connection to XBMC. - * @author Stefan Agner * + * @author Stefan Agner */ -public class PacketBYE extends Packet -{ +public class PacketBYE extends Packet { /** * A BYE packet terminates the connection to XBMC. */ - public PacketBYE() - { + public PacketBYE() { super(PT_BYE); } } diff --git a/src/org/xbmc/eventclient/PacketHELO.java b/app/src/main/java/org/xbmc/eventclient/PacketHELO.java similarity index 76% rename from src/org/xbmc/eventclient/PacketHELO.java rename to app/src/main/java/org/xbmc/eventclient/PacketHELO.java index ca54dbf2..61172e18 100644 --- a/src/org/xbmc/eventclient/PacketHELO.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketHELO.java @@ -2,44 +2,44 @@ /** * XBMC Event Client Class - * + *

* A HELO packet establishes a valid connection to XBMC. It is the * first packet that should be sent. - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketHELO extends Packet { - - + + /** * A HELO packet establishes a valid connection to XBMC. + * * @param devicename Name of the device which connects to XBMC */ - public PacketHELO(String devicename) - { + public PacketHELO(String devicename) { super(PT_HELO); this.appendPayload(devicename); this.appendPayload(ICON_NONE); - this.appendPayload((short)0); // port no + this.appendPayload((short) 0); // port no this.appendPayload(0); // reserved1 this.appendPayload(0); // reserved2 } /** * A HELO packet establishes a valid connection to XBMC. + * * @param devicename Name of the device which connects to XBMC - * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) - * @param iconData The icon as a Byte-Array + * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) + * @param iconData The icon as a Byte-Array */ - public PacketHELO(String devicename, byte iconType, byte[] iconData) - { + public PacketHELO(String devicename, byte iconType, byte[] iconData) { super(PT_HELO); this.appendPayload(devicename); this.appendPayload(iconType); - this.appendPayload((short)0); // port no + this.appendPayload((short) 0); // port no this.appendPayload(0); // reserved1 this.appendPayload(0); // reserved2 this.appendPayload(iconData); // reserved2 } - + } diff --git a/src/org/xbmc/eventclient/PacketLOG.java b/app/src/main/java/org/xbmc/eventclient/PacketLOG.java similarity index 50% rename from src/org/xbmc/eventclient/PacketLOG.java rename to app/src/main/java/org/xbmc/eventclient/PacketLOG.java index 693ad71e..cec15b85 100644 --- a/src/org/xbmc/eventclient/PacketLOG.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketLOG.java @@ -1,28 +1,29 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified. - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketLOG extends Packet { - + /** * A LOG packet tells XBMC to log the message to xbmc.log with the loglevel as specified. - * @param loglevel the loglevel, follows XBMC standard. - *

    - *
  • 0 = DEBUG
  • - *
  • 1 = INFO
  • - *
  • 2 = NOTICE
  • - *
  • 3 = WARNING
  • - *
  • 4 = ERROR
  • - *
  • 5 = SEVERE
  • - *
+ * + * @param loglevel the loglevel, follows XBMC standard. + *
    + *
  • 0 = DEBUG
  • + *
  • 1 = INFO
  • + *
  • 2 = NOTICE
  • + *
  • 3 = WARNING
  • + *
  • 4 = ERROR
  • + *
  • 5 = SEVERE
  • + *
* @param logmessage the message to log */ - public PacketLOG(byte loglevel, String logmessage) - { + public PacketLOG(byte loglevel, String logmessage) { super(PT_LOG); appendPayload(loglevel); appendPayload(logmessage); diff --git a/src/org/xbmc/eventclient/PacketMOUSE.java b/app/src/main/java/org/xbmc/eventclient/PacketMOUSE.java similarity index 82% rename from src/org/xbmc/eventclient/PacketMOUSE.java rename to app/src/main/java/org/xbmc/eventclient/PacketMOUSE.java index d7755ef0..1f6c36f1 100644 --- a/src/org/xbmc/eventclient/PacketMOUSE.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketMOUSE.java @@ -1,27 +1,28 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* A MOUSE packets sets the mouse position in XBMC - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketMOUSE extends Packet { - + protected final static byte MS_ABSOLUTE = 0x01; /** * A MOUSE packets sets the mouse position in XBMC + * * @param x horitontal position ranging from 0 to 65535 * @param y vertical position ranging from 0 to 65535 */ - public PacketMOUSE(int x, int y) - { + public PacketMOUSE(int x, int y) { super(PT_MOUSE); byte flags = 0; flags |= MS_ABSOLUTE; appendPayload(flags); - appendPayload((short)x); - appendPayload((short)y); + appendPayload((short) x); + appendPayload((short) y); } } diff --git a/src/org/xbmc/eventclient/PacketNOTIFICATION.java b/app/src/main/java/org/xbmc/eventclient/PacketNOTIFICATION.java similarity index 77% rename from src/org/xbmc/eventclient/PacketNOTIFICATION.java rename to app/src/main/java/org/xbmc/eventclient/PacketNOTIFICATION.java index 15a5ec8f..7bb358a8 100644 --- a/src/org/xbmc/eventclient/PacketNOTIFICATION.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketNOTIFICATION.java @@ -1,53 +1,54 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* This packet displays a notification window in XBMC. It can contain * a caption, a message and an icon. - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketNOTIFICATION extends Packet { /** * This packet displays a notification window in XBMC. - * @param title Message title - * @param message The actual message + * + * @param title Message title + * @param message The actual message * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) * @param iconData The icon as a Byte-Array */ - public PacketNOTIFICATION(String title, String message, byte iconType, byte[] iconData) - { + public PacketNOTIFICATION(String title, String message, byte iconType, byte[] iconData) { super(PT_NOTIFICATION); appendPayload(title, message, iconType, iconData); } - + /** * This packet displays a notification window in XBMC. - * @param title Message title + * + * @param title Message title * @param message The actual message */ - public PacketNOTIFICATION(String title, String message) - { + public PacketNOTIFICATION(String title, String message) { super(PT_NOTIFICATION); appendPayload(title, message, Packet.ICON_NONE, null); } /** * Appends the payload to the packet... - * @param title Message title - * @param message The actual message + * + * @param title Message title + * @param message The actual message * @param iconType Type of the icon (Packet.ICON_PNG, Packet.ICON_JPEG or Packet.ICON_GIF) * @param iconData The icon as a Byte-Array */ - private void appendPayload(String title, String message, byte iconType, byte[] iconData) - { + private void appendPayload(String title, String message, byte iconType, byte[] iconData) { appendPayload(title); appendPayload(message); appendPayload(iconType); appendPayload(0); // reserved - if(iconData!=null) + if (iconData != null) appendPayload(iconData); - + } } diff --git a/src/org/xbmc/eventclient/PacketPING.java b/app/src/main/java/org/xbmc/eventclient/PacketPING.java similarity index 92% rename from src/org/xbmc/eventclient/PacketPING.java rename to app/src/main/java/org/xbmc/eventclient/PacketPING.java index e405812f..d2b0222d 100644 --- a/src/org/xbmc/eventclient/PacketPING.java +++ b/app/src/main/java/org/xbmc/eventclient/PacketPING.java @@ -1,19 +1,19 @@ package org.xbmc.eventclient; + /** * XBMC Event Client Class - * + *

* A PING packet tells XBMC that the client is still alive. All valid * packets act as ping (not just this one). A client needs to ping * XBMC at least once in 60 seconds or it will time - * @author Stefan Agner * + * @author Stefan Agner */ public class PacketPING extends Packet { /** * A PING packet tells XBMC that the client is still alive. */ - public PacketPING() - { + public PacketPING() { super(PT_PING); } } diff --git a/src/org/xbmc/httpapi/BroadcastListener.java b/app/src/main/java/org/xbmc/httpapi/BroadcastListener.java similarity index 76% rename from src/org/xbmc/httpapi/BroadcastListener.java rename to app/src/main/java/org/xbmc/httpapi/BroadcastListener.java index d40899a6..e0beba2e 100644 --- a/src/org/xbmc/httpapi/BroadcastListener.java +++ b/app/src/main/java/org/xbmc/httpapi/BroadcastListener.java @@ -1,342 +1,356 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi; - -import java.io.IOException; -import java.net.DatagramPacket; -import java.net.DatagramSocket; -import java.net.InetAddress; -import java.net.SocketException; -import java.util.Observable; -import java.util.Random; -import java.util.Timer; -import java.util.TimerTask; - -import org.xbmc.android.remote.business.Command; -import org.xbmc.api.business.DataResponse; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; - -import android.util.Log; - -/** - * Implementation of XBMC's broadcast feature. - * - *

Classical observer pattern, any class implementing the observer interface - * can subscribe. On any event, the {@link Observable#update(Observable o, Object arg) update()} - * method is executed on the subscriber, with the event code in the - * {@link BroadcastListener.Event} object.

- * - *

We will set the broadcast port to something random in order to distinguish - * between several potential XBMC instances running concurrently. If broadcasting - * is active and a random port is already set, the current port will be reused, - * otherwise it'll be reset.

- * - *

At start, we'll make XBMC broadcast an initial packet to test if it's - * working (different subnets will already not work, for instance). Upon - * success, the EVENT_AVAILABLE event is propagated. If nothing was - * received after a timeout or an error happened, the EVENT_TIMEOUT - * or the EVENT_ERROR event are propagated respectively.

- * - * @see XBMC Wiki - * @see Trac about missing messages - * @author Team XBMC - */ -public class BroadcastListener extends Observable implements Runnable { - - private static final String TAG = "broadcast"; - - public static final int EVENT_ERROR = -1; - public static final int EVENT_UNKNOWN = 0; - public static final int EVENT_STARTUP = 1; - public static final int EVENT_SHUTDOWN = 2; - public static final int EVENT_ON_ACTION = 3; - public static final int EVENT_ON_PLAYBACK_STARTED = 4; - public static final int EVENT_ON_PLAYBACK_ENDED = 5; - public static final int EVENT_ON_PLAYBACK_STOPPED = 6; - public static final int EVENT_ON_PLAYBACK_PAUSED = 7; - public static final int EVENT_ON_PLAYBACK_RESUMED = 8; - public static final int EVENT_ON_PLAYBACK_SEEK = 9; - public static final int EVENT_ON_PLAYBACK_SPEEDCHANGE = 10; - public static final int EVENT_ON_QUEUE_NEXT_ITEM = 11; - public static final int EVENT_ON_MEDIA_CHANGED = 12; - public static final int EVENT_ON_PROGRESS_CHANGED = 13; - public static final int EVENT_AVAILABLE = 100; - public static final int EVENT_TIMEOUT = 101; - - private static final String THREAD_NAME = "BroadcastListener"; - private static final String TIMER_NAME = "BroadcastTimer"; - private static final String BCAST_PING = "OnXbmcRemoteTest"; - - private static final int TIMEOUT = 10; - private static final int DEFAULT_PORT = 8278; - private static final int BUFFER_LENGTH = 256; - private static final int BCAST_LEVEL = 2; - private static final String BCAST_ADDR = "255.255.255.255"; - - private static final Timer sTimer = new Timer(TIMER_NAME); - private static BroadcastListener sInstance; - private static Thread sThread; - - private final HttpApi mHttpClient; - - private boolean mIsListening = false; - private boolean mIsAvailable = false; - private int mPort = 0; - - private final INotifiableManager mManagerStub; - - /** - * Returns the current instance of the listener, or creates a new one if - * not available. - * @param httpClient Used for HTTP control API. - * @return Current instance - */ - public static BroadcastListener getInstance(HttpApi httpClient) { - if (sInstance == null) { - Log.i(TAG, "creating instance.."); - sInstance = new BroadcastListener(httpClient); - sThread = new Thread(sInstance, THREAD_NAME); - } - return sInstance; - } - - /** - * It's a singleton class, so the class constructor is private. Use getInstance(). - * @param httpClient - */ - private BroadcastListener(HttpApi httpClient) { - mHttpClient = httpClient; - init(); - mManagerStub = new INotifiableManager() { - public void onMessage(int code, String message) { } - public void onMessage(String message) { } - public void onError(Exception e) { } - public void onFinish(DataResponse response) { - } - public void onWrongConnectionState(int state, Command cmd) { - } - public void retryAll() { - } - }; - } - - /** - * Runs a thread that: - * 1. Checks if XBMC's broadcast port needs to be reset - * 2. Sets XBMC's broadcast port if necessary - * 3. Starts the listener thread - * 4. Sends a test broadcast via HTTP API - * 5. Loops until the listener thread received the test broadcast or - * timeout occurs. Dispatches timeout event in that case (test broadcast - * reception is handelled by the listener thread) - */ - private synchronized void init() { - (new Thread(THREAD_NAME + "-INIT") { - public void run() { - Log.i(TAG, "init start..."); - final int port = mHttpClient.control.getBroadcast(mManagerStub); - Log.i(TAG, "current port = " + port); - if (port == 0 || port == DEFAULT_PORT) { - final Random rnd = new Random(); - final int rndPort = (rnd.nextInt() % 22768) + 10000; - Log.i(TAG, "new port = " + rndPort); - if (!mHttpClient.control.setBroadcast(mManagerStub, rndPort, BCAST_LEVEL)) { - Log.i(TAG, "SETTING BROADCAST SETTINGS FAILED!"); - dispatch(EVENT_ERROR); - mIsAvailable = false; - mPort = 0; - return; - } - mPort = rndPort; - } else { - mPort = port; - Log.i(TAG, "keeping port " + port); - } - // now we have a port, launch the listener thread - sThread.start(); - int n = 0; - while (!mIsAvailable || !mIsListening) { - Log.i(TAG, "broadcast PING (" + BCAST_PING + ")..."); - mHttpClient.control.broadcast(mManagerStub, BCAST_PING); - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - break; - } - if (n++ > TIMEOUT) { - Log.i(TAG, "TIMEOUT waiting for ping packet."); - dispatch(EVENT_TIMEOUT); - break; - } - } - Log.i(TAG, "EXITED firstrun loop!"); - } - }).start(); - } - - /** - * Starts the thread listening for broadcast packets. - */ - public void run() { - try { - - byte[] b = new byte[BUFFER_LENGTH]; - DatagramPacket packet = new DatagramPacket(b, b.length); - DatagramSocket socket = new DatagramSocket(mPort, InetAddress.getByName(BCAST_ADDR)); - - mIsListening = true; - while (mIsListening) { - // blocks until a datagram is received - socket.receive(packet); - String received = new String(packet.getData(), 0, packet.getLength()); - // must reset length field - packet.setLength(b.length); - handle(received.replace("", "").replace("", "")); - } - Log.i(TAG, "EXITED listener loop!"); - } catch (SocketException e) { - e.printStackTrace(); - String[] params = { e.getMessage() }; - dispatch(EVENT_ERROR, params); - } catch (IOException e) { - e.printStackTrace(); - String[] params = { e.getMessage() }; - dispatch(EVENT_ERROR, params); - } - } - - /** - * Stops the broadcast listener - */ - public void stop() { - mIsListening = false; - } - - /** - * Notifies the observers - * @param event - * @param params - */ - private void dispatch(int event, String[] params) { - setChanged(); - notifyObservers(new Event(event, params)); - } - - /** - * Notifies the observers - * @param event - */ - private void dispatch(int event) { - String[] params = {}; - dispatch(event, params); - } - - /** - * Parses the received packet and sets the event id accordingly. Also the - * timer thread providing virtual clock events is managed in here. - * @param response Stripped response string - */ - private void handle(String response) { - Log.i(TAG, "RECEIVED: " + response); - String param = ""; - String[] params = null; - int event = EVENT_UNKNOWN; - if (response.contains(":")) { - param = response.substring(response.indexOf(":") + 1, response.lastIndexOf(";")); - } - if (response.startsWith("StartUp")) { - event = EVENT_STARTUP; - } else if (response.startsWith("ShutDown")) { - event = EVENT_SHUTDOWN; - } else if (response.startsWith("OnAction")) { - event = EVENT_ON_ACTION; - params = new String[1]; - params[0] = param; - } else if (response.startsWith("OnPlayBackStarted")) { - event = EVENT_ON_PLAYBACK_STARTED; - ICurrentlyPlaying currPlaying = mHttpClient.control.getCurrentlyPlaying(mManagerStub); - sTimer.schedule(new BroadcastListener.Counter(currPlaying.getTime(), currPlaying.getDuration()), 0L, 1000L); - } else if (response.startsWith("OnPlayBackStopped")) { - event = EVENT_ON_PLAYBACK_STOPPED; - sTimer.cancel(); - } else if (response.startsWith("OnPlayBackEnded")) { - event = EVENT_ON_PLAYBACK_ENDED; - sTimer.cancel(); - } else if (response.startsWith("OnPlayBackPaused")) { - event = EVENT_ON_PLAYBACK_PAUSED; - sTimer.cancel(); - } else if (response.startsWith("OnPlayBackResumed")) { - event = EVENT_ON_PLAYBACK_RESUMED; - ICurrentlyPlaying currPlaying = mHttpClient.control.getCurrentlyPlaying(mManagerStub); - sTimer.schedule(new BroadcastListener.Counter(currPlaying.getTime(), currPlaying.getDuration()), 0L, 1000L); - } else if (response.startsWith("OnQueueNextItem")) { - event = EVENT_ON_QUEUE_NEXT_ITEM; - } else if (response.startsWith("MediaChanged")) { - event = EVENT_ON_MEDIA_CHANGED; - params = param.split("
  • "); - } else if (response.startsWith(BCAST_PING)) { - event = EVENT_AVAILABLE; - mIsAvailable = true; - } - if (params == null) { - params = new String[0]; - } - dispatch(event, params); - } - - private class Counter extends TimerTask { - private int mStart, mEnd; - Counter(int start, int end) { - mStart = start; - mEnd = end; - } - @Override - public void run() { - String[] params = { String.valueOf(mStart++) }; - dispatch(EVENT_ON_PROGRESS_CHANGED, params); - if (mStart > mEnd) { - cancel(); - } - } - } - - /** - * The object that is returned upon - * @author Team XBMC - */ - public static class Event { - public final int id; - public final String[] params; - public Event(int event, String[] params) { - this.id = event; - this.params = params; - } - public int getInt(int fallback) { - try { - return params.length > 0 ? Integer.valueOf(params[0]) : fallback; - } catch (NumberFormatException e) { - return fallback; - } - } - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi; + +import android.util.Log; + +import org.xbmc.android.remote.business.Command; +import org.xbmc.api.business.DataResponse; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.SocketException; +import java.util.Observable; +import java.util.Random; +import java.util.Timer; +import java.util.TimerTask; + +/** + * Implementation of XBMC's broadcast feature. + *

    + *

    Classical observer pattern, any class implementing the observer interface + * can subscribe. On any event, the {@link java.util.Observer#update(Observable o, Object arg) update()} + * method is executed on the subscriber, with the event code in the + * {@link BroadcastListener.Event} object.

    + *

    + *

    We will set the broadcast port to something random in order to distinguish + * between several potential XBMC instances running concurrently. If broadcasting + * is active and a random port is already set, the current port will be reused, + * otherwise it'll be reset.

    + *

    + *

    At start, we'll make XBMC broadcast an initial packet to test if it's + * working (different subnets will already not work, for instance). Upon + * success, the EVENT_AVAILABLE event is propagated. If nothing was + * received after a timeout or an error happened, the EVENT_TIMEOUT + * or the EVENT_ERROR event are propagated respectively.

    + * + * @author Team XBMC + * @see XBMC Wiki + * @see Trac about missing messages + */ +public class BroadcastListener extends Observable implements Runnable { + + public static final int EVENT_ERROR = -1; + public static final int EVENT_UNKNOWN = 0; + public static final int EVENT_STARTUP = 1; + public static final int EVENT_SHUTDOWN = 2; + public static final int EVENT_ON_ACTION = 3; + public static final int EVENT_ON_PLAYBACK_STARTED = 4; + public static final int EVENT_ON_PLAYBACK_ENDED = 5; + public static final int EVENT_ON_PLAYBACK_STOPPED = 6; + public static final int EVENT_ON_PLAYBACK_PAUSED = 7; + public static final int EVENT_ON_PLAYBACK_RESUMED = 8; + public static final int EVENT_ON_PLAYBACK_SEEK = 9; + public static final int EVENT_ON_PLAYBACK_SPEEDCHANGE = 10; + public static final int EVENT_ON_QUEUE_NEXT_ITEM = 11; + public static final int EVENT_ON_MEDIA_CHANGED = 12; + public static final int EVENT_ON_PROGRESS_CHANGED = 13; + public static final int EVENT_AVAILABLE = 100; + public static final int EVENT_TIMEOUT = 101; + private static final String TAG = "broadcast"; + private static final String THREAD_NAME = "BroadcastListener"; + private static final String TIMER_NAME = "BroadcastTimer"; + private static final Timer sTimer = new Timer(TIMER_NAME); + private static final String BCAST_PING = "OnXbmcRemoteTest"; + private static final int TIMEOUT = 10; + private static final int DEFAULT_PORT = 8278; + private static final int BUFFER_LENGTH = 256; + private static final int BCAST_LEVEL = 2; + private static final String BCAST_ADDR = "255.255.255.255"; + private static BroadcastListener sInstance; + private static Thread sThread; + + private final HttpApi mHttpClient; + private final INotifiableManager mManagerStub; + private boolean mIsListening = false; + private boolean mIsAvailable = false; + private int mPort = 0; + + /** + * It's a singleton class, so the class constructor is private. Use getInstance(). + * + * @param httpClient + */ + private BroadcastListener(HttpApi httpClient) { + mHttpClient = httpClient; + init(); + mManagerStub = new INotifiableManager() { + public void onMessage(int code, String message) { + } + + public void onMessage(String message) { + } + + public void onError(Exception e) { + } + + public void onFinish(DataResponse response) { + } + + public void onWrongConnectionState(int state, Command cmd) { + } + + public void retryAll() { + } + }; + } + + /** + * Returns the current instance of the listener, or creates a new one if + * not available. + * + * @param httpClient Used for HTTP control API. + * @return Current instance + */ + public static BroadcastListener getInstance(HttpApi httpClient) { + if (sInstance == null) { + Log.i(TAG, "creating instance.."); + sInstance = new BroadcastListener(httpClient); + sThread = new Thread(sInstance, THREAD_NAME); + } + return sInstance; + } + + /** + * Runs a thread that: + * 1. Checks if XBMC's broadcast port needs to be reset + * 2. Sets XBMC's broadcast port if necessary + * 3. Starts the listener thread + * 4. Sends a test broadcast via HTTP API + * 5. Loops until the listener thread received the test broadcast or + * timeout occurs. Dispatches timeout event in that case (test broadcast + * reception is handelled by the listener thread) + */ + private synchronized void init() { + (new Thread(THREAD_NAME + "-INIT") { + public void run() { + Log.i(TAG, "init start..."); + final int port = mHttpClient.control.getBroadcast(mManagerStub); + Log.i(TAG, "current port = " + port); + if (port == 0 || port == DEFAULT_PORT) { + final Random rnd = new Random(); + final int rndPort = (rnd.nextInt() % 22768) + 10000; + Log.i(TAG, "new port = " + rndPort); + if (!mHttpClient.control.setBroadcast(mManagerStub, rndPort, BCAST_LEVEL)) { + Log.i(TAG, "SETTING BROADCAST SETTINGS FAILED!"); + dispatch(EVENT_ERROR); + mIsAvailable = false; + mPort = 0; + return; + } + mPort = rndPort; + } else { + mPort = port; + Log.i(TAG, "keeping port " + port); + } + // now we have a port, launch the listener thread + sThread.start(); + int n = 0; + while (!mIsAvailable || !mIsListening) { + Log.i(TAG, "broadcast PING (" + BCAST_PING + ")..."); + mHttpClient.control.broadcast(mManagerStub, BCAST_PING); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + break; + } + if (n++ > TIMEOUT) { + Log.i(TAG, "TIMEOUT waiting for ping packet."); + dispatch(EVENT_TIMEOUT); + break; + } + } + Log.i(TAG, "EXITED firstrun loop!"); + } + }).start(); + } + + /** + * Starts the thread listening for broadcast packets. + */ + public void run() { + try { + + byte[] b = new byte[BUFFER_LENGTH]; + DatagramPacket packet = new DatagramPacket(b, b.length); + DatagramSocket socket = new DatagramSocket(mPort, InetAddress.getByName(BCAST_ADDR)); + + mIsListening = true; + while (mIsListening) { + // blocks until a datagram is received + socket.receive(packet); + String received = new String(packet.getData(), 0, packet.getLength()); + // must reset length field + packet.setLength(b.length); + handle(received.replace("", "").replace("", "")); + } + Log.i(TAG, "EXITED listener loop!"); + } catch (SocketException e) { + e.printStackTrace(); + String[] params = {e.getMessage()}; + dispatch(EVENT_ERROR, params); + } catch (IOException e) { + e.printStackTrace(); + String[] params = {e.getMessage()}; + dispatch(EVENT_ERROR, params); + } + } + + /** + * Stops the broadcast listener + */ + public void stop() { + mIsListening = false; + } + + /** + * Notifies the observers + * + * @param event + * @param params + */ + private void dispatch(int event, String[] params) { + setChanged(); + notifyObservers(new Event(event, params)); + } + + /** + * Notifies the observers + * + * @param event + */ + private void dispatch(int event) { + String[] params = {}; + dispatch(event, params); + } + + /** + * Parses the received packet and sets the event id accordingly. Also the + * timer thread providing virtual clock events is managed in here. + * + * @param response Stripped response string + */ + private void handle(String response) { + Log.i(TAG, "RECEIVED: " + response); + String param = ""; + String[] params = null; + int event = EVENT_UNKNOWN; + if (response.contains(":")) { + param = response.substring(response.indexOf(":") + 1, response.lastIndexOf(";")); + } + if (response.startsWith("StartUp")) { + event = EVENT_STARTUP; + } else if (response.startsWith("ShutDown")) { + event = EVENT_SHUTDOWN; + } else if (response.startsWith("OnAction")) { + event = EVENT_ON_ACTION; + params = new String[1]; + params[0] = param; + } else if (response.startsWith("OnPlayBackStarted")) { + event = EVENT_ON_PLAYBACK_STARTED; + ICurrentlyPlaying currPlaying = mHttpClient.control.getCurrentlyPlaying(mManagerStub); + sTimer.schedule(new BroadcastListener.Counter(currPlaying.getTime(), currPlaying.getDuration()), 0L, + 1000L); + } else if (response.startsWith("OnPlayBackStopped")) { + event = EVENT_ON_PLAYBACK_STOPPED; + sTimer.cancel(); + } else if (response.startsWith("OnPlayBackEnded")) { + event = EVENT_ON_PLAYBACK_ENDED; + sTimer.cancel(); + } else if (response.startsWith("OnPlayBackPaused")) { + event = EVENT_ON_PLAYBACK_PAUSED; + sTimer.cancel(); + } else if (response.startsWith("OnPlayBackResumed")) { + event = EVENT_ON_PLAYBACK_RESUMED; + ICurrentlyPlaying currPlaying = mHttpClient.control.getCurrentlyPlaying(mManagerStub); + sTimer.schedule(new BroadcastListener.Counter(currPlaying.getTime(), currPlaying.getDuration()), 0L, + 1000L); + } else if (response.startsWith("OnQueueNextItem")) { + event = EVENT_ON_QUEUE_NEXT_ITEM; + } else if (response.startsWith("MediaChanged")) { + event = EVENT_ON_MEDIA_CHANGED; + params = param.split("
  • "); + } else if (response.startsWith(BCAST_PING)) { + event = EVENT_AVAILABLE; + mIsAvailable = true; + } + if (params == null) { + params = new String[0]; + } + dispatch(event, params); + } + + /** + * The object that is returned upon + * + * @author Team XBMC + */ + public static class Event { + public final int id; + public final String[] params; + + public Event(int event, String[] params) { + this.id = event; + this.params = params; + } + + public int getInt(int fallback) { + try { + return params.length > 0 ? Integer.valueOf(params[0]) : fallback; + } catch (NumberFormatException e) { + return fallback; + } + } + } + + private class Counter extends TimerTask { + private int mStart, mEnd; + + Counter(int start, int end) { + mStart = start; + mEnd = end; + } + + @Override + public void run() { + String[] params = {String.valueOf(mStart++)}; + dispatch(EVENT_ON_PROGRESS_CHANGED, params); + if (mStart > mEnd) { + cancel(); + } + } + } } \ No newline at end of file diff --git a/src/org/xbmc/httpapi/Connection.java b/app/src/main/java/org/xbmc/httpapi/Connection.java similarity index 85% rename from src/org/xbmc/httpapi/Connection.java rename to app/src/main/java/org/xbmc/httpapi/Connection.java index 432e8d5b..9a455fd7 100644 --- a/src/org/xbmc/httpapi/Connection.java +++ b/app/src/main/java/org/xbmc/httpapi/Connection.java @@ -1,546 +1,567 @@ -/* - * Copyright (C) 2005-2010 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashMap; - -import org.apache.http.HttpException; -import org.xbmc.android.util.Base64; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.Host; - -import android.util.Log; - - -/** - * Singleton class. Will be instantiated only once - * - * @author Team XBMC - */ -public class Connection { - - private static final String TAG = "Connection"; - private static final String XBMC_HTTP_BOOTSTRAP = "/xbmcCmds/xbmcHttp"; - private static final String XBMC_MICROHTTPD_THUMB_BOOTSTRAP = "/thumb/"; - private static final String XBMC_MICROHTTPD_VFS_BOOTSTRAP = "/vfs/"; - private static final int SOCKET_CONNECTION_TIMEOUT = 5000; - - /** - * Singleton class instance - */ - private static Connection sConnection; - - /** - * Complete URL without any attached command parameters, for instance: - * http://192.168.0.10:8080 - */ - private String mUrlSuffix; - - /** - * Socket read timeout (connection timeout is default) - */ - private int mSocketReadTimeout = 0; - - /** - * Holds the base64 encoded user/pass for http authentication - */ - private String authEncoded = null; - - /** - * Use getInstance() for public class instantiation - * @param host XBMC host - * @param port HTTP API port - */ - private Connection(String host, int port) { - setHost(host, port); - } - - /** - * Returns the singleton instance of this connection. Note that host and - * port settings are only looked at the first time. Use {@link setHost()} - * if you want to update these parameters. - * @param host XBMC host - * @param port HTTP API port - * @return Connection instance - */ - public static Connection getInstance(String host, int port) { - if (sConnection == null) { - sConnection = new Connection(host, port); - } - if (sConnection.mUrlSuffix == null) { - sConnection.setHost(host, port); - } - return sConnection; - } - - /** - * Updates host info of the connection instance - * @param host - */ - public void setHost(Host host) { - if (host == null) { - setHost(null, 0); - } else { - setHost(host.addr, host.port); - setAuth(host.user, host.pass); - } - } - - /** - * Updates host and port parameters of the connection instance. - * @param host Host or IP address of the host - * @param port Port the HTTP API is listening to - */ - public void setHost(String host, int port) { - if (host == null || port <= 0) { - mUrlSuffix = null; - } else { - StringBuilder sb = new StringBuilder(); - sb.append("http://"); - sb.append(host); - sb.append(":"); - sb.append(port); - mUrlSuffix = sb.toString(); - } - } - - /** - * Sets authentication info - * @param user HTTP API username - * @param pass HTTP API password - */ - public void setAuth(String user, String pass) { - if (user != null && pass != null) { - String auth = user + ":" + pass; - authEncoded = Base64.encodeBytes(auth.getBytes()).toString(); - } else { - authEncoded = null; - } - } - - /** - * Sets socket read timeout (connection timeout has constant value) - * @param timeout Read timeout in milliseconds. - */ - public void setTimeout(int timeout) { - if (timeout > 0) { - mSocketReadTimeout = timeout; - } - } - - /** - * Returns the full URL of an HTTP API request - * @param command Name of the command to execute - * @param parameters Parameters, separated by ";". - * @return Absolute URL to HTTP API - */ - public String getUrl(String command, String parameters) { - // create url - StringBuilder sb = new StringBuilder(mUrlSuffix); - sb.append(XBMC_HTTP_BOOTSTRAP); - sb.append("?command="); - sb.append(command); - sb.append("("); - sb.append(URLEncoder.encode(parameters)); - sb.append(")"); - return sb.toString(); - } - - /** - * Returns an input stream pointing to a HTTP API command. - * @param command Name of the command to execute - * @param parameters Parameters, separated by ";". - * @param manager Reference back to business layer - * @return - */ - public InputStream getThumbInputStream(String command, String parameters, INotifiableManager manager) { - URLConnection uc = null; - try { - if (mUrlSuffix == null) { - throw new NoSettingsException(); - } - URL url = new URL(getUrl(command, parameters)); - uc = getUrlConnection(url); - Log.i(TAG, "Preparing input stream from " + url); - return uc.getInputStream(); - } catch (MalformedURLException e) { - manager.onError(e); - } catch (IOException e) { - manager.onError(e); - } catch (NoSettingsException e) { - manager.onError(e); - } - return null; - } - - /** - * Returns an input stream pointing to a HTTP API command. - * @param command Name of the command to execute - * @param parameters Parameters, separated by ";". - * @param manager Reference back to business layer - * @return - */ - public InputStream getThumbInputStreamForMicroHTTPd(String thumb, INotifiableManager manager) throws FileNotFoundException { - URLConnection uc = null; - try { - if (mUrlSuffix == null) { - throw new NoSettingsException(); - } - final URL url; - if (ClientFactory.XBMC_REV > 0 && ClientFactory.XBMC_REV >= ClientFactory.THUMB_TO_VFS_REV) { - url = new URL(mUrlSuffix + XBMC_MICROHTTPD_VFS_BOOTSTRAP + URLEncoder.encode(thumb)); - } else { - url = new URL(mUrlSuffix + XBMC_MICROHTTPD_THUMB_BOOTSTRAP + thumb + ".jpg"); - } - Log.i(TAG, "Preparing input stream from " + url + " for microhttpd.."); - uc = getUrlConnection(url); - return uc.getInputStream(); - } catch (FileNotFoundException e) { - throw e; - } catch (MalformedURLException e) { - manager.onError(e); - } catch (IOException e) { - manager.onError(e); - } catch (NoSettingsException e) { - manager.onError(e); - } - return null; - } - - /** - * Executes a query. - * @param command Name of the command to execute - * @param parameters Parameters, separated by ";". - * @param manager Reference back to business layer - * @return HTTP response string. - */ - public String query(String command, String parameters, INotifiableManager manager) { - URLConnection uc = null; - - try { - if (mUrlSuffix == null) { - throw new NoSettingsException(); - } - - URL url = new URL(getUrl(command, parameters)); - uc = getUrlConnection(url); - - final String debugUrl = URLDecoder.decode(url.toString()); - Log.i(TAG, debugUrl); - - final BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()), 8192); - final StringBuilder response = new StringBuilder(); - String line; - - while((line = in.readLine()) != null) { - response.append(line); - } - in.close(); +/* + * Copyright (C) 2005-2010 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi; + +import android.util.Log; + +import org.apache.http.HttpException; +import org.xbmc.android.util.Base64; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.Host; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; + + +/** + * Singleton class. Will be instantiated only once + * + * @author Team XBMC + */ +public class Connection { + + public static final String LINE_SEP = "
  • "; + public static final String VALUE_SEP = ";"; + public static final String PAIR_SEP = ":"; + private static final String TAG = "Connection"; + private static final String XBMC_HTTP_BOOTSTRAP = "/xbmcCmds/xbmcHttp"; + private static final String XBMC_MICROHTTPD_THUMB_BOOTSTRAP = "/thumb/"; + private static final String XBMC_MICROHTTPD_VFS_BOOTSTRAP = "/vfs/"; + private static final int SOCKET_CONNECTION_TIMEOUT = 5000; + /** + * Singleton class instance + */ + private static Connection sConnection; + /** + * Complete URL without any attached command parameters, for instance: + * http://192.168.0.10:8080 + */ + private String mUrlSuffix; + /** + * Socket read timeout (connection timeout is default) + */ + private int mSocketReadTimeout = 0; + /** + * Holds the base64 encoded user/pass for http authentication + */ + private String authEncoded = null; + + /** + * Use getInstance() for public class instantiation + * + * @param host XBMC host + * @param port HTTP API port + */ + private Connection(String host, int port) { + setHost(host, port); + } + + /** + * Returns the singleton instance of this connection. Note that host and + * port settings are only looked at the first time. Use {@link #setHost} + * if you want to update these parameters. + * + * @param host XBMC host + * @param port HTTP API port + * @return Connection instance + */ + public static Connection getInstance(String host, int port) { + if (sConnection == null) { + sConnection = new Connection(host, port); + } + if (sConnection.mUrlSuffix == null) { + sConnection.setHost(host, port); + } + return sConnection; + } + + /** + * Removes the trailing "" string from the value + * + * @param value + * @return Trimmed value + */ + public static String trim(String value) { + return new String(value.replace("", "").replace("", "").replace("", + "").toCharArray()); + } + + /** + * Removes the trailing "" string from the value and tries to + * parse an integer from it. On error, returns -1. + * + * @param value + * @return Parsed integer from field value + */ + public static int trimInt(String value) { + String trimmed = trim(value); + if (trimmed.length() > 0) { + try { + return Integer.parseInt(trimmed.replace(",", "")); + } catch (NumberFormatException e) { + return -1; + } + } else { + return -1; + } + } + + /** + * Removes the trailing "" string from the value and tries to + * parse a double from it. On error, returns -1.0. + * + * @param value + * @return Parsed double from field value + */ + public static double trimDouble(String value) { + String trimmed = trim(value); + if (trimmed.length() > 0) { + try { + return Double.parseDouble(trimmed); + } catch (NumberFormatException e) { + return -1.0; + } + } else { + return -1.0; + } + } + + /** + * Removes the trailing "" string from the value and tries to + * parse a boolean from it. + * + * @param value + * @return Parsed boolean from field value + */ + public static boolean trimBoolean(String value) { + String trimmed = trim(value); + if (trimmed.length() > 0) { + if (trimmed.startsWith("0") || trimmed.toLowerCase().startsWith("false")) { + return false; + } + if (trimmed.startsWith("1") || trimmed.toLowerCase().startsWith("true")) { + return true; + } + } + return false; + } + + /** + * Updates host info of the connection instance + * + * @param host + */ + public void setHost(Host host) { + if (host == null) { + setHost(null, 0); + } else { + setHost(host.addr, host.port); + setAuth(host.user, host.pass); + } + } + + /** + * Updates host and port parameters of the connection instance. + * + * @param host Host or IP address of the host + * @param port Port the HTTP API is listening to + */ + public void setHost(String host, int port) { + if (host == null || port <= 0) { + mUrlSuffix = null; + } else { + StringBuilder sb = new StringBuilder(); + sb.append("http://"); + sb.append(host); + sb.append(":"); + sb.append(port); + mUrlSuffix = sb.toString(); + } + } + + /** + * Sets authentication info + * + * @param user HTTP API username + * @param pass HTTP API password + */ + public void setAuth(String user, String pass) { + if (user != null && pass != null) { + String auth = user + ":" + pass; + authEncoded = Base64.encodeBytes(auth.getBytes()).toString(); + } else { + authEncoded = null; + } + } + + /** + * Sets socket read timeout (connection timeout has constant value) + * + * @param timeout Read timeout in milliseconds. + */ + public void setTimeout(int timeout) { + if (timeout > 0) { + mSocketReadTimeout = timeout; + } + } + + /** + * Returns the full URL of an HTTP API request + * + * @param command Name of the command to execute + * @param parameters Parameters, separated by ";". + * @return Absolute URL to HTTP API + */ + public String getUrl(String command, String parameters) { + // create url + StringBuilder sb = new StringBuilder(mUrlSuffix); + sb.append(XBMC_HTTP_BOOTSTRAP); + sb.append("?command="); + sb.append(command); + sb.append("("); + sb.append(URLEncoder.encode(parameters)); + sb.append(")"); + return sb.toString(); + } + + /** + * Returns an input stream pointing to a HTTP API command. + * + * @param command Name of the command to execute + * @param parameters Parameters, separated by ";". + * @param manager Reference back to business layer + * @return + */ + public InputStream getThumbInputStream(String command, String parameters, INotifiableManager manager) { + URLConnection uc = null; + try { + if (mUrlSuffix == null) { + throw new NoSettingsException(); + } + URL url = new URL(getUrl(command, parameters)); + uc = getUrlConnection(url); + Log.i(TAG, "Preparing input stream from " + url); + return uc.getInputStream(); + } catch (MalformedURLException e) { + manager.onError(e); + } catch (IOException e) { + manager.onError(e); + } catch (NoSettingsException e) { + manager.onError(e); + } + return null; + } + + /** + * Returns an input stream pointing to a HTTP API command. + * + * @param manager Reference back to business layer + * @return + */ + public InputStream getThumbInputStreamForMicroHTTPd(String thumb, INotifiableManager manager) throws + FileNotFoundException { + URLConnection uc = null; + try { + if (mUrlSuffix == null) { + throw new NoSettingsException(); + } + final URL url; + if (ClientFactory.XBMC_REV > 0 && ClientFactory.XBMC_REV >= ClientFactory.THUMB_TO_VFS_REV) { + url = new URL(mUrlSuffix + XBMC_MICROHTTPD_VFS_BOOTSTRAP + URLEncoder.encode(thumb)); + } else { + url = new URL(mUrlSuffix + XBMC_MICROHTTPD_THUMB_BOOTSTRAP + thumb + ".jpg"); + } + Log.i(TAG, "Preparing input stream from " + url + " for microhttpd.."); + uc = getUrlConnection(url); + return uc.getInputStream(); + } catch (FileNotFoundException e) { + throw e; + } catch (MalformedURLException e) { + manager.onError(e); + } catch (IOException e) { + manager.onError(e); + } catch (NoSettingsException e) { + manager.onError(e); + } + return null; + } + + /** + * Executes a query. + * + * @param command Name of the command to execute + * @param parameters Parameters, separated by ";". + * @param manager Reference back to business layer + * @return HTTP response string. + */ + public String query(String command, String parameters, INotifiableManager manager) { + URLConnection uc = null; + + try { + if (mUrlSuffix == null) { + throw new NoSettingsException(); + } + + URL url = new URL(getUrl(command, parameters)); + uc = getUrlConnection(url); + + final String debugUrl = URLDecoder.decode(url.toString()); + Log.i(TAG, debugUrl); + + final BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream()), 8192); + final StringBuilder response = new StringBuilder(); + String line; + + while ((line = in.readLine()) != null) { + response.append(line); + } + in.close(); return response.toString().replace("", "").replace("", ""); - } catch (MalformedURLException e) { - manager.onError(e); - } catch (IOException e) { - int responseCode = -1; - try { - if (uc != null) { - responseCode = ((HttpURLConnection)uc).getResponseCode(); - } - } catch (IOException e1) { } // do nothing, getResponse code failed so treat as default i/o exception. - if (uc != null && responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { - manager.onError(new HttpException(Integer.toString(HttpURLConnection.HTTP_UNAUTHORIZED))); - } else { - manager.onError(e); - } - } catch (NoSettingsException e) { - manager.onError(e); - } - return ""; - } - - /** - * Executes an HTTP API method and returns the result as string. - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @return Result - */ - public String getString(INotifiableManager manager, String method, String parameters) { - return query(method, parameters, manager).replaceAll(LINE_SEP, "").trim(); - } - - /** - * Executes an HTTP API method and returns the result as string. - * @param method Name of the method to run - * @return Result - */ - public String getString(INotifiableManager manager, String method) { - return getString(manager, method, ""); - } - - /** - * Executes an HTTP API method and returns the result as integer. - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @return Result - */ - public int getInt(INotifiableManager manager, String method, String parameters) { - try { - return Integer.parseInt(getString(manager, method, parameters)); - } catch (NumberFormatException e) { - return 0; - } - } - - /** - * Executes an HTTP API method without parameter and returns the result as - * integer. - * @param method Name of the method to run - * @return Result - */ - public int getInt(INotifiableManager manager, String method) { - return getInt(manager, method, ""); - } - - /** - * Executes an HTTP API method and makes sure the result is OK (or something - * like that) - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @throws WrongDataFormatException If not "OK" - */ - public boolean assertBoolean(INotifiableManager manager, String method, String parameters) throws WrongDataFormatException { - final String ret = query(method, parameters, manager); - if (ret.contains("OK") || ret.contains("true") || ret.contains("True") || ret.contains("TRUE")) { - return true; - } else if (ret.contains("false") || ret.contains("False") || ret.contains("FALSE")) { - return false; - } else { - throw new WrongDataFormatException("OK", ret); - } - } - - /** - * Executes an HTTP API method and makes sure the result is OK (or something - * like that) - * @param method Name of the method to run - * @throws WrongDataFormatException If not "OK" - */ - public boolean assertBoolean(INotifiableManager manager, String method) throws WrongDataFormatException { - return assertBoolean(manager, method, ""); - } - - /** - * Executes an HTTP API method and returns the result as boolean. - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @return Result - */ - public boolean getBoolean(INotifiableManager manager, String method, String parameters) { - try { - return assertBoolean(manager, method, parameters); - } catch (WrongDataFormatException e) { - return false; - } - } - - /** - * Executes an HTTP API method and returns the result as boolean. - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @return Result - */ - public boolean getBoolean(INotifiableManager manager, String method) { - return getBoolean(manager, method, ""); - } - - /** - * Executes an HTTP API method and returns the result in a list of strings. - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - */ - public ArrayList getArray(INotifiableManager manager, String method, String parameters) { - final String[] rows = query(method, parameters, manager).split(LINE_SEP); - final ArrayList result = new ArrayList(); - for (String row : rows) { - if (row.length() > 0) { - result.add(row.trim()); - } - } - return result; - } - - /** - * Executes an HTTP API method and returns the result as a list of - * key => value pairs - * @param method Name of the method to run - * @param parameters Parameters of the method, separated by ";" - * @return - */ - public HashMap getPairs(INotifiableManager manager, String method, String parameters) { - final String[] rows = query(method, parameters, manager).split(LINE_SEP); - final HashMap result = new HashMap(); - for (String row : rows) { - final String[] pair = row.split(PAIR_SEP, 2); - if (pair.length == 1) { - result.put(pair[0].trim(), ""); - } else if (pair.length == 2 && pair[0].trim().length() > 0) { - result.put(pair[0].trim(), pair[1].trim()); - } - } - return result; - } - - /** - * Executes an HTTP API method without parameter and returns the result as - * a list of key => value pairs - * @param method Name of the method to run - * @return - */ - public HashMap getPairs(INotifiableManager manager, String method) { - return getPairs(manager, method, ""); - } - - /** - * Create a new URLConnection with the request headers set, including authentication. - * - * @param url The request url - * @return URLConnection - * @throws IOException - */ - private URLConnection getUrlConnection(URL url) throws IOException { - final URLConnection uc = url.openConnection(); - uc.setConnectTimeout(SOCKET_CONNECTION_TIMEOUT); - uc.setReadTimeout(mSocketReadTimeout); - uc.setRequestProperty("Connection", "close"); - - if (authEncoded != null) { - uc.setRequestProperty("Authorization", "Basic " + authEncoded); - } - - return uc; - } - - public byte[] download(String pathToDownload) throws IOException, URISyntaxException { - try { - final URL url = new URL(pathToDownload); - final URLConnection uc = getUrlConnection(url); - - final InputStream is = uc.getInputStream(); - final InputStreamReader isr = new InputStreamReader(is); - final BufferedReader rd = new BufferedReader(isr, 8192); - - final StringBuilder sb = new StringBuilder(); - String line = ""; - while ((line = rd.readLine()) != null) { - sb.append(line); - } - - rd.close(); - return Base64.decode(sb.toString().replace("", "").replace("", "")); - } catch (Exception e) { - return null; - } - } - - /** - * Removes the trailing "" string from the value - * @param value - * @return Trimmed value - */ - public static String trim(String value) { - return new String(value.replace("", "").replace("", "").replace("", "").toCharArray()); - } - - /** - * Removes the trailing "" string from the value and tries to - * parse an integer from it. On error, returns -1. - * @param value - * @return Parsed integer from field value - */ - public static int trimInt(String value) { - String trimmed = trim(value); - if (trimmed.length() > 0) { - try { - return Integer.parseInt(trimmed.replace(",", "")); - } catch (NumberFormatException e) { - return -1; - } - } else { - return -1; - } - } - - /** - * Removes the trailing "" string from the value and tries to - * parse a double from it. On error, returns -1.0. - * @param value - * @return Parsed double from field value - */ - public static double trimDouble(String value) { - String trimmed = trim(value); - if (trimmed.length() > 0) { - try { - return Double.parseDouble(trimmed); - } catch (NumberFormatException e) { - return -1.0; - } - } else { - return -1.0; - } - } - - /** - * Removes the trailing "" string from the value and tries to - * parse a boolean from it. - * @param value - * @return Parsed boolean from field value - */ - public static boolean trimBoolean(String value) { - String trimmed = trim(value); - if (trimmed.length() > 0) { - if (trimmed.startsWith("0") || trimmed.toLowerCase().startsWith("false")) { - return false; - } - if (trimmed.startsWith("1") || trimmed.toLowerCase().startsWith("true")) { - return true; - } - } - return false; - } - - public static final String LINE_SEP = "
  • "; - public static final String VALUE_SEP = ";"; - public static final String PAIR_SEP = ":"; -} + } catch (MalformedURLException e) { + manager.onError(e); + } catch (IOException e) { + int responseCode = -1; + try { + if (uc != null) { + responseCode = ((HttpURLConnection) uc).getResponseCode(); + } + } catch (IOException e1) { + } // do nothing, getResponse code failed so treat as default i/o exception. + if (uc != null && responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { + manager.onError(new HttpException(Integer.toString(HttpURLConnection.HTTP_UNAUTHORIZED))); + } else { + manager.onError(e); + } + } catch (NoSettingsException e) { + manager.onError(e); + } + return ""; + } + + /** + * Executes an HTTP API method and returns the result as string. + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + * @return Result + */ + public String getString(INotifiableManager manager, String method, String parameters) { + return query(method, parameters, manager).replaceAll(LINE_SEP, "").trim(); + } + + /** + * Executes an HTTP API method and returns the result as string. + * + * @param method Name of the method to run + * @return Result + */ + public String getString(INotifiableManager manager, String method) { + return getString(manager, method, ""); + } + + /** + * Executes an HTTP API method and returns the result as integer. + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + * @return Result + */ + public int getInt(INotifiableManager manager, String method, String parameters) { + try { + return Integer.parseInt(getString(manager, method, parameters)); + } catch (NumberFormatException e) { + return 0; + } + } + + /** + * Executes an HTTP API method without parameter and returns the result as + * integer. + * + * @param method Name of the method to run + * @return Result + */ + public int getInt(INotifiableManager manager, String method) { + return getInt(manager, method, ""); + } + + /** + * Executes an HTTP API method and makes sure the result is OK (or something + * like that) + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + * @throws WrongDataFormatException If not "OK" + */ + public boolean assertBoolean(INotifiableManager manager, String method, String parameters) throws + WrongDataFormatException { + final String ret = query(method, parameters, manager); + if (ret.contains("OK") || ret.contains("true") || ret.contains("True") || ret.contains("TRUE")) { + return true; + } else if (ret.contains("false") || ret.contains("False") || ret.contains("FALSE")) { + return false; + } else { + throw new WrongDataFormatException("OK", ret); + } + } + + /** + * Executes an HTTP API method and makes sure the result is OK (or something + * like that) + * + * @param method Name of the method to run + * @throws WrongDataFormatException If not "OK" + */ + public boolean assertBoolean(INotifiableManager manager, String method) throws WrongDataFormatException { + return assertBoolean(manager, method, ""); + } + + /** + * Executes an HTTP API method and returns the result as boolean. + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + * @return Result + */ + public boolean getBoolean(INotifiableManager manager, String method, String parameters) { + try { + return assertBoolean(manager, method, parameters); + } catch (WrongDataFormatException e) { + return false; + } + } + + /** + * Executes an HTTP API method and returns the result as boolean. + * + * @param method Name of the method to run + * @return Result + */ + public boolean getBoolean(INotifiableManager manager, String method) { + return getBoolean(manager, method, ""); + } + + /** + * Executes an HTTP API method and returns the result in a list of strings. + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + */ + public ArrayList getArray(INotifiableManager manager, String method, String parameters) { + final String[] rows = query(method, parameters, manager).split(LINE_SEP); + final ArrayList result = new ArrayList(); + for (String row : rows) { + if (row.length() > 0) { + result.add(row.trim()); + } + } + return result; + } + + /** + * Executes an HTTP API method and returns the result as a list of + * key => value pairs + * + * @param method Name of the method to run + * @param parameters Parameters of the method, separated by ";" + * @return + */ + public HashMap getPairs(INotifiableManager manager, String method, String parameters) { + final String[] rows = query(method, parameters, manager).split(LINE_SEP); + final HashMap result = new HashMap(); + for (String row : rows) { + final String[] pair = row.split(PAIR_SEP, 2); + if (pair.length == 1) { + result.put(pair[0].trim(), ""); + } else if (pair.length == 2 && pair[0].trim().length() > 0) { + result.put(pair[0].trim(), pair[1].trim()); + } + } + return result; + } + + /** + * Executes an HTTP API method without parameter and returns the result as + * a list of key => value pairs + * + * @param method Name of the method to run + * @return + */ + public HashMap getPairs(INotifiableManager manager, String method) { + return getPairs(manager, method, ""); + } + + /** + * Create a new URLConnection with the request headers set, including authentication. + * + * @param url The request url + * @return URLConnection + * @throws IOException + */ + private URLConnection getUrlConnection(URL url) throws IOException { + final URLConnection uc = url.openConnection(); + uc.setConnectTimeout(SOCKET_CONNECTION_TIMEOUT); + uc.setReadTimeout(mSocketReadTimeout); + uc.setRequestProperty("Connection", "close"); + + if (authEncoded != null) { + uc.setRequestProperty("Authorization", "Basic " + authEncoded); + } + + return uc; + } + + public byte[] download(String pathToDownload) throws IOException, URISyntaxException { + try { + final URL url = new URL(pathToDownload); + final URLConnection uc = getUrlConnection(url); + + final InputStream is = uc.getInputStream(); + final InputStreamReader isr = new InputStreamReader(is); + final BufferedReader rd = new BufferedReader(isr, 8192); + + final StringBuilder sb = new StringBuilder(); + String line = ""; + while ((line = rd.readLine()) != null) { + sb.append(line); + } + + rd.close(); + return Base64.decode(sb.toString().replace("", "").replace("", "")); + } catch (Exception e) { + return null; + } + } +} diff --git a/src/org/xbmc/httpapi/HttpApi.java b/app/src/main/java/org/xbmc/httpapi/HttpApi.java similarity index 99% rename from src/org/xbmc/httpapi/HttpApi.java rename to app/src/main/java/org/xbmc/httpapi/HttpApi.java index d6c3986a..387185d9 100644 --- a/src/org/xbmc/httpapi/HttpApi.java +++ b/app/src/main/java/org/xbmc/httpapi/HttpApi.java @@ -32,38 +32,39 @@ * Wrapper class for our HTTP clients. The idea is to separate the loads of * API method we're going to have into separate classes. The HttpClient class * instantiates them and keeps them in a central place. - * + * * @author Team XBMC */ public class HttpApi { - + /** * Use this client for anything system related */ public final InfoClient info; - + /** * Use this client for anything music related */ public final MusicClient music; - + /** * Use this client for anything video related */ public final VideoClient video; - + /** * Use this client for anything media controller related */ public final ControlClient control; - + /** * Use this client for anything tv show related */ public final TvShowClient shows; - + /** * Construct with all paramaters + * * @param host Connection data of the host * @param timeout Read timeout */ @@ -82,9 +83,10 @@ public HttpApi(Host host, int timeout) { control = new ControlClient(connection); shows = new TvShowClient(connection); } - + /** * Updates host info on all clients + * * @param host */ public void setHost(Host host) { diff --git a/src/org/xbmc/httpapi/NoNetworkException.java b/app/src/main/java/org/xbmc/httpapi/NoNetworkException.java similarity index 96% rename from src/org/xbmc/httpapi/NoNetworkException.java rename to app/src/main/java/org/xbmc/httpapi/NoNetworkException.java index 1e57b9f4..111b5874 100644 --- a/src/org/xbmc/httpapi/NoNetworkException.java +++ b/app/src/main/java/org/xbmc/httpapi/NoNetworkException.java @@ -1,34 +1,35 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi; - -/** - * Throw this exception if network is not available on the device - * - * @author Team XBMC - */ -public class NoNetworkException extends Exception { - private static final long serialVersionUID = -300859290934884233L; - public NoNetworkException() { - super("This application requires network access. Enable mobile network or Wi-Fi to download data."); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi; + +/** + * Throw this exception if network is not available on the device + * + * @author Team XBMC + */ +public class NoNetworkException extends Exception { + private static final long serialVersionUID = -300859290934884233L; + + public NoNetworkException() { + super("This application requires network access. Enable mobile network or Wi-Fi to download data."); + } +} diff --git a/src/org/xbmc/httpapi/NoSettingsException.java b/app/src/main/java/org/xbmc/httpapi/NoSettingsException.java similarity index 92% rename from src/org/xbmc/httpapi/NoSettingsException.java rename to app/src/main/java/org/xbmc/httpapi/NoSettingsException.java index b10ba8b6..3c1e951f 100644 --- a/src/org/xbmc/httpapi/NoSettingsException.java +++ b/app/src/main/java/org/xbmc/httpapi/NoSettingsException.java @@ -1,36 +1,38 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi; - -/** - * Throw this exception if setting values were empty. - * - * @author Team XBMC - */ -public class NoSettingsException extends Exception { - - private static final long serialVersionUID = -5024397978225112156L; - - public NoSettingsException() { - super("Click on \"Settings\" or use the menu in order to add an XBMC host or IP address to your configuration."); - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi; + +/** + * Throw this exception if setting values were empty. + * + * @author Team XBMC + */ +public class NoSettingsException extends Exception { + + private static final long serialVersionUID = -5024397978225112156L; + + public NoSettingsException() { + super("Click on \"Settings\" or use the menu in order to add an XBMC host or IP address to your " + + "configuration" + + "."); + } +} diff --git a/src/org/xbmc/httpapi/WifiStateException.java b/app/src/main/java/org/xbmc/httpapi/WifiStateException.java similarity index 98% rename from src/org/xbmc/httpapi/WifiStateException.java rename to app/src/main/java/org/xbmc/httpapi/WifiStateException.java index b185cebf..dd56f729 100644 --- a/src/org/xbmc/httpapi/WifiStateException.java +++ b/app/src/main/java/org/xbmc/httpapi/WifiStateException.java @@ -3,11 +3,11 @@ public class WifiStateException extends Exception { /** - * + * */ private static final long serialVersionUID = 3588074771970912287L; private int state; - + public WifiStateException(int state) { this.state = state; } diff --git a/src/org/xbmc/httpapi/WrongDataFormatException.java b/app/src/main/java/org/xbmc/httpapi/WrongDataFormatException.java similarity index 96% rename from src/org/xbmc/httpapi/WrongDataFormatException.java rename to app/src/main/java/org/xbmc/httpapi/WrongDataFormatException.java index 5821be11..17969209 100644 --- a/src/org/xbmc/httpapi/WrongDataFormatException.java +++ b/app/src/main/java/org/xbmc/httpapi/WrongDataFormatException.java @@ -1,44 +1,47 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi; - -/** - * Throw this exception if API response is something different than expected. - * - * @author Team XBMC - */ -public class WrongDataFormatException extends Exception { - private static final long serialVersionUID = 42438942451326636L; - private String mExpected; - private String mReceived; - public WrongDataFormatException(String expected, String received) { - super("Wrong data format, expected '" + expected + "', got '" + received + "'."); - mExpected = expected; - mReceived = received; - } - public String getExpected() { - return mExpected; - } - public String getReceived() { - return mReceived; - } +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi; + +/** + * Throw this exception if API response is something different than expected. + * + * @author Team XBMC + */ +public class WrongDataFormatException extends Exception { + private static final long serialVersionUID = 42438942451326636L; + private String mExpected; + private String mReceived; + + public WrongDataFormatException(String expected, String received) { + super("Wrong data format, expected '" + expected + "', got '" + received + "'."); + mExpected = expected; + mReceived = received; + } + + public String getExpected() { + return mExpected; + } + + public String getReceived() { + return mReceived; + } } \ No newline at end of file diff --git a/src/org/xbmc/httpapi/client/Client.java b/app/src/main/java/org/xbmc/httpapi/client/Client.java similarity index 84% rename from src/org/xbmc/httpapi/client/Client.java rename to app/src/main/java/org/xbmc/httpapi/client/Client.java index 30946552..57879485 100644 --- a/src/org/xbmc/httpapi/client/Client.java +++ b/app/src/main/java/org/xbmc/httpapi/client/Client.java @@ -1,278 +1,286 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC Remote; see the file license. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -package org.xbmc.httpapi.client; - -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -import org.xbmc.android.util.Base64; -import org.xbmc.android.util.ClientFactory; -import org.xbmc.android.util.ImportUtilities; -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.object.ICoverArt; -import org.xbmc.api.type.ThumbSize; -import org.xbmc.api.type.ThumbSize.Dimension; -import org.xbmc.httpapi.Connection; - -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Bitmap.CompressFormat; -import android.util.Log; - -/** - * Abstract super class of all (media) clients. - * - * @author Team XBMC - */ -abstract class Client { - - public static final String TAG = "Client-HTTPAPI"; - - protected final Connection mConnection; - - /** - * Class constructor needs reference to HTTP client connection - * @param connection - */ - Client(Connection connection) { - mConnection = connection; - } - - /** - * Downloads a cover. - * - * Since base64-download is a REAL pita, we'll check for XBMC revision and - * dispatch to direct download via the /thumbs accessor if possible. - * - * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. - * @param url URL to primary cover - * @param fallbackUrl URL to fallback cover - * @return Bitmap - */ - protected Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size, String url, String fallbackUrl) { - try { - if (ClientFactory.XBMC_REV >= ClientFactory.MICROHTTPD_REV) { - return getCoverFromMicroHTTPd(manager, cover, size, url, fallbackUrl); - } else { - return getCoverFromLibGoAhead(manager, cover, size, url, fallbackUrl); - } - } catch (OutOfMemoryError e) { - manager.onError(new Exception("Out of memory. We're aware of this problem and we're working on it. Restarting the app should help.")); - return null; - } - } - - - /** - * Downloads a cover "the old way", meaning the base64-encoded result is - * stored in a String and decoded from there. I've tried using a - * Base64.InputStream directly with libgoahead crashing as a result. - * - * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. - * @param url URL to primary cover - * @param fallbackUrl URL to fallback cover - * @return Bitmap - */ - private Bitmap getCoverFromLibGoAhead(INotifiableManager manager, ICoverArt cover, int size, String url, String fallbackUrl) { - final int mediaType = cover.getMediaType(); - - // don't fetch small sizes - size = size < ThumbSize.BIG ? ThumbSize.MEDIUM : ThumbSize.BIG; - try { - String b64enc = mConnection.query("FileDownload", url, manager); - if (b64enc.length() <= 0) { - if (fallbackUrl != null) { - Log.i(TAG, "*** Downloaded cover has size null, retrying with fallback:"); - b64enc = mConnection.query("FileDownload", fallbackUrl, manager); - } else { - b64enc = null; - } - } - if (b64enc != null) { - byte[] bytes = Base64.decode(b64enc); - - if (bytes.length > 0) { - final BitmapFactory.Options opts = prefetch(manager, bytes, size); - final Dimension dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); - final int ss = ImportUtilities.calculateSampleSize(opts, dim); - opts.inDither = true; - opts.inSampleSize = ss; - opts.inJustDecodeBounds = false; - - Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); - if (ss == 1) { - bitmap = blowup(bitmap); - } - return bitmap; - } - } - } catch (IOException e) { - e.printStackTrace(); - } - return null; - } - - /** - * Downloads a cover using microhttpd. - * - * First, only boundaries are downloaded in order to determine the sample - * size. Setting sample size > 1 will do two things: - *
    1. Only a fragment of the total size will be downloaded
    2. - *
    3. Resizing will be smooth and not pixelated as before
    - * There is no base64-decoding since we're accessing the /thumb accessor - * directly. The returned size is the next bigger (but smaller than the - * double) size of the original image. - * - * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. - * @param url URL to primary cover - * @param fallbackUrl URL to fallback cover - * @return Bitmap - */ - private Bitmap getCoverFromMicroHTTPd(INotifiableManager manager, ICoverArt cover, int size, String url, String fallbackUrl) { - final int mediaType = cover.getMediaType(); - // don't fetch small sizes - size = size < ThumbSize.BIG ? ThumbSize.MEDIUM : ThumbSize.BIG; - InputStream is = null; - try { - - Log.i(TAG, "Starting download (" + url + ") - microhttpd"); - BitmapFactory.Options opts = prefetch(manager, url, size); - Dimension dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); - - Log.i(TAG, "Pre-fetch: " + opts.outWidth + "x" + opts.outHeight + " => " + dim); - if (opts.outWidth < 1) { - if (fallbackUrl != null) { - Log.i(TAG, "Starting fallback download (" + fallbackUrl + ")"); - opts = prefetch(manager, fallbackUrl, size); - dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); - Log.i(TAG, "FALLBACK-Pre-fetch: " + opts.outWidth + "x" + opts.outHeight + " => " + dim); - if (opts.outWidth < 1) { - return null; - } else { - url = fallbackUrl; - } - } else { - Log.i(TAG, "Fallback url is null, returning null-bitmap"); - return null; - } - } - final int ss = ImportUtilities.calculateSampleSize(opts, dim); - Log.i(TAG, "Sample size: " + ss); - - is = new BufferedInputStream(mConnection.getThumbInputStreamForMicroHTTPd(url, manager), 8192); - opts.inDither = true; - opts.inSampleSize = ss; - opts.inJustDecodeBounds = false; - - Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts); - if (ss == 1) { - bitmap = blowup(bitmap); - } - is.close(); - if (bitmap == null) { - Log.i(TAG, "Fetch: Bitmap is null!!"); - return null; - } else { - Log.i(TAG, "Fetch: Bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight()); - return bitmap; - } - } catch (FileNotFoundException e) { - Log.i(TAG, "Fetch: Bitmap not found"); - - } catch (IOException e) { - manager.onError(e); - e.printStackTrace(); - } finally { - try { - if (is != null) { - is.close(); - } - } catch (IOException e) { } - } - return null; - } - - /** - * Only downloads as much as boundaries of the image in order to find out - * its size. - * @param manager Postback manager - * @param url URL to primary cover - * @param size Minmal size to pre-resize to. - * @return - */ - private BitmapFactory.Options prefetch(INotifiableManager manager, String url, int size) { - BitmapFactory.Options opts = new BitmapFactory.Options(); - try { - InputStream is = new BufferedInputStream(mConnection.getThumbInputStreamForMicroHTTPd(url, manager), 8192); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeStream(is, null, opts); - } catch (FileNotFoundException e) { - return opts; - } - return opts; - } - - /** - * Only decodes as much as boundaries of the image in order to find out - * its size. - * @param manager Postback manager - * @param data Image data as byte array - * @param size Minmal size to pre-resize to. - * @return - */ - private BitmapFactory.Options prefetch(INotifiableManager manager, byte[] data, int size) { - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inJustDecodeBounds = true; - BitmapFactory.decodeByteArray(data, 0, data.length, opts); - return opts; - } - - /** - * Doubles the size of a bitmap and re-reads it with samplesize 2. I've - * found no other way to smoothely resize images with samplesize = 1. - * @param source - * @return - */ - private Bitmap blowup(Bitmap source) { - if (source != null) { - Bitmap big = Bitmap.createScaledBitmap(source, source.getWidth() * 2, source.getHeight() * 2, true); - BitmapFactory.Options opts = new BitmapFactory.Options(); - opts.inSampleSize = 2; - - ByteArrayOutputStream os = new ByteArrayOutputStream(); - big.compress(CompressFormat.PNG, 100, os); - - byte[] array = os.toByteArray(); - return BitmapFactory.decodeByteArray(array, 0, array.length, opts); - } - return null; - } -} +/* + * Copyright (C) 2005-2009 Team XBMC + * http://xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC Remote; see the file license. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +package org.xbmc.httpapi.client; + +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.util.Log; + +import org.xbmc.android.util.Base64; +import org.xbmc.android.util.ClientFactory; +import org.xbmc.android.util.ImportUtilities; +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.object.ICoverArt; +import org.xbmc.api.type.ThumbSize; +import org.xbmc.api.type.ThumbSize.Dimension; +import org.xbmc.httpapi.Connection; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +/** + * Abstract super class of all (media) clients. + * + * @author Team XBMC + */ +abstract class Client { + + public static final String TAG = "Client-HTTPAPI"; + + protected final Connection mConnection; + + /** + * Class constructor needs reference to HTTP client connection + * + * @param connection + */ + Client(Connection connection) { + mConnection = connection; + } + + /** + * Downloads a cover. + *

    + * Since base64-download is a REAL pita, we'll check for XBMC revision and + * dispatch to direct download via the /thumbs accessor if possible. + * + * @param manager Postback manager + * @param cover Cover object + * @param size Minmal size to pre-resize to. + * @param url URL to primary cover + * @param fallbackUrl URL to fallback cover + * @return Bitmap + */ + protected Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size, String url, String fallbackUrl) { + try { + if (ClientFactory.XBMC_REV >= ClientFactory.MICROHTTPD_REV) { + return getCoverFromMicroHTTPd(manager, cover, size, url, fallbackUrl); + } else { + return getCoverFromLibGoAhead(manager, cover, size, url, fallbackUrl); + } + } catch (OutOfMemoryError e) { + manager.onError(new Exception("Out of memory. We're aware of this problem and we're working on it. " + + "Restarting the app should help.")); + return null; + } + } + + + /** + * Downloads a cover "the old way", meaning the base64-encoded result is + * stored in a String and decoded from there. I've tried using a + * Base64.InputStream directly with libgoahead crashing as a result. + * + * @param manager Postback manager + * @param cover Cover object + * @param size Minmal size to pre-resize to. + * @param url URL to primary cover + * @param fallbackUrl URL to fallback cover + * @return Bitmap + */ + private Bitmap getCoverFromLibGoAhead(INotifiableManager manager, ICoverArt cover, int size, String url, + String fallbackUrl) { + final int mediaType = cover.getMediaType(); + + // don't fetch small sizes + size = size < ThumbSize.BIG ? ThumbSize.MEDIUM : ThumbSize.BIG; + try { + String b64enc = mConnection.query("FileDownload", url, manager); + if (b64enc.length() <= 0) { + if (fallbackUrl != null) { + Log.i(TAG, "*** Downloaded cover has size null, retrying with fallback:"); + b64enc = mConnection.query("FileDownload", fallbackUrl, manager); + } else { + b64enc = null; + } + } + if (b64enc != null) { + byte[] bytes = Base64.decode(b64enc); + + if (bytes.length > 0) { + final BitmapFactory.Options opts = prefetch(manager, bytes, size); + final Dimension dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); + final int ss = ImportUtilities.calculateSampleSize(opts, dim); + opts.inDither = true; + opts.inSampleSize = ss; + opts.inJustDecodeBounds = false; + + Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); + if (ss == 1) { + bitmap = blowup(bitmap); + } + return bitmap; + } + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + /** + * Downloads a cover using microhttpd. + *

    + * First, only boundaries are downloaded in order to determine the sample + * size. Setting sample size > 1 will do two things: + *

    1. Only a fragment of the total size will be downloaded
    2. + *
    3. Resizing will be smooth and not pixelated as before
    + * There is no base64-decoding since we're accessing the /thumb accessor + * directly. The returned size is the next bigger (but smaller than the + * double) size of the original image. + * + * @param manager Postback manager + * @param cover Cover object + * @param size Minmal size to pre-resize to. + * @param url URL to primary cover + * @param fallbackUrl URL to fallback cover + * @return Bitmap + */ + private Bitmap getCoverFromMicroHTTPd(INotifiableManager manager, ICoverArt cover, int size, String url, + String fallbackUrl) { + final int mediaType = cover.getMediaType(); + // don't fetch small sizes + size = size < ThumbSize.BIG ? ThumbSize.MEDIUM : ThumbSize.BIG; + InputStream is = null; + try { + + Log.i(TAG, "Starting download (" + url + ") - microhttpd"); + BitmapFactory.Options opts = prefetch(manager, url, size); + Dimension dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); + + Log.i(TAG, "Pre-fetch: " + opts.outWidth + "x" + opts.outHeight + " => " + dim); + if (opts.outWidth < 1) { + if (fallbackUrl != null) { + Log.i(TAG, "Starting fallback download (" + fallbackUrl + ")"); + opts = prefetch(manager, fallbackUrl, size); + dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); + Log.i(TAG, "FALLBACK-Pre-fetch: " + opts.outWidth + "x" + opts.outHeight + " => " + dim); + if (opts.outWidth < 1) { + return null; + } else { + url = fallbackUrl; + } + } else { + Log.i(TAG, "Fallback url is null, returning null-bitmap"); + return null; + } + } + final int ss = ImportUtilities.calculateSampleSize(opts, dim); + Log.i(TAG, "Sample size: " + ss); + + is = new BufferedInputStream(mConnection.getThumbInputStreamForMicroHTTPd(url, manager), 8192); + opts.inDither = true; + opts.inSampleSize = ss; + opts.inJustDecodeBounds = false; + + Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts); + if (ss == 1) { + bitmap = blowup(bitmap); + } + is.close(); + if (bitmap == null) { + Log.i(TAG, "Fetch: Bitmap is null!!"); + return null; + } else { + Log.i(TAG, "Fetch: Bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight()); + return bitmap; + } + } catch (FileNotFoundException e) { + Log.i(TAG, "Fetch: Bitmap not found"); + + } catch (IOException e) { + manager.onError(e); + e.printStackTrace(); + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + } + } + return null; + } + + /** + * Only downloads as much as boundaries of the image in order to find out + * its size. + * + * @param manager Postback manager + * @param url URL to primary cover + * @param size Minmal size to pre-resize to. + * @return + */ + private BitmapFactory.Options prefetch(INotifiableManager manager, String url, int size) { + BitmapFactory.Options opts = new BitmapFactory.Options(); + try { + InputStream is = new BufferedInputStream(mConnection.getThumbInputStreamForMicroHTTPd(url, manager), 8192); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeStream(is, null, opts); + } catch (FileNotFoundException e) { + return opts; + } + return opts; + } + + /** + * Only decodes as much as boundaries of the image in order to find out + * its size. + * + * @param manager Postback manager + * @param data Image data as byte array + * @param size Minmal size to pre-resize to. + * @return + */ + private BitmapFactory.Options prefetch(INotifiableManager manager, byte[] data, int size) { + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeByteArray(data, 0, data.length, opts); + return opts; + } + + /** + * Doubles the size of a bitmap and re-reads it with samplesize 2. I've + * found no other way to smoothely resize images with samplesize = 1. + * + * @param source + * @return + */ + private Bitmap blowup(Bitmap source) { + if (source != null) { + Bitmap big = Bitmap.createScaledBitmap(source, source.getWidth() * 2, source.getHeight() * 2, true); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = 2; + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + big.compress(CompressFormat.PNG, 100, os); + + byte[] array = os.toByteArray(); + return BitmapFactory.decodeByteArray(array, 0, array.length, opts); + } + return null; + } +} diff --git a/src/org/xbmc/httpapi/client/ControlClient.java b/app/src/main/java/org/xbmc/httpapi/client/ControlClient.java similarity index 81% rename from src/org/xbmc/httpapi/client/ControlClient.java rename to app/src/main/java/org/xbmc/httpapi/client/ControlClient.java index 42f1c0ab..77afb7c3 100644 --- a/src/org/xbmc/httpapi/client/ControlClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/ControlClient.java @@ -21,8 +21,6 @@ package org.xbmc.httpapi.client; -import java.util.HashMap; - import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.data.IControlClient; import org.xbmc.api.info.GuiActions; @@ -34,12 +32,14 @@ import org.xbmc.httpapi.Connection; import org.xbmc.httpapi.WrongDataFormatException; +import java.util.HashMap; + /** * The ControlClient class takes care of everything related to controlling * XBMC. These are essentially play controls, navigation controls other actions * the user may wants to execute. It equally reads the information instead of * setting it. - * + * * @author Team XBMC */ public class ControlClient implements IControlClient { @@ -48,43 +48,48 @@ public class ControlClient implements IControlClient { /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public ControlClient(Connection connection) { mConnection = connection; } - + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - + /** * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. - * @param manager Manager reference + * + * @param manager Manager reference * @param fileOrFolder * @return true on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, String fileOrFolder, int playlistId) { return mConnection.getBoolean(manager, "AddToPlayList", fileOrFolder); } - + /** * Starts playing the media file filename . - * @param manager Manager reference + * + * @param manager Manager reference * @param filename File to play * @return true on success, false otherwise. */ public boolean playFile(INotifiableManager manager, String filename, int playlistId) { return mConnection.getBoolean(manager, "PlayFile", filename); } - + /** * Starts playing/showing the next media/image in the current playlist or, - * if currently showing a slideshow, the slideshow playlist. + * if currently showing a slideshow, the slideshow playlist. + * * @param manager Manager reference * @return true on success, false otherwise. */ @@ -95,92 +100,100 @@ public boolean playNext(INotifiableManager manager) { /** * Starts playing/showing the previous media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean playPrevious(INotifiableManager manager) { return mConnection.getBoolean(manager, "PlayPrev"); } - + /** - * Pauses the currently playing media. + * Pauses the currently playing media. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean pause(INotifiableManager manager) { return mConnection.getBoolean(manager, "Pause"); } - + /** - * Stops the currently playing media. + * Stops the currently playing media. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean stop(INotifiableManager manager) { return mConnection.getBoolean(manager, "Stop"); } - + /** * Start playing the media file at the given URL + * * @param manager Manager reference - * @param url An URL pointing to a supported media file + * @param url An URL pointing to a supported media file * @return true on success, false otherwise. */ public boolean playUrl(INotifiableManager manager, String url) { return mConnection.getBoolean(manager, "ExecBuiltin", "PlayMedia(" + url + ")"); } - + /** * Show the picture file filename . - * @param manager Manager reference + * + * @param manager Manager reference * @param filename File to show * @return true on success, false otherwise. */ public boolean showPicture(INotifiableManager manager, String filename) { mConnection.getBoolean(manager, "ClearSlideshow"); - mConnection.getBoolean(manager, "PlaySlideshow", filename.substring(0, filename.replaceAll("\\\\", "/").lastIndexOf("/") ) + ";false"); - mConnection.getBoolean(manager, "SlideshowSelect", filename ); + mConnection.getBoolean(manager, "PlaySlideshow", filename.substring(0, filename.replaceAll("\\\\", + "/").lastIndexOf("/")) + ";false"); + mConnection.getBoolean(manager, "SlideshowSelect", filename); return playNext(manager); - + } - + /** * Send the string text via keys on the virtual keyboard. + * * @param manager Manager reference - * @param text The text string to send. + * @param text The text string to send. * @return true on success, false otherwise. */ public boolean sendText(INotifiableManager manager, String text) { final int codeOffset = 0xf100; for (char c : text.toCharArray()) { - int code = (int)c+codeOffset; - if (! mConnection.getBoolean(manager, "SendKey", Integer.toString(code))) { + int code = (int) c + codeOffset; + if (!mConnection.getBoolean(manager, "SendKey", Integer.toString(code))) { return false; } } return true; } - + /** * Sets the volume as a percentage of the maximum possible. + * * @param manager Manager reference - * @param volume New volume (0-100) + * @param volume New volume (0-100) * @return true on success, false otherwise. */ public boolean setVolume(INotifiableManager manager, int volume) { return mConnection.getBoolean(manager, "SetVolume", String.valueOf(volume)); } - + /** * Seeks to a position. If type is *
      - *
    • absolute - Sets the playing position of the currently - * playing media as a percentage of the media�s length.
    • - *
    • relative - Adds/Subtracts the current percentage on to - * the current position in the song
    • - *
    - * - * @param manager Manager reference + *
  • absolute - Sets the playing position of the currently + * playing media as a percentage of the media�s length.
  • + *
  • relative - Adds/Subtracts the current percentage on to + * the current position in the song
  • + * + * + * @param manager Manager reference * @param type Seek type, relative or absolute * @param progress Progress * @return true on success, false otherwise. @@ -191,38 +204,42 @@ public boolean seek(INotifiableManager manager, SeekType type, int progress) { else return mConnection.getBoolean(manager, "SeekPercentageRelative", String.valueOf(progress)); } - + /** * Toggles the sound on/off. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean mute(INotifiableManager manager) { return mConnection.getBoolean(manager, "Mute"); } - + /** * Retrieves the current playing position of the currently playing media as - * a percentage of the media's length. + * a percentage of the media's length. + * * @param manager Manager reference * @return Percentage (0-100) */ public int getPercentage(INotifiableManager manager) { return mConnection.getInt(manager, "GetPercentage"); } - + /** - * Retrieves the current volume setting as a percentage of the maximum + * Retrieves the current volume setting as a percentage of the maximum * possible value. + * * @param manager Manager reference * @return Volume (0-100) */ public int getVolume(INotifiableManager manager) { return mConnection.getInt(manager, "GetVolume"); } - + /** * Navigates... UP! + * * @param manager Manager reference * @return true on success, false otherwise. */ @@ -232,56 +249,61 @@ public boolean navUp(INotifiableManager manager) { /** * Navigates... DOWN! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navDown(INotifiableManager manager) { return mConnection.getBoolean(manager, "Action", String.valueOf(GuiActions.ACTION_MOVE_DOWN)); } - + /** * Navigates... LEFT! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navLeft(INotifiableManager manager) { return mConnection.getBoolean(manager, "Action", String.valueOf(GuiActions.ACTION_MOVE_LEFT)); } - + /** * Navigates... RIGHT! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navRight(INotifiableManager manager) { return mConnection.getBoolean(manager, "Action", String.valueOf(GuiActions.ACTION_MOVE_RIGHT)); } - + /** * Selects current item. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navSelect(INotifiableManager manager) { return mConnection.getBoolean(manager, "Action", String.valueOf(GuiActions.ACTION_SELECT_ITEM)); } - + /** - * Takes either "video" or "music" as a parameter to begin updating the - * corresponding database. - * + * Takes either "video" or "music" as a parameter to begin updating the + * corresponding database. + *

    * TODO For "video" you can additionally specify a specific path to be scanned. - * - * @param manager Manager reference + * + * @param manager Manager reference * @param mediaType Either video or music. * @return True on success, false otherwise. */ public boolean updateLibrary(INotifiableManager manager, String mediaType) { return mConnection.getBoolean(manager, "ExecBuiltin", "UpdateLibrary(" + mediaType + ")"); } - + /** - * Broadcast a message. Used to test broadcasting feature. + * Broadcast a message. Used to test broadcasting feature. + * * @param manager Manager reference * @param message * @return True on success, false otherwise. @@ -289,9 +311,10 @@ public boolean updateLibrary(INotifiableManager manager, String mediaType) { public boolean broadcast(INotifiableManager manager, String message) { return mConnection.getBoolean(manager, "Broadcast", message); } - + /** * Returns the current broadcast port number, or 0 if deactivated. + * * @param manager Manager reference * @return Current broadcast port number. */ @@ -304,18 +327,18 @@ public int getBroadcast(INotifiableManager manager) { return 0; } } - + /** * Sets the brodcast level and port. Level currently only takes three values: - *

      - *
    • 0 - No broadcasts
    • - *
    • 1 - Media playback and startup & shutdown events - *
    • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. - *
    - * - * @param manager Manager reference - * @param port Broadcast port - * @param level Broadcast level + *
      + *
    • 0 - No broadcasts
    • + *
    • 1 - Media playback and startup & shutdown events + *
    • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. + *
    + * + * @param manager Manager reference + * @param port Broadcast port + * @param level Broadcast level * @return True on success, false otherwise. */ public boolean setBroadcast(INotifiableManager manager, int port, int level) { @@ -324,63 +347,71 @@ public boolean setBroadcast(INotifiableManager manager, int port, int level) { /** * Returns current play state + * * @param manager Manager reference * @return */ public int getPlayState(INotifiableManager manager) { return PlayStatus.parse(mConnection.getString(manager, "GetCurrentlyPlaying")); } - + /** * Returns the current playlist identifier + * * @param manager Manager reference */ public int getPlaylistId(INotifiableManager manager) { return mConnection.getInt(manager, "GetCurrentPlaylist"); } - + /** * Sets the current playlist identifier + * * @param manager Manager reference - * @param id Playlist identifier + * @param id Playlist identifier * @return True on success, false otherwise. */ public boolean setPlaylistId(INotifiableManager manager, int id) { return mConnection.getBoolean(manager, "SetCurrentPlaylist", String.valueOf(id)); } - + /** * Sets the current playlist position - * @param manager Manager reference + * + * @param manager Manager reference * @param position New playlist position * @return True on success, false otherwise. */ public boolean setPlaylistPos(INotifiableManager manager, int playlistId, int position) { return mConnection.getBoolean(manager, "SetPlaylistSong", String.valueOf(position)); } - + /** * Clears a playlist. - * @param manager Manager reference - * @param int Playlist to clear (0 = music, 1 = video) + * + * @param manager Manager reference + * @param playlistId Playlist to clear (0 = music, 1 = video) * @return True on success, false otherwise. */ public boolean clearPlaylist(INotifiableManager manager, int playlistId) { return mConnection.getBoolean(manager, "ClearPlayList", String.valueOf(playlistId)); } - + /** * Sets current playlist - * @param manager Manager reference + * + * @param manager Manager reference * @param playlistId Playlist ID ("0" = music, "1" = video) * @return True on success, false otherwise. */ public boolean setCurrentPlaylist(INotifiableManager manager, int playlistId) { return mConnection.getBoolean(manager, "SetCurrentPlaylist", String.valueOf(playlistId)); - } + } + /** * Sets the correct response format to default values - * @param manager Manager reference + * + * @param manager Manager reference * @return True on success, false otherwise. */ public boolean setResponseFormat(INotifiableManager manager) { @@ -390,11 +421,13 @@ public boolean setResponseFormat(INotifiableManager manager) { sb.append("WebFooter;true;"); sb.append("Header; ;"); sb.append("Footer; ;"); - sb.append("OpenTag;");sb.append(Connection.LINE_SEP);sb.append(";"); + sb.append("OpenTag;"); + sb.append(Connection.LINE_SEP); + sb.append(";"); sb.append("CloseTag;\n;"); sb.append("CloseFinalTag;false"); mConnection.assertBoolean(manager, "SetResponseFormat", sb.toString()); - + sb = new StringBuilder(); sb.append("OpenRecordSet; ;"); sb.append("CloseRecordSet; ;"); @@ -403,64 +436,105 @@ public boolean setResponseFormat(INotifiableManager manager) { sb.append("OpenField;;"); sb.append("CloseField;"); mConnection.assertBoolean(manager, "SetResponseFormat", sb.toString()); - + return true; } catch (WrongDataFormatException e) { return false; } } - + /** * Sets the gui setting of XBMC to value - * @param manager + * + * @param manager * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings - * @param value the value to set - * @return {@code true} if the value was set successfully + * @param value the value to set + * @return {@code true} if the value was set successfully */ public boolean setGuiSetting(INotifiableManager manager, final int setting, final String value) { - return mConnection.getBoolean(manager, "SetGUISetting", GuiSettings.getType(setting) + + return mConnection.getBoolean(manager, "SetGUISetting", GuiSettings.getType(setting) + ";" + GuiSettings.getName(setting) + ";" + value); } - + /** * Returns state and type of the media currently playing. + * * @return */ public ICurrentlyPlaying getCurrentlyPlaying(INotifiableManager manager) { final HashMap map = mConnection.getPairs(manager, "GetCurrentlyPlaying", " ; ; ;true"); final IControlClient.ICurrentlyPlaying nothingPlaying = new IControlClient.ICurrentlyPlaying() { private static final long serialVersionUID = -1554068775915058884L; - public boolean isPlaying() { return false; } - public int getMediaType() { return 0; } - public int getPlaylistPosition() { return -1; } - public String getTitle() { return ""; } - public int getTime() { return 0; } - public int getPlayStatus() { return PlayStatus.STOPPED; } - public float getPercentage() { return 0; } - public String getFilename() { return ""; } - public int getDuration() { return 0; } - public String getArtist() { return ""; } - public String getAlbum() { return ""; } - public int getHeight() { return 0; } - public int getWidth() { return 0; } + + public boolean isPlaying() { + return false; + } + + public int getMediaType() { + return 0; + } + + public int getPlaylistPosition() { + return -1; + } + + public String getTitle() { + return ""; + } + + public int getTime() { + return 0; + } + + public int getPlayStatus() { + return PlayStatus.STOPPED; + } + + public float getPercentage() { + return 0; + } + + public String getFilename() { + return ""; + } + + public int getDuration() { + return 0; + } + + public String getArtist() { + return ""; + } + + public String getAlbum() { + return ""; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } }; if (map == null) return nothingPlaying; if (map.get("Filename") != null && map.get("Filename").contains("Nothing Playing")) { return nothingPlaying; } else { - //final int type = map.get("Type").contains("Audio") ? MediaType.MUSIC : (map.get("Type").contains("Video") ? MediaType.VIDEO : MediaType.PICTURES ); + //final int type = map.get("Type").contains("Audio") ? MediaType.MUSIC : (map.get("Type").contains + // ("Video") ? MediaType.VIDEO : MediaType.PICTURES ); final int type; if (map.containsKey("Type")) { if (map.get("Type").contains("Audio")) type = MediaType.MUSIC; else if (map.get("Type").contains("Video")) { - if (map.get("Show Title")!= null && map.get("Episode") != null) + if (map.get("Show Title") != null && map.get("Episode") != null) type = MediaType.VIDEO_TVEPISODE; - else + else type = MediaType.VIDEO; - } - else + } else type = MediaType.PICTURES; } else { return nothingPlaying; diff --git a/src/org/xbmc/httpapi/client/InfoClient.java b/app/src/main/java/org/xbmc/httpapi/client/InfoClient.java similarity index 81% rename from src/org/xbmc/httpapi/client/InfoClient.java rename to app/src/main/java/org/xbmc/httpapi/client/InfoClient.java index 5e34f3d2..94fbd266 100644 --- a/src/org/xbmc/httpapi/client/InfoClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/InfoClient.java @@ -1,184 +1,203 @@ -package org.xbmc.httpapi.client; - -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; - -import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IInfoClient; -import org.xbmc.api.info.GuiSettings; -import org.xbmc.api.object.FileLocation; -import org.xbmc.api.object.Host; -import org.xbmc.api.type.DirectoryMask; -import org.xbmc.api.type.MediaType; -import org.xbmc.httpapi.Connection; - -/** - * The InfoClient basically takes care of everything else not covered by the - * other clients (music, video and control). That means its tasks are bound to - * system related stuff like directory listing and so on. - * - * @author Team XBMC - */ -public class InfoClient implements IInfoClient { - - private final Connection mConnection; - - /** - * Class constructor needs reference to HTTP client connection - * @param connection - */ - public InfoClient(Connection connection) { - mConnection = connection; - } - - /** - * Updates host info on the connection. - * @param host - */ - public void setHost(Host host) { - mConnection.setHost(host); - } - - /** - * Returns the contents of a directory - * - * @param path Path to the directory - * @param mask Mask to filter - * @param offset Offset (0 for none) - * @param limit Limit (0 for none) - * @param mediaType MediaType - * @return - */ - public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, int offset, int limit, int mediaType) { - ArrayList result = new ArrayList(); - - if (mediaType == MediaType.UNKNOWN) { - result = this.getNonAddonDirectory(manager, path, mask, offset, limit); - } else { - result = this.getAddonDirectory(manager, path, mediaType); - } - - final ArrayList files = new ArrayList(); - for (String file : result) { - files.add(new FileLocation(file)); - } - return files; - } - - private ArrayList getNonAddonDirectory(INotifiableManager manager, String path, DirectoryMask mask, int offset, int limit) { - return mConnection.getArray(manager, "GetDirectory", path + ";" + (mask != null ? mask.toString() : " ") + ";" + (offset > 0 ? offset : " ") + ";" - + (limit > 0 ? limit : " ")); - } - - private ArrayList getAddonDirectory(INotifiableManager manager, String path, int mediaType) { - String mediaFileTypeName = MediaType.getName(mediaType); - return mConnection.getArray(manager, "GetMediaLocation", mediaFileTypeName + ";" + path); - } - - /** - * Returns all the contents of a directory - * @param path Path to the directory - * @return - */ - public ArrayList getDirectory(INotifiableManager manager, String path, int mediaType) { - return this.getDirectory(manager, path, null, 0, 0, mediaType); - } - - - /** - * Returns all defined shares of a media type - * @param mediaType Media type - * @return - */ - public ArrayList getShares(INotifiableManager manager, int mediaType) { - final ArrayList result = mConnection.getArray(manager, "GetShares", MediaType.getName(mediaType)); - final ArrayList shares = new ArrayList(); - for (String share : result) { - shares.add(new FileLocation(share)); - } - return shares; - } - - public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, URISyntaxException { - final ArrayList array = mConnection.getArray(manager, "GetCurrentlyPlaying", " ; ; ;true"); - Boolean isSlideShow = false; - int thumbNum = 0; - for (String s : array) { - if (s.startsWith("SlideFilename")) { - isSlideShow = true; - } else if (s.startsWith("Thumb")) { - // from XBMC r27606 the http api gives the slideshow thumb and the media thumb - if (!isSlideShow || ++thumbNum == 2) { - return mConnection.getUrl("FileDownload", s.substring(6)); - } - } - } - return null; - } - - /** - * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} - * @param field Field to return - * @return - */ - public String getSystemInfo(INotifiableManager manager, int field) { - return mConnection.getString(manager, "GetSystemInfo", String.valueOf(field)); - } - - /** - * Returns a boolean GUI setting - * @param field - * @return - */ - public boolean getGuiSettingBool(INotifiableManager manager, int field) { - return mConnection.getBoolean(manager, "GetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field)); - } - - /** - * Returns an integer GUI setting - * @param field - * @return - */ - public int getGuiSettingInt(INotifiableManager manager, int field) { - return mConnection.getInt(manager, "GetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field)); - } - - /** - * Returns a boolean GUI setting - * @param field - * @param value Value - * @return - */ - public boolean setGuiSettingBool(INotifiableManager manager, int field, boolean value) { - return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field) + ";" + value); - } - - /** - * Returns an integer GUI setting - * @param field - * @param value Value - * @return - */ - public boolean setGuiSettingInt(INotifiableManager manager, int field, int value) { - return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field) + ";" + value); - } - - /** - * Returns any music info variable see {@link org.xbmc.http.info.MusicInfo} - * @param field Field to return - * @return - */ - public String getMusicInfo(INotifiableManager manager, int field) { - return mConnection.getString(manager, "GetMusicLabel", String.valueOf(field)); - } - - /** - * Returns any video info variable see {@link org.xbmc.http.info.VideoInfo} - * @param field Field to return - * @return - */ - public String getVideoInfo(INotifiableManager manager, int field) { - return mConnection.getString(manager, "GetVideoLabel", String.valueOf(field)); - } +package org.xbmc.httpapi.client; + +import org.xbmc.api.business.INotifiableManager; +import org.xbmc.api.data.IInfoClient; +import org.xbmc.api.info.GuiSettings; +import org.xbmc.api.object.FileLocation; +import org.xbmc.api.object.Host; +import org.xbmc.api.type.DirectoryMask; +import org.xbmc.api.type.MediaType; +import org.xbmc.httpapi.Connection; + +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.ArrayList; + +/** + * The InfoClient basically takes care of everything else not covered by the + * other clients (music, video and control). That means its tasks are bound to + * system related stuff like directory listing and so on. + * + * @author Team XBMC + */ +public class InfoClient implements IInfoClient { + + private final Connection mConnection; + + /** + * Class constructor needs reference to HTTP client connection + * + * @param connection + */ + public InfoClient(Connection connection) { + mConnection = connection; + } + + /** + * Updates host info on the connection. + * + * @param host + */ + public void setHost(Host host) { + mConnection.setHost(host); + } + + /** + * Returns the contents of a directory + * + * @param path Path to the directory + * @param mask Mask to filter + * @param offset Offset (0 for none) + * @param limit Limit (0 for none) + * @param mediaType MediaType + * @return + */ + public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, + int offset, int limit, int mediaType) { + ArrayList result = new ArrayList(); + + if (mediaType == MediaType.UNKNOWN) { + result = this.getNonAddonDirectory(manager, path, mask, offset, limit); + } else { + result = this.getAddonDirectory(manager, path, mediaType); + } + + final ArrayList files = new ArrayList(); + for (String file : result) { + files.add(new FileLocation(file)); + } + return files; + } + + private ArrayList getNonAddonDirectory(INotifiableManager manager, String path, DirectoryMask mask, + int offset, int limit) { + return mConnection.getArray(manager, "GetDirectory", path + ";" + (mask != null ? mask.toString() : " ") + ";" + + (offset > 0 ? offset : " ") + ";" + + (limit > 0 ? limit : " ")); + } + + private ArrayList getAddonDirectory(INotifiableManager manager, String path, int mediaType) { + String mediaFileTypeName = MediaType.getName(mediaType); + return mConnection.getArray(manager, "GetMediaLocation", mediaFileTypeName + ";" + path); + } + + /** + * Returns all the contents of a directory + * + * @param path Path to the directory + * @return + */ + public ArrayList getDirectory(INotifiableManager manager, String path, int mediaType) { + return this.getDirectory(manager, path, null, 0, 0, mediaType); + } + + + /** + * Returns all defined shares of a media type + * + * @param mediaType Media type + * @return + */ + public ArrayList getShares(INotifiableManager manager, int mediaType) { + final ArrayList result = mConnection.getArray(manager, "GetShares", MediaType.getName(mediaType)); + final ArrayList shares = new ArrayList(); + for (String share : result) { + shares.add(new FileLocation(share)); + } + return shares; + } + + public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, + URISyntaxException { + final ArrayList array = mConnection.getArray(manager, "GetCurrentlyPlaying", " ; ; ;true"); + Boolean isSlideShow = false; + int thumbNum = 0; + for (String s : array) { + if (s.startsWith("SlideFilename")) { + isSlideShow = true; + } else if (s.startsWith("Thumb")) { + // from XBMC r27606 the http api gives the slideshow thumb and the media thumb + if (!isSlideShow || ++thumbNum == 2) { + return mConnection.getUrl("FileDownload", s.substring(6)); + } + } + } + return null; + } + + /** + * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} + * + * @param field Field to return + * @return + */ + public String getSystemInfo(INotifiableManager manager, int field) { + return mConnection.getString(manager, "GetSystemInfo", String.valueOf(field)); + } + + /** + * Returns a boolean GUI setting + * + * @param field + * @return + */ + public boolean getGuiSettingBool(INotifiableManager manager, int field) { + return mConnection.getBoolean(manager, "GetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName + (field)); + } + + /** + * Returns an integer GUI setting + * + * @param field + * @return + */ + public int getGuiSettingInt(INotifiableManager manager, int field) { + return mConnection.getInt(manager, "GetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName + (field)); + } + + /** + * Returns a boolean GUI setting + * + * @param field + * @param value Value + * @return + */ + public boolean setGuiSettingBool(INotifiableManager manager, int field, boolean value) { + return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName + (field) + ";" + value); + } + + /** + * Returns an integer GUI setting + * + * @param field + * @param value Value + * @return + */ + public boolean setGuiSettingInt(INotifiableManager manager, int field, int value) { + return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName + (field) + ";" + value); + } + + /** + * Returns any music info variable see {@link org.xbmc.api.info.MusicInfo} + * + * @param field Field to return + * @return + */ + public String getMusicInfo(INotifiableManager manager, int field) { + return mConnection.getString(manager, "GetMusicLabel", String.valueOf(field)); + } + + /** + * Returns any video info variable see {@link org.xbmc.api.info.VideoInfo} + * + * @param field Field to return + * @return + */ + public String getVideoInfo(INotifiableManager manager, int field) { + return mConnection.getString(manager, "GetVideoLabel", String.valueOf(field)); + } } \ No newline at end of file diff --git a/src/org/xbmc/httpapi/client/MusicClient.java b/app/src/main/java/org/xbmc/httpapi/client/MusicClient.java similarity index 84% rename from src/org/xbmc/httpapi/client/MusicClient.java rename to app/src/main/java/org/xbmc/httpapi/client/MusicClient.java index 427a8798..309dc3c0 100644 --- a/src/org/xbmc/httpapi/client/MusicClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/MusicClient.java @@ -21,13 +21,12 @@ package org.xbmc.httpapi.client; -import java.util.ArrayList; -import java.util.HashMap; +import android.graphics.Bitmap; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IMusicClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.IMusicClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Album; import org.xbmc.api.object.Artist; @@ -39,139 +38,231 @@ import org.xbmc.api.type.SortType; import org.xbmc.httpapi.Connection; -import android.graphics.Bitmap; +import java.util.ArrayList; +import java.util.HashMap; /** * Takes care of every music related stuff, notably the music database. - * + * * @author Team XBMC */ public class MusicClient extends Client implements IMusicClient { - + public static final String TAG = "MusicClient"; - + public static final int VIEW_ALBUMS = 1; public static final int VIEW_SONGS = 2; - + public static final String PLAYLIST_ID = "0"; public static final String LIBRARY_TYPE = "songs"; - + public static final int PLAYLIST_LIMIT = 100; - + /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public MusicClient(Connection connection) { super(connection); } - + + static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { + return new IControlClient.ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + return map.get("Title"); + } + + public int getTime() { + return parseTime(map.get("Time")); + } + + public int getPlayStatus() { + return PlayStatus.parse(map.get("PlayStatus")); + } + + public int getPlaylistPosition() { + return Integer.parseInt(map.get("SongNo")); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return Integer.valueOf(map.get("Percentage")); + } catch (NumberFormatException e) { + } + return Float.valueOf(map.get("Percentage")); + } + + public String getFilename() { + return map.get("Filename"); + } + + public int getDuration() { + return parseTime(map.get("Duration")); + } + + public String getArtist() { + return map.get("Artist"); + } + + public String getAlbum() { + return map.get("Album"); + } + + public int getMediaType() { + return MediaType.MUSIC; + } + + public boolean isPlaying() { + return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + + private int parseTime(String time) { + String[] s = time.split(":"); + if (s.length == 2) { + return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); + } else if (s.length == 3) { + return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); + } else { + return 0; + } + } + }; + } + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - /** * Adds an album to the current playlist. + * * @param album Album * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Album album, int sortBy, String sortOrder) { - return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(album) + songsOrderBy(sortBy, sortOrder)); + return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(album) + + songsOrderBy(sortBy, sortOrder)); } /** * Adds all songs from an artist to the current playlist. + * * @param artist Artist * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { - return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(artist) + songsOrderBy(sortBy, sortOrder)); + return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(artist) + + songsOrderBy(sortBy, sortOrder)); } /** * Adds all songs from a genre to the current playlist. + * * @param genre Genre * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { - return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(genre) + songsOrderBy(sortBy, sortOrder)); + return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(genre) + + songsOrderBy(sortBy, sortOrder)); } /** * Adds songs of a genre from an artist to the current playlist. + * * @param artist Artist - * @param genre Genre + * @param genre Genre * @return True on success, false otherwise. */ - public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder) { - return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(artist, genre) + songsOrderBy(sortBy, sortOrder)); + public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, + String sortOrder) { + return mConnection.getBoolean(manager, "AddToPlayListFromDB", LIBRARY_TYPE + ";" + getSongsCondition(artist, + genre) + songsOrderBy(sortBy, sortOrder)); } - + /** * Adds a song to the current playlist. + * * @param song Song to add * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Song song) { return mConnection.getBoolean(manager, "AddToPlayList", song.path + ";" + PLAYLIST_ID); } - + /** * Returns how many items are in the playlist. + * * @return Number of items in the playlist */ public int getPlaylistSize(INotifiableManager manager) { return mConnection.getInt(manager, "GetPlaylistLength", PLAYLIST_ID); } - + /** * Retrieves the currently playing song number in the playlist. + * * @return Number of items in the playlist */ public int getPlaylistPosition(INotifiableManager manager) { return mConnection.getInt(manager, "GetPlaylistSong"); } - + /** * Sets the media at playlist position position to be the next item to be played. + * * @param position New position, starting with 0. * @return True on success, false otherwise. */ public boolean setPlaylistPosition(INotifiableManager manager, int position) { return mConnection.getBoolean(manager, "SetPlaylistSong", String.valueOf(position)); } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * * @param position Position to remove, starting with 0. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, int position) { return mConnection.getBoolean(manager, "RemoveFromPlaylist", PLAYLIST_ID + ";" + position); } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. + * + * @param path Complete path (including filename) of the media to be removed. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, String path) { return mConnection.getBoolean(manager, "RemoveFromPlaylist", PLAYLIST_ID + ";" + path); } - + /** - * Returns the first {@link PLAYLIST_LIMIT} songs of the playlist. + * Returns the first songs of the playlist. + * * @return Songs in the playlist. */ public ArrayList getPlaylist(INotifiableManager manager) { - ArrayList temp= mConnection.getArray(manager, "GetPlaylistContents", PLAYLIST_ID); + ArrayList temp = mConnection.getArray(manager, "GetPlaylistContents", PLAYLIST_ID); return temp; - + /* final ArrayList nodes = mConnection.getArray("GetDirectory", "playlistmusic://"); final ArrayList ids = new ArrayList(); @@ -195,81 +286,89 @@ public ArrayList getPlaylist(INotifiableManager manager) { sql.append(")"); final HashMap unsortedSongs = getSongsAsHashMap(sql); final ArrayList sortedSongs = new ArrayList(); - + for (String node : nodes) { try { final int id = Integer.parseInt(node.substring(node.lastIndexOf('/') + 1, node.lastIndexOf('.'))); sortedSongs.add(unsortedSongs.get(id)); - } catch (NumberFormatException e) { + } catch (NumberFormatException e) { Log.e(TAG, e.getMessage()); e.printStackTrace(); } } return sortedSongs;*/ } - + /** * Clears current playlist + * * @return True on success, false otherwise. */ public boolean clearPlaylist(INotifiableManager manager) { return mConnection.getBoolean(manager, "ClearPlayList", PLAYLIST_ID); } - + /** * Adds a song to the current playlist and plays it. + * * @param song Song * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Song song) { return play(manager, getSongsCondition(song)); } - + /** * Plays an album. Playlist is previously cleared. - * @param album Album to play - * @param sortBy Sort field, see SortType.* + * + * @param album Album to play + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Album album, int sortBy, String sortOrder) { return play(manager, getSongsCondition(album).append(songsOrderBy(sortBy, sortOrder))); } - + /** * Plays all songs of a genre. Playlist is previously cleared. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { return play(manager, getSongsCondition(genre).append(songsOrderBy(sortBy, sortOrder))); } - + /** * Plays all songs from an artist. Playlist is previously cleared. - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { return play(manager, getSongsCondition(artist).append(songsOrderBy(sortBy, sortOrder))); } - + /** * Plays songs of a genre from an artist. Playlist is previously cleared. + * * @param artist Artist - * @param genre Genre + * @param genre Genre * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Artist artist, Genre genre) { - return play(manager, getSongsCondition(artist, genre).append(songsOrderBy(SortType.ARTIST, SortType.ORDER_ASC))); + return play(manager, getSongsCondition(artist, genre).append(songsOrderBy(SortType.ARTIST, + SortType.ORDER_ASC))); } /** * Plays all songs fetched by a SQL condition. + * * @param sqlCondition SQL Condition * @return True on success, false otherwise. */ @@ -279,10 +378,11 @@ private boolean play(INotifiableManager manager, StringBuilder sqlCondition) { mConnection.getBoolean(manager, "SetCurrentPlaylist", PLAYLIST_ID); return playNext(manager); } - + /** * Starts playing/showing the next media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @return True on success, false otherwise. */ public boolean playNext(INotifiableManager manager) { @@ -292,35 +392,40 @@ public boolean playNext(INotifiableManager manager) { /** * Starts playing/showing the previous media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @return True on success, false otherwise. */ public boolean playPrev(INotifiableManager manager) { return mConnection.getBoolean(manager, "PlayPrev"); } - + /** - * Sets the media at playlist position position to be the next item to be + * Sets the media at playlist position position to be the next item to be * played. Position starts at 0, so SetPlaylistSong(5) sets the position * to the 6th song in the playlist. + * * @param pos Position * @return true on success, false otherwise. */ public boolean playlistSetSong(INotifiableManager manager, int pos) { return mConnection.getBoolean(manager, "SetPlaylistSong", String.valueOf(pos)); } - + /** * Gets all albums with given artist IDs + * * @param artistIDs Array of artist IDs * @return All compilation albums */ public ArrayList getAlbums(INotifiableManager manager, ArrayList artistIDs) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, art.url"); + sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, " + + "art.url"); sb.append(" FROM albumview"); sb.append(" LEFT OUTER JOIN album_artist ON album_artist.idAlbum=albumview.idAlbum"); sb.append(" LEFT OUTER JOIN artist ON album_artist.idArtist=artist.idArtist"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art" + + ".type='thumb'"); sb.append(" WHERE albumview.strAlbum <> ''"); sb.append(" AND album_artist.idArtist IN ("); int n = 0; @@ -334,20 +439,23 @@ public ArrayList getAlbums(INotifiableManager manager, ArrayList sb.append(") GROUP BY albumview.idAlbum"); return parseAlbums(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - + /** * Gets all albums from database - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All albums */ public ArrayList getAlbums(INotifiableManager manager, int sortBy, String sortOrder) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, art.url"); + sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, " + + "art.url"); sb.append(" FROM albumview"); sb.append(" LEFT OUTER JOIN album_artist ON album_artist.idAlbum=albumview.idAlbum"); sb.append(" LEFT OUTER JOIN artist ON album_artist.idArtist=artist.idArtist"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art" + + ".type='thumb'"); sb.append(" WHERE albumview.strAlbum <> '' GROUP BY albumview.idAlbum"); sb.append(albumsOrderBy(sortBy, sortOrder)); return parseAlbums(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); @@ -355,18 +463,21 @@ public ArrayList getAlbums(INotifiableManager manager, int sortBy, String /** * Gets all albums of an artist from database - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Albums with an artist */ public ArrayList getAlbums(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, art.url"); + sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, " + + "art.url"); sb.append(" FROM albumview"); sb.append(" LEFT OUTER JOIN album_artist ON album_artist.idAlbum=albumview.idAlbum"); sb.append(" LEFT OUTER JOIN artist ON album_artist.idArtist=artist.idArtist"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art" + + ".type='thumb'"); sb.append(" WHERE albumview.strAlbum <> ''"); sb.append(" AND album_artist.idArtist = " + artist.id + " GROUP BY albumview.idAlbum"); sb.append(albumsOrderBy(sortBy, sortOrder)); @@ -375,30 +486,34 @@ public ArrayList getAlbums(INotifiableManager manager, Artist artist, int /** * Gets all albums of with at least one song in a genre - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Albums of a genre */ public ArrayList getAlbums(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, art.url"); - sb.append(" FROM albumview"); - sb.append(" LEFT OUTER JOIN album_artist ON album_artist.idAlbum=albumview.idAlbum"); - sb.append(" LEFT OUTER JOIN artist ON album_artist.idArtist=artist.idArtist"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art.type='thumb'"); - sb.append(" WHERE albumview.strAlbum <> ''"); - sb.append(" AND (albumview.idAlbum IN ("); - sb.append(" SELECT song.idAlbum FROM song"); - sb.append(" JOIN song_genre ON song.idSong = song_genre.idSong"); + sb.append("SELECT albumview.idAlbum, strAlbum, group_concat(DISTINCT strArtist) AS strArtists, iYear, " + + "art.url"); + sb.append(" FROM albumview"); + sb.append(" LEFT OUTER JOIN album_artist ON album_artist.idAlbum=albumview.idAlbum"); + sb.append(" LEFT OUTER JOIN artist ON album_artist.idArtist=artist.idArtist"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=albumview.idAlbum AND art.media_type='album' AND art" + + ".type='thumb'"); + sb.append(" WHERE albumview.strAlbum <> ''"); + sb.append(" AND (albumview.idAlbum IN ("); + sb.append(" SELECT song.idAlbum FROM song"); + sb.append(" JOIN song_genre ON song.idSong = song_genre.idSong"); sb.append(" WHERE song_genre.idGenre = " + genre.id); sb.append(" )) GROUP BY albumview.idAlbum"); sb.append(albumsOrderBy(sortBy, sortOrder)); return parseAlbums(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - + /** * Gets all albums from database + * * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. * @return All albums */ @@ -429,7 +544,8 @@ public ArrayList getArtists(INotifiableManager manager, boolean albumArt /** * Gets all artists with at least one song of a genre. - * @param genre Genre + * + * @param genre Genre * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. * @return Albums with a genre */ @@ -456,21 +572,25 @@ public ArrayList getArtists(INotifiableManager manager, Genre genre, boo sb.append(" WHERE album.strExtraArtists != ''"); sb.append(" )"); sb.append(" ) AND artist.strArtist != ''"); - } + } sb.append(" ORDER BY upper(strArtist), strArtist"); return parseArtists(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - + /** * Gets all genres from database + * * @return All genres */ public ArrayList getGenres(INotifiableManager manager) { - return parseGenres(mConnection.query("QueryMusicDatabase", "SELECT idGenre, strGenre FROM genre ORDER BY upper(strGenre), strGenre", manager)); + return parseGenres(mConnection.query("QueryMusicDatabase", "SELECT idGenre, " + + "strGenre FROM genre ORDER BY upper" + + "(strGenre), strGenre", manager)); } - + /** * Updates the album object with additional data from the albuminfo table + * * @param album * @return Updated album */ @@ -484,9 +604,10 @@ public Album updateAlbumInfo(INotifiableManager manager, Album album) { sb.append(" AND a.idAlbum = " + album.id); return parseAlbumInfo(album, mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - + /** * Updates the artist object with additional data from the artistinfo table + * * @param artist * @return Updated artist */ @@ -497,43 +618,49 @@ public Artist updateArtistInfo(INotifiableManager manager, Artist artist) { sb.append(" WHERE idArtist = " + artist.id); return parseArtistInfo(artist, mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - + + /** + * Returns a hash map containing tracks of a certain condition. + * @param sqlCondition SQL condition which tracks to return + * @return Found tracks + * + private HashMap getSongsAsHashMap(StringBuilder sqlCondition) { + StringBuilder sb = new StringBuilder(); + sb.append("SELECT idSong, strTitle, strArtist, strAlbum, iTrack, iDuration, strPath, strFileName, strThumb"); + sb.append(" FROM songview WHERE "); + sb.append(sqlCondition); + sb.append(" ORDER BY iTrack, strFileName"); + return parseSongsAsHashMap(mConnection.query("QueryMusicDatabase", sb.toString())); + }*/ + /** * Returns a list containing tracks of a certain condition. + * * @param sqlCondition SQL condition which tracks to return * @return Found tracks */ - private ArrayList getSongs(INotifiableManager manager, StringBuilder sqlCondition, int sortBy, String sortOrder) { + private ArrayList getSongs(INotifiableManager manager, StringBuilder sqlCondition, int sortBy, + String sortOrder) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT songview.idSong, strTitle, group_concat(DISTINCT strArtist) AS strArtists, strAlbum, iTrack, iDuration, strPath, strFileName, art.url"); + sb.append("SELECT songview.idSong, strTitle, group_concat(DISTINCT strArtist) AS strArtists, strAlbum, " + + "iTrack," + + " iDuration, strPath, strFileName, art.url"); sb.append(" FROM songview"); sb.append(" LEFT OUTER JOIN song_artist ON song_artist.idSong=songview.idSong"); sb.append(" LEFT OUTER JOIN artist ON song_artist.idArtist=artist.idArtist"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=songview.idSong AND art.media_type='song' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=songview.idSong AND art.media_type='song' AND art" + + ".type='thumb'"); sb.append(" WHERE "); sb.append(sqlCondition); sb.append(" GROUP BY idSong"); sb.append(songsOrderBy(sortBy, sortOrder)); - + return parseSongs(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); } - - /** - * Returns a hash map containing tracks of a certain condition. - * @param sqlCondition SQL condition which tracks to return - * @return Found tracks - * - private HashMap getSongsAsHashMap(StringBuilder sqlCondition) { - StringBuilder sb = new StringBuilder(); - sb.append("SELECT idSong, strTitle, strArtist, strAlbum, iTrack, iDuration, strPath, strFileName, strThumb"); - sb.append(" FROM songview WHERE "); - sb.append(sqlCondition); - sb.append(" ORDER BY iTrack, strFileName"); - return parseSongsAsHashMap(mConnection.query("QueryMusicDatabase", sb.toString())); - }*/ - + /** * Returns the SQL condition that returns all songs of a song. + * * @param song Song * @return SQL string */ @@ -546,6 +673,7 @@ private StringBuilder getSongsCondition(Song song) { /** * Returns the SQL condition that returns all songs of an album. + * * @param album Album * @return SQL string */ @@ -558,6 +686,7 @@ private StringBuilder getSongsCondition(Album album) { /** * Returns the SQL condition that returns all songs of an artist. + * * @param artist Artist * @return SQL string */ @@ -588,10 +717,11 @@ private StringBuilder getSongsCondition(Artist artist) { sb.append(" )"); sb.append(")");*/ return sb; - } - + } + /** * Returns the SQL condition that returns all songs of a genre. + * * @param genre Genre * @return SQL string */ @@ -606,8 +736,9 @@ private StringBuilder getSongsCondition(Genre genre) { /** * Returns the SQL condition that returns all songs of a genre AND an artist. + * * @param artist Artist - * @param genre Genre + * @param genre Genre * @return SQL string */ private StringBuilder getSongsCondition(Artist artist, Genre genre) { @@ -645,12 +776,13 @@ private StringBuilder getSongsCondition(Artist artist, Genre genre) { sb.append(")"); return sb; } - + /** * Returns a list containing all tracks of an album. The list is sorted by filename. - * @param album Album - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * + * @param album Album + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of an album */ public ArrayList getSongs(INotifiableManager manager, Album album, int sortBy, String sortOrder) { @@ -659,45 +791,50 @@ public ArrayList getSongs(INotifiableManager manager, Album album, int sor /** * Returns a list containing all tracks of an artist. The list is sorted by album name, filename. - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the artist */ public ArrayList getSongs(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { return getSongs(manager, getSongsCondition(artist), sortBy, sortOrder); } - + /** * Returns a list containing all tracks of a genre. The list is sorted by artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the genre */ public ArrayList getSongs(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { return getSongs(manager, getSongsCondition(genre), sortBy, sortOrder); } - + /** - * Returns a list containing all tracks of a genre AND and artist. The list is sorted by + * Returns a list containing all tracks of a genre AND and artist. The list is sorted by * artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the genre */ - public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder) { + public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, + String sortOrder) { return getSongs(manager, getSongsCondition(artist, genre), sortBy, sortOrder); } - + /** * Returns a pre-resized album/artist cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minimal size to pre-resize to. + * @param cover Cover object + * @param size Minimal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { @@ -707,11 +844,12 @@ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { return getCover(manager, cover, size, Album.getThumbUri(cover), Album.getFallbackThumbUri(cover)); } } - + /** * Returns a list containing all artist IDs that stand for "compilation". * Best case scenario would be only one ID for "Various Artists", though * there are also just "V.A." or "VA" naming conventions. + * * @return List of compilation artist IDs */ public ArrayList getCompilationArtistIDs(INotifiableManager manager) { @@ -722,11 +860,12 @@ public ArrayList getCompilationArtistIDs(INotifiableManager manager) { sb.append(" OR lower(strArtist) LIKE 'v.a.%%'"); sb.append(" OR lower(strArtist) = 'va'"); return parseIntArray(mConnection.query("QueryMusicDatabase", sb.toString(), manager)); - + } - + /** * Returns an SQL String of given sort options of albums query + * * @param sortBy Sort field * @param sortOrder Sort order * @return SQL "ORDER BY" string @@ -747,6 +886,7 @@ private String albumsOrderBy(int sortBy, String sortOrder) { /** * Returns an SQL String of given sort options of songs query + * * @param sortBy Sort field * @param sortOrder Sort order * @return SQL "ORDER BY" string @@ -756,7 +896,8 @@ private String songsOrderBy(int sortBy, String sortOrder) { case SortType.ALBUM: return " ORDER BY lower(strAlbum) " + sortOrder + ", iTrack " + sortOrder; case SortType.ARTIST: - return " ORDER BY lower(strArtist) " + sortOrder + ", lower(strAlbum) " + sortOrder + ", iTrack " + sortOrder; + return " ORDER BY lower(strArtist) " + sortOrder + ", lower(strAlbum) " + sortOrder + ", " + + "iTrack " + sortOrder; case SortType.TITLE: return " ORDER BY lower(strTitle)" + sortOrder; case SortType.FILENAME: @@ -773,12 +914,13 @@ private String songsOrderBy(int sortBy, String sortOrder) { * Converts query response from HTTP API to a list of Album objects. Each * row must return the following attributes in the following order: *
      - *
    1. idAlbum
    2. - *
    3. strAlbum
    4. - *
    5. strArtist
    6. - *
    7. iYear
    8. - *
    9. strThumb
    10. - *
    + *
  • idAlbum
  • + *
  • strAlbum
  • + *
  • strArtist
  • + *
  • iYear
  • + *
  • strThumb
  • + * + * * @param response * @return List of albums */ @@ -788,8 +930,8 @@ private ArrayList parseAlbums(String response) { try { for (int row = 1; row < fields.length; row += 5) { albums.add(new Album( - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]), Connection.trim(fields[row + 2]), Connection.trimInt(fields[row + 3]), Connection.trim(fields[row + 4]) @@ -802,16 +944,17 @@ private ArrayList parseAlbums(String response) { } return albums; } - + /** - * Updates an album with info from HTTP API query response. One row is + * Updates an album with info from HTTP API query response. One row is * expected, with the following columns: *
      - *
    1. strGenre
    2. - *
    3. strExtraGenres
    4. - *
    5. strLabel
    6. - *
    7. iRating
    8. - *
    + *
  • strGenre
  • + *
  • strExtraGenres
  • + *
  • strLabel
  • + *
  • iRating
  • + * + * * @param album * @param response * @return Updated album @@ -835,18 +978,19 @@ private Album parseAlbumInfo(Album album, String response) { } return album; } - + /** - * Updates an artist with info from HTTP API query response. One row is + * Updates an artist with info from HTTP API query response. One row is * expected, with the following columns: *
      - *
    1. strBorn
    2. - *
    3. strFormed
    4. - *
    5. strGenre
    6. - *
    7. strMoods
    8. - *
    9. strStyles
    10. - *
    11. strBiography
    12. - *
    + *
  • strBorn
  • + *
  • strFormed
  • + *
  • strGenre
  • + *
  • strMoods
  • + *
  • strStyles
  • + *
  • strBiography
  • + * + * * @param artist * @param response * @return Updated artist @@ -856,7 +1000,7 @@ private Artist parseArtistInfo(Artist artist, String response) { try { if (Connection.trim(fields[1]).length() > 0) { artist.born = Connection.trim(fields[1]); - } + } if (Connection.trim(fields[2]).length() > 0) { artist.formed = Connection.trim(fields[2]); } @@ -879,7 +1023,7 @@ private Artist parseArtistInfo(Artist artist, String response) { } return artist; } - + /** * Converts query response from HTTP API to a list of Song objects. Each * row must return the following columns in the following order: @@ -896,85 +1040,89 @@ private Artist parseArtistInfo(Artist artist, String response) { * * @param response * @return List of Songs - */ - private ArrayList parseSongs(String response) { - ArrayList songs = new ArrayList(); - String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 9) { - songs.add(new Song( // int id, String title, String artist, String album, int track, int duration, String path, String filename, String thumbPath - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), - Connection.trim(fields[row + 2]), - Connection.trim(fields[row + 3]), - Connection.trimInt(fields[row + 4]), - Connection.trimInt(fields[row + 5]), - Connection.trim(fields[row + 6]), - Connection.trim(fields[row + 7]), - Connection.trim(fields[row + 8]) - )); - } - } catch (Exception e) { - System.err.println("ERROR: " + e.getMessage()); - System.err.println("response = " + response); - e.printStackTrace(); - } - return songs; + * + private HashMap parseSongsAsHashMap(String response) { + HashMap songs = new HashMap(); + String[] fields = response.split(""); + try { + for (int row = 1; row < fields.length; row += 9) { + songs.put(Connection.trimInt(fields[row]), + new Song( // int id, String title, String artist, String album, int track, int duration, String path, + String filename, String thumbPath + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]), + Connection.trim(fields[row + 2]), + Connection.trim(fields[row + 3]), + Connection.trimInt(fields[row + 4]), + Connection.trimInt(fields[row + 5]), + Connection.trim(fields[row + 6]), + Connection.trim(fields[row + 7]), + Connection.trim(fields[row + 8]) + ) + ); + } + } catch (Exception e) { + System.err.println("ERROR: " + e.getMessage()); + System.err.println("response = " + response); + e.printStackTrace(); } - + return songs; + }*/ + /** * Converts query response from HTTP API to a list of Song objects. Each * row must return the following columns in the following order: *
      - *
    1. idSong
    2. - *
    3. strTitle
    4. - *
    5. strArtist
    6. - *
    7. strAlbum
    8. - *
    9. iTrack
    10. - *
    11. iDuration
    12. - *
    13. strPath
    14. - *
    15. strFileName
    16. - *
    17. strThumb
    18. - *
    + *
  • idSong
  • + *
  • strTitle
  • + *
  • strArtist
  • + *
  • strAlbum
  • + *
  • iTrack
  • + *
  • iDuration
  • + *
  • strPath
  • + *
  • strFileName
  • + *
  • strThumb
  • + * + * * @param response * @return List of Songs - * - private HashMap parseSongsAsHashMap(String response) { - HashMap songs = new HashMap(); + */ + private ArrayList parseSongs(String response) { + ArrayList songs = new ArrayList(); String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 9) { - songs.put(Connection.trimInt(fields[row]), - new Song( // int id, String title, String artist, String album, int track, int duration, String path, String filename, String thumbPath + try { + for (int row = 1; row < fields.length; row += 9) { + songs.add(new Song( // int id, String title, String artist, String album, int track, int duration, + // String path, String filename, String thumbPath Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), - Connection.trim(fields[row + 2]), - Connection.trim(fields[row + 3]), - Connection.trimInt(fields[row + 4]), - Connection.trimInt(fields[row + 5]), + Connection.trim(fields[row + 1]), + Connection.trim(fields[row + 2]), + Connection.trim(fields[row + 3]), + Connection.trimInt(fields[row + 4]), + Connection.trimInt(fields[row + 5]), Connection.trim(fields[row + 6]), - Connection.trim(fields[row + 7]), + Connection.trim(fields[row + 7]), Connection.trim(fields[row + 8]) - ) - ); + )); } } catch (Exception e) { System.err.println("ERROR: " + e.getMessage()); System.err.println("response = " + response); e.printStackTrace(); } - return songs; - }*/ - + return songs; + } + /** * Converts query response from HTTP API to a list of integer values. + * * @param response * @return */ private ArrayList parseIntArray(String response) { ArrayList array = new ArrayList(); String[] fields = response.split(""); - try { + try { for (int row = 1; row < fields.length; row += 9) { array.add(Connection.trimInt(fields[row])); } @@ -985,24 +1133,25 @@ private ArrayList parseIntArray(String response) { } return array; } - + /** * Converts query response from HTTP API to a list of Artist objects. Each * row must return the following columns in the following order: *
      - *
    1. idArtist
    2. - *
    3. strArtist
    4. + *
    5. idArtist
    6. + *
    7. strArtist
    8. *
    + * * @param response * @return List of Artists */ private ArrayList parseArtists(String response) { ArrayList artists = new ArrayList(); String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 3) { + try { + for (int row = 1; row < fields.length; row += 3) { artists.add(new Artist( - Connection.trimInt(fields[row]), + Connection.trimInt(fields[row]), Connection.trim(fields[row + 1]), Connection.trim(fields[row + 2]) )); @@ -1012,26 +1161,27 @@ private ArrayList parseArtists(String response) { System.err.println("response = " + response); e.printStackTrace(); } - return artists; + return artists; } - + /** * Converts query response from HTTP API to a list of Genre objects. Each * row must return the following columns in the following order: *
      - *
    1. idGenre
    2. - *
    3. strGenre
    4. + *
    5. idGenre
    6. + *
    7. strGenre
    8. *
    + * * @param response * @return List of Genres */ private ArrayList parseGenres(String response) { ArrayList genres = new ArrayList(); String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 2) { + try { + for (int row = 1; row < fields.length; row += 2) { genres.add(new Genre( - Connection.trimInt(fields[row]), + Connection.trimInt(fields[row]), Connection.trim(fields[row + 1]) )); } @@ -1040,65 +1190,6 @@ private ArrayList parseGenres(String response) { System.err.println("response = " + response); e.printStackTrace(); } - return genres; - } - - static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { - return new IControlClient.ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - return map.get("Title"); - } - public int getTime() { - return parseTime(map.get("Time")); - } - public int getPlayStatus() { - return PlayStatus.parse(map.get("PlayStatus")); - } - public int getPlaylistPosition() { - return Integer.parseInt(map.get("SongNo")); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return Integer.valueOf(map.get("Percentage")); - } catch (NumberFormatException e) { } - return Float.valueOf(map.get("Percentage")); - } - public String getFilename() { - return map.get("Filename"); - } - public int getDuration() { - return parseTime(map.get("Duration")); - } - public String getArtist() { - return map.get("Artist"); - } - public String getAlbum() { - return map.get("Album"); - } - public int getMediaType() { - return MediaType.MUSIC; - } - public boolean isPlaying() { - return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - private int parseTime(String time) { - String[] s = time.split(":"); - if (s.length == 2) { - return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); - } else if (s.length == 3) { - return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); - } else { - return 0; - } - } - }; + return genres; } } \ No newline at end of file diff --git a/src/org/xbmc/httpapi/client/PictureClient.java b/app/src/main/java/org/xbmc/httpapi/client/PictureClient.java similarity index 95% rename from src/org/xbmc/httpapi/client/PictureClient.java rename to app/src/main/java/org/xbmc/httpapi/client/PictureClient.java index 52eccdf1..7bd80965 100644 --- a/src/org/xbmc/httpapi/client/PictureClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/PictureClient.java @@ -21,26 +21,25 @@ package org.xbmc.httpapi.client; -import java.util.HashMap; - import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.type.MediaType; +import java.util.HashMap; + /** * Takes care of Picture/SlideShow stuff - * - * @author Team XBMC * + * @author Team XBMC */ public class PictureClient { public static final String TAG = "PictureClient"; - + static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { return new ICurrentlyPlaying() { private static final long serialVersionUID = 5036994329211476713L; - + public int getMediaType() { return MediaType.PICTURES; } @@ -97,27 +96,28 @@ public int getHeight() { public int getWidth() { return parseWidth(map.get("Resolution")); } - - private int parseHeight(String resolution){ + + private int parseHeight(String resolution) { String[] xy = resolution.split("x"); if (xy.length != 2) return 0; - try{ + try { return Integer.parseInt(xy[1].trim()); } catch (NumberFormatException e) { return 0; } } - private int parseWidth(String resolution){ + + private int parseWidth(String resolution) { String[] xy = resolution.split("x"); if (xy.length != 2) return 0; - try{ + try { return Integer.parseInt(xy[0].trim()); } catch (NumberFormatException e) { return 0; } - } + } }; } } \ No newline at end of file diff --git a/src/org/xbmc/httpapi/client/TvShowClient.java b/app/src/main/java/org/xbmc/httpapi/client/TvShowClient.java similarity index 87% rename from src/org/xbmc/httpapi/client/TvShowClient.java rename to app/src/main/java/org/xbmc/httpapi/client/TvShowClient.java index f4255d16..80781e32 100644 --- a/src/org/xbmc/httpapi/client/TvShowClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/TvShowClient.java @@ -21,12 +21,12 @@ package org.xbmc.httpapi.client; -import java.util.ArrayList; -import java.util.HashMap; +import android.graphics.Bitmap; +import android.util.Log; import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.ITvShowClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.ITvShowClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Actor; import org.xbmc.api.object.Episode; @@ -39,8 +39,8 @@ import org.xbmc.api.type.SortType; import org.xbmc.httpapi.Connection; -import android.graphics.Bitmap; -import android.util.Log; +import java.util.ArrayList; +import java.util.HashMap; /** * TV show client for HTTP API. @@ -57,11 +57,11 @@ * - c09: empty * - c10: tvdb urls * - c11: fanart urls - * - c12: tvdb show id - * - c13: content rating - * - c14: network name - * - c15-c20: empty - * -> plus strPath, totalCount, watchedCount, watched + * - c12: tvdb show id + * - c13: content rating + * - c14: network name + * - c15-c20: empty + * -> plus strPath, totalCount, watchedCount, watched *
    *
      * Episode DB Fields:
    @@ -82,6 +82,7 @@
      * c13: Episode Number
      * idFile: Foreign key to the files table
      * 
    + * * @author Team XBMC */ public class TvShowClient extends Client implements ITvShowClient { @@ -91,12 +92,92 @@ public class TvShowClient extends Client implements ITvShowClient { public TvShowClient(Connection connection) { super(connection); } - - public ArrayList getTvShows(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { + + static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { + return new ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + return map.get("Show Title"); + } + + public int getTime() { + return parseTime(map.get("Time")); + } + + public int getPlayStatus() { + return PlayStatus.parse(map.get("PlayStatus")); + } + + public int getPlaylistPosition() { + return Integer.parseInt(map.get("VideoNo")); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return Integer.valueOf(map.get("Percentage")); + } catch (NumberFormatException e) { + } + return Float.valueOf(map.get("Percentage")); + } + + public String getFilename() { + return map.get("Filename"); + } + + public int getDuration() { + return parseTime(map.get("Duration")); + } + + public String getArtist() { + if (Integer.valueOf(map.get("Season")) == 0) { + return "Specials / Episode " + map.get("Episode"); + } else { + return "Season " + map.get("Season") + " / Episode " + map.get("Episode"); + } + } + + public String getAlbum() { + return map.get("Title"); + } + + public int getMediaType() { + return MediaType.VIDEO_TVSHOW; + } + + public boolean isPlaying() { + return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + + private int parseTime(String time) { + String[] s = time.split(":"); + if (s.length == 2) { + return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); + } else if (s.length == 3) { + return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); + } else { + return 0; + } + } + }; + } + + public ArrayList getTvShows(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); - + // don't fetch summary for list view - sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, tvshow.c13, tvshow.c14,"); + sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, " + + "tvshow.c13, tvshow.c14,"); sb.append(" paths.strPath,"); sb.append(" counts.totalcount AS totalCount,"); sb.append(" counts.watchedcount AS watchedCount,"); @@ -108,7 +189,8 @@ public ArrayList getTvShows(INotifiableManager manager, int sortBy, Stri sb.append(" ) showNames"); sb.append(" LEFT OUTER join tvshow on showNames.idShow = tvshow.idShow"); sb.append(" LEFT OUTER join ("); - sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, count(files.playCount) AS watchedcount"); + sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, " + + "count(files.playCount) AS watchedcount"); sb.append(" FROM tvshow"); sb.append(" JOIN episode ON episode.idShow = tvshow.idShow"); sb.append(" JOIN files ON files.idFile = episode.idFile"); @@ -128,16 +210,18 @@ public ArrayList getTvShows(INotifiableManager manager, int sortBy, Stri } sb.append(showsOrderBy(sortBy, sortOrder)); Log.i(TAG, sb.toString()); - - -/* sb.append("SELECT tvshow.idShow, c00, c01, c04, c05, c08, c13, c14, strPath FROM tvshow, path, tvshowlinkpath"); + + +/* sb.append("SELECT tvshow.idShow, c00, c01, c04, c05, c08, c13, c14, strPath FROM tvshow, path, +tvshowlinkpath"); sb.append(" WHERE tvshow.idShow = tvshowlinkpath.idShow"); sb.append(" AND path.idPath = tvshowlinkpath.idPath");*/ return parseShows(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all tv show actors from database + * * @return All tv show actors */ public ArrayList getTvShowActors(INotifiableManager manager) { @@ -147,9 +231,10 @@ public ArrayList getTvShowActors(INotifiableManager manager) { sb.append(" ORDER BY upper(strActor), strActor"); return VideoClient.parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all tv show genres from database + * * @return All tv show genres */ public ArrayList getTvShowGenres(INotifiableManager manager) { @@ -159,16 +244,19 @@ public ArrayList getTvShowGenres(INotifiableManager manager) { sb.append(" ORDER BY upper(strGenre)"); return VideoClient.parseGenres(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all tv shows with the specified actor + * * @param manager * @param actor * @return */ - public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, tvshow.c13, tvshow.c14,"); + sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, " + + "tvshow.c13, tvshow.c14,"); sb.append(" paths.strPath,"); sb.append(" counts.totalcount AS totalCount,"); sb.append(" counts.watchedcount AS watchedCount,"); @@ -180,7 +268,8 @@ public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sb.append(" ) showNames"); sb.append(" LEFT OUTER join tvshow on showNames.idShow = tvshow.idShow"); sb.append(" LEFT OUTER join ("); - sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, count(files.playCount) AS watchedcount"); + sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, " + + "count(files.playCount) AS watchedcount"); sb.append(" FROM tvshow"); sb.append(" JOIN episode ON episode.idShow = tvshow.idShow"); sb.append(" JOIN files ON files.idFile = episode.idFile"); @@ -206,18 +295,19 @@ public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sb.append(" AND counts.totalcount > counts.watchedcount "); } sb.append(showsOrderBy(sortBy, sortOrder)); - + Log.i(TAG, sb.toString()); return parseShows(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all tv shows for the specified genre - * */ - public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, tvshow.c13, tvshow.c14,"); + sb.append("SELECT tvshow.idShow, tvshow.c00, \"\" AS c01, ROUND(tvshow.c04, 2), tvshow.c05, tvshow.c08, " + + "tvshow.c13, tvshow.c14,"); sb.append(" paths.strPath,"); sb.append(" counts.totalcount AS totalCount,"); sb.append(" counts.watchedcount AS watchedCount,"); @@ -229,7 +319,8 @@ public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sb.append(" ) showNames"); sb.append(" LEFT OUTER join tvshow on showNames.idShow = tvshow.idShow"); sb.append(" LEFT OUTER join ("); - sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, count(files.playCount) AS watchedcount"); + sb.append(" SELECT min(tvshow.idShow) as idShow, tvshow.c00, count(1) AS totalcount, " + + "count(files.playCount) AS watchedcount"); sb.append(" FROM tvshow"); sb.append(" JOIN episode ON episode.idShow = tvshow.idShow"); sb.append(" JOIN files ON files.idFile = episode.idFile"); @@ -255,13 +346,14 @@ public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sb.append(" AND counts.totalcount > counts.watchedcount "); } sb.append(showsOrderBy(sortBy, sortOrder)); - + Log.i(TAG, sb.toString()); return parseShows(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all seasons for the specified show + * * @param manager * @param show * @return @@ -284,20 +376,22 @@ public ArrayList getSeasons(INotifiableManager manager, TvShow show, boo sb.append("GROUP BY episode.c12, tvshow.c00 "); sb.append(") q"); sb.append(" LEFT OUTER JOIN seasons ON seasons.idShow=q.idShow AND seasons.season=q.c12"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=seasons.idSeason AND art.media_type='season' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=seasons.idSeason AND art.media_type='season' AND art" + + ".type='thumb'"); sb.append(" where not q.c12 is null "); sb.append("ORDER BY q.c12+0"); - + return parseSeasons(mConnection.query("QueryVideoDatabase", sb.toString(), manager), show); } - + /** * Gets all seasons for all shows + * * @param manager - * @param show * @return */ - public ArrayList getSeasons(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getSeasons(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { ArrayList shows = getTvShows(manager, sortBy, sortOrder, hideWatched); HashMap showMap = new HashMap(); for (TvShow tvShow : shows) { @@ -311,71 +405,84 @@ public ArrayList getSeasons(INotifiableManager manager, int sortBy, Stri sb.append(" LEFT OUTER JOIN files ON files.idFile = episode.idFile "); } sb.append(" LEFT OUTER JOIN seasons ON seasons.idShow=tvshow.idShow AND seasons.season=episode.c12"); - sb.append(" LEFT OUTER JOIN art ON art.media_id=seasons.idSeason AND art.media_type='season' AND art.type='thumb'"); + sb.append(" LEFT OUTER JOIN art ON art.media_id=seasons.idSeason AND art.media_type='season' AND art" + + ".type='thumb'"); sb.append("WHERE NOT episode.c12 is null "); if (hideWatched) { sb.append(" AND (files.playCount IS NULL OR files.playCount = 0) "); } sb.append("GROUP BY episode.c12, tvshow.c00 "); sb.append("ORDER BY tvshow.idShow, episode.c12+0"); - + return parseSeasons(mConnection.query("QueryVideoDatabase", sb.toString(), manager), showMap); } - + /** * Gets all Episodes for the specified show + * * @param manager * @param show * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, + boolean hideWatched) { return getEpisodes(manager, show, null, sortBy, sortOrder, hideWatched); } - + /** * Gets all Episodes for the specified season + * * @param manager * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, + boolean hideWatched) { return getEpisodes(manager, season.show, season, sortBy, sortOrder, hideWatched); } - + /** * Gets all Episodes for all shows + * * @param manager * @return */ - public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT idEpisode, c00, \"\" AS c01, ROUND(c03, 2), c04, c05, c06, playCount, c10, c12, c13, strPath, strFileName, strTitle, art.url"); - sb.append(" FROM episodeview LEFT OUTER JOIN art ON art.media_id=episodeview.idEpisode AND art.media_type='episode' AND art.type='thumb'"); + sb.append("SELECT idEpisode, c00, \"\" AS c01, ROUND(c03, 2), c04, c05, c06, playCount, c10, c12, c13, " + + "strPath, strFileName, strTitle, art.url"); + sb.append(" FROM episodeview LEFT OUTER JOIN art ON art.media_id=episodeview.idEpisode AND art" + + ".media_type='episode' AND art.type='thumb'"); if (hideWatched) { sb.append(" WHERE (playCount IS NULL OR playCount = 0) "); } sb.append(showsOrderBy(sortBy, sortOrder)); return parseEpisodes(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all Episodes for the specified show and season + * * @param manager * @param show * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, + String sortOrder, boolean hideWatched) { StringBuilder sb = new StringBuilder(); - sb.append("SELECT idEpisode, c00, \"\" AS c01, ROUND(c03, 2), c04, c05, c06, playCount, c10, c12, c13, strPath, strFileName, strTitle, art.url"); - sb.append(" FROM episodeview LEFT OUTER JOIN art ON art.media_id=episodeview.idEpisode AND art.media_type='episode' AND art.type='thumb'"); + sb.append("SELECT idEpisode, c00, \"\" AS c01, ROUND(c03, 2), c04, c05, c06, playCount, c10, c12, c13, " + + "strPath, strFileName, strTitle, art.url"); + sb.append(" FROM episodeview LEFT OUTER JOIN art ON art.media_id=episodeview.idEpisode AND art" + + ".media_type='episode' AND art.type='thumb'"); sb.append(" WHERE idShow in ( select idShow from tvshow where c00 in (select c00 from tvshow where idShow = "); sb.append(show.id); sb.append("))"); if (hideWatched) { sb.append(" AND (playCount IS NULL OR playCount = 0) "); } - if(season != null) { + if (season != null) { sb.append(" AND (c12 = "); sb.append(season.number); sb.append(" OR (c12 = 0 AND (c15 = 0 OR c15 = "); @@ -385,7 +492,7 @@ public ArrayList getEpisodes(INotifiableManager manager, TvShow show, S sb.append(showsOrderBy(sortBy, sortOrder)); return parseEpisodes(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + public TvShow updateTvShowDetails(INotifiableManager manager, TvShow show) { StringBuilder sb = new StringBuilder(); sb.append("SELECT c01"); @@ -396,14 +503,15 @@ public TvShow updateTvShowDetails(INotifiableManager manager, TvShow show) { //parse actors of the show sb = new StringBuilder(); sb.append("SELECT actors.idActor, strActor, art.url, strRole"); - sb.append(" FROM actors LEFT JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' AND art.type='thumb', actorlinktvshow"); + sb.append(" FROM actors LEFT JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' AND art" + + ".type='thumb', actorlinktvshow"); sb.append(" WHERE actors.idActor = actorlinktvshow.idActor"); sb.append(" AND actorlinktvshow.idShow ="); sb.append(show.getId()); - show.actors = VideoClient.parseActorRoles(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); + show.actors = VideoClient.parseActorRoles(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); return show; } - + private TvShow parseTvShowDetails(String response, TvShow show) { String[] fields = response.split(""); try { @@ -415,7 +523,7 @@ private TvShow parseTvShowDetails(String response, TvShow show) { } return show; } - + public Episode updateEpisodeDetails(INotifiableManager manager, Episode episode) { StringBuilder sb = new StringBuilder(); sb.append("SELECT c01 "); @@ -425,14 +533,16 @@ public Episode updateEpisodeDetails(INotifiableManager manager, Episode episode) episode = parseEpisodeDetails(mConnection.query("QueryVideoDatabase", sb.toString(), manager), episode); sb = new StringBuilder(); sb.append("SELECT actors.idActor, strActor, art.url, strRole"); - sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' AND art.type='thumb', actorlinkepisode"); + sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' AND " + + "art" + + ".type='thumb', actorlinkepisode"); sb.append(" WHERE actors.idActor = actorlinkepisode.idActor"); sb.append(" AND actorlinkepisode.idEpisode ="); sb.append(episode.id); episode.actors = VideoClient.parseActorRoles(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); return episode; } - + private Episode parseEpisodeDetails(String response, Episode episode) { String[] fields = response.split(""); try { @@ -444,78 +554,15 @@ private Episode parseEpisodeDetails(String response, Episode episode) { } return episode; } - - static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { - return new ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - return map.get("Show Title"); - } - public int getTime() { - return parseTime(map.get("Time")); - } - public int getPlayStatus() { - return PlayStatus.parse(map.get("PlayStatus")); - } - public int getPlaylistPosition() { - return Integer.parseInt(map.get("VideoNo")); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return Integer.valueOf(map.get("Percentage")); - } catch (NumberFormatException e) { } - return Float.valueOf(map.get("Percentage")); - } - public String getFilename() { - return map.get("Filename"); - } - public int getDuration() { - return parseTime(map.get("Duration")); - } - public String getArtist() { - if(Integer.valueOf(map.get("Season")) == 0) { - return "Specials / Episode " + map.get("Episode"); - } - else { - return "Season " + map.get("Season") + " / Episode " + map.get("Episode"); - } - } - public String getAlbum() { - return map.get("Title"); - } - public int getMediaType() { - return MediaType.VIDEO_TVSHOW; - } - public boolean isPlaying() { - return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - private int parseTime(String time) { - String[] s = time.split(":"); - if (s.length == 2) { - return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); - } else if (s.length == 3) { - return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); - } else { - return 0; - } - } - }; - } - + /** * Returns a pre-resized movie cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. + * @param cover Cover object + * @param size Minmal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { @@ -534,26 +581,27 @@ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { public int season; public int episode; */ + /** - * Episode DB Fields: - * idEpisode integer Primary Key - * c00: Episode Title - * c01: Plot Summary - * c03: Rating - * c04: Writer - * c05: First Aired - * c06: Thumbnail URL - * c08: Has the episode been watched? - * c10: Director - * c12: Season - * c13: Episode Number - * idFile: Foreign key to the files table - */ + * Episode DB Fields: + * idEpisode integer Primary Key + * c00: Episode Title + * c01: Plot Summary + * c03: Rating + * c04: Writer + * c05: First Aired + * c06: Thumbnail URL + * c08: Has the episode been watched? + * c10: Director + * c12: Season + * c13: Episode Number + * idFile: Foreign key to the files table + */ protected ArrayList parseEpisodes(String response) { ArrayList episodes = new ArrayList(); String[] fields = response.split(""); try { - for(int row = 1; row < fields.length; row += 15) { + for (int row = 1; row < fields.length; row += 15) { episodes.add(new Episode(Connection.trimInt(fields[row]), Connection.trim(fields[row + 1]), Connection.trim(fields[row + 2]), @@ -568,7 +616,7 @@ protected ArrayList parseEpisodes(String response) { Connection.trim(fields[row + 12]), Connection.trim(fields[row + 13]), Connection.trim(fields[row + 14]) - )); + )); } } catch (Exception e) { System.err.println("ERROR: " + e.getMessage()); @@ -583,17 +631,18 @@ protected ArrayList parseSeasons(String response, TvShow show) { ArrayList seasons = new ArrayList(); String[] fields = response.split(""); try { - for( int row = 1; row < fields.length; row += 2) { - seasons.add(new Season(Connection.trimInt(fields[row]), false, show, Connection.trim(fields[row+1]))); + for (int row = 1; row < fields.length; row += 2) { + seasons.add(new Season(Connection.trimInt(fields[row]), false, show, + Connection.trim(fields[row + 1]))); } - }catch (Exception e) { + } catch (Exception e) { System.err.println("ERROR: " + e.getMessage()); System.err.println("response = " + response); e.printStackTrace(); } return seasons; } - + protected ArrayList parseSeasons(String response, HashMap showMap) { ArrayList seasons = new ArrayList(); String[] fields = response.split(""); @@ -601,17 +650,18 @@ protected ArrayList parseSeasons(String response, HashMap"); @@ -640,15 +690,18 @@ protected ArrayList parseShows(String response) { } return shows; } - + private String showsOrderBy(int sortBy, String sortOrder) { switch (sortBy) { default: return " ORDER BY lower(tvshow.c00) asc"; case SortType.TITLE: - return " ORDER BY CASE WHEN tvshow.c15 IS NULL OR tvshow.c15 = '' THEN replace(lower(tvshow.c00),'the ','') ELSE replace(lower(tvshow.c15),'the ','') END " + sortOrder; + return " ORDER BY CASE WHEN tvshow.c15 IS NULL OR tvshow.c15 = '' THEN replace(lower(tvshow.c00)," + + "'the ','') ELSE replace(lower(tvshow.c15),'the ','') END " + sortOrder; case SortType.YEAR: - return " ORDER BY tvshow.c05 " + sortOrder + ", CASE WHEN tvshow.c15 IS NULL OR tvshow.c15 = '' THEN lower(tvshow.c00) ELSE lower(tvshow.c15) END " + sortOrder; + return " ORDER BY tvshow.c05 " + sortOrder + ", CASE WHEN tvshow.c15 IS NULL OR tvshow.c15 = '' THEN" + + " " + + "lower(tvshow.c00) ELSE lower(tvshow.c15) END " + sortOrder; case SortType.RATING: return " ORDER BY ROUND(tvshow.c04, 2) " + sortOrder; case SortType.EPISODE_NUM: @@ -662,6 +715,7 @@ private String showsOrderBy(int sortBy, String sortOrder) { /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { diff --git a/src/org/xbmc/httpapi/client/VideoClient.java b/app/src/main/java/org/xbmc/httpapi/client/VideoClient.java similarity index 80% rename from src/org/xbmc/httpapi/client/VideoClient.java rename to app/src/main/java/org/xbmc/httpapi/client/VideoClient.java index f81c34b9..7a95548e 100644 --- a/src/org/xbmc/httpapi/client/VideoClient.java +++ b/app/src/main/java/org/xbmc/httpapi/client/VideoClient.java @@ -21,12 +21,11 @@ package org.xbmc.httpapi.client; -import java.util.ArrayList; -import java.util.HashMap; +import android.graphics.Bitmap; import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IVideoClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.IVideoClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Actor; import org.xbmc.api.object.Genre; @@ -37,46 +36,221 @@ import org.xbmc.api.type.SortType; import org.xbmc.httpapi.Connection; -import android.graphics.Bitmap; +import java.util.ArrayList; +import java.util.HashMap; /** * Takes care of everything related to the video database. - * + * * @author Team XBMC */ public class VideoClient extends Client implements IVideoClient { - - private static final String MOVIE_COLUMNS = "idMovie, c00, c07, strPath, strFileName, c15, c11, c14, ROUND(c05, 2), playCount, c09, art.url"; - - private static final String SELECT_MOVIES = "SELECT" + " " + MOVIE_COLUMNS; - - private static final String WHERE_MOVIES = " " + "FROM" + " " + "movie, files, path, art"; public static final String TAG = "VideoClient"; - public static final String PLAYLIST_ID = "1"; - public static final int PLAYLIST_LIMIT = 100; - + private static final String MOVIE_COLUMNS = "idMovie, c00, c07, strPath, strFileName, c15, c11, c14, ROUND(c05, " + + "2), playCount, c09, art.url"; + private static final String SELECT_MOVIES = "SELECT" + " " + MOVIE_COLUMNS; + private static final String WHERE_MOVIES = " " + "FROM" + " " + "movie, files, path, art"; + /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public VideoClient(Connection connection) { super(connection); } - + + /** + * Converts query response from HTTP API to a list of Actor objects. Each + * row must return the following columns in the following order: + *
      + *
    1. idActor
    2. + *
    3. strActor
    4. + *
    + * + * @param response + * @return List of Actors + */ + public static ArrayList parseActors(String response) { + ArrayList actors = new ArrayList(); + String[] fields = response.split(""); + try { + for (int row = 1; row < fields.length; row += 3) { + actors.add(new Actor( + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]), + Connection.trim(fields[row + 2]) + )); + } + } catch (Exception e) { + System.err.println("ERROR: " + e.getMessage()); + System.err.println("response = " + response); + e.printStackTrace(); + } + return actors; + } + + /** + * Converts query response from HTTP API to a list of Actor objects with + * roles attached. Each row must return the following columns in the + * following order: + *
      + *
    1. idActor
    2. + *
    3. strActor
    4. + *
    5. strRole
    6. + *
    + * + * @param response + * @return List of Actors + */ + public static ArrayList parseActorRoles(String response) { + ArrayList actors = new ArrayList(); + String[] fields = response.split(""); + try { + for (int row = 1; row < fields.length; row += 4) { + actors.add(new Actor( + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]), + Connection.trim(fields[row + 2]), + Connection.trim(fields[row + 3]) + )); + } + } catch (Exception e) { + System.err.println("ERROR: " + e.getMessage()); + System.err.println("response = " + response); + e.printStackTrace(); + } + return actors; + } + + /** + * Converts query response from HTTP API to a list of Genre objects. Each + * row must return the following columns in the following order: + *
      + *
    1. idGenre
    2. + *
    3. strGenre
    4. + *
    + * + * @param response + * @return List of Genres + */ + public static ArrayList parseGenres(String response) { + ArrayList genres = new ArrayList(); + String[] fields = response.split(""); + try { + for (int row = 1; row < fields.length; row += 2) { + genres.add(new Genre( + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]) + )); + } + } catch (Exception e) { + System.err.println("ERROR: " + e.getMessage()); + System.err.println("response = " + response); + e.printStackTrace(); + } + return genres; + } + + static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { + + return new ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + String title = map.get("Title"); + if (title != null) + return title; + String[] path = map.get("Filename").replaceAll("\\\\", "/").split("/"); + return path[path.length - 1]; + } + + public int getTime() { + return parseTime(map.get("Time")); + } + + public int getPlayStatus() { + return PlayStatus.parse(map.get("PlayStatus")); + } + + public int getPlaylistPosition() { + return Integer.parseInt(map.get("VideoNo")); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return Integer.valueOf(map.get("Percentage")); + } catch (NumberFormatException e) { + } + return Float.valueOf(map.get("Percentage")); + } + + public String getFilename() { + return map.get("Filename"); + } + + public int getDuration() { + return parseTime(map.get("Duration")); + } + + public String getArtist() { + return map.get("Genre"); + } + + public String getAlbum() { + String title = map.get("Tagline"); + if (title != null) + return title; + String path = map.get("Filename").replaceAll("\\\\", "/"); + return path.substring(0, path.lastIndexOf("/")); + } + + public int getMediaType() { + return MediaType.VIDEO; + } + + public boolean isPlaying() { + return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + + private int parseTime(String time) { + String[] s = time.split(":"); + if (s.length == 2) { + return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); + } else if (s.length == 3) { + return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); + } else { + return 0; + } + } + }; + } + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - + /** * Gets all movies from database - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies */ @@ -84,41 +258,48 @@ public ArrayList getMovies(INotifiableManager manager, int sortBy, String StringBuilder sb = new StringBuilder(); sb.append(SELECT_MOVIES); sb.append(WHERE_MOVIES); - sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND art.media_type='movie' AND art.type='thumb'"); + sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND " + + "art.media_type='movie' AND art.type='thumb'"); sb.append(watchedFilter(hideWatched)); sb.append(moviesOrderBy(sortBy, sortOrder)); return parseMovies(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets movies from database with offset - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Movies with offset */ - public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, boolean hideWatched) { + public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); sb.append(SELECT_MOVIES); sb.append(WHERE_MOVIES); - sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND art.media_type='movie' AND art.type='thumb'"); + sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND " + + "art.media_type='movie' AND art.type='thumb'"); sb.append(watchedFilter(hideWatched)); sb.append(moviesOrderBy(sortBy, sortOrder)); sb.append(" LIMIT -1 OFFSET " + offset); return parseMovies(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movies with an actor from database - * @param actor Display only movies with this actor. - * @param sortBy Sort field, see SortType.* + * + * @param actor Display only movies with this actor. + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies with an actor */ - public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); sb.append(SELECT_MOVIES); sb.append(WHERE_MOVIES); - sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND art.media_type='movie' AND art.type='thumb' AND movie.idmovie IN ("); + sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND " + + "art.media_type='movie' AND art.type='thumb' AND movie.idmovie IN ("); sb.append(" SELECT DISTINCT idMovie "); sb.append(" FROM actorlinkmovie "); sb.append(" WHERE idActor ="); @@ -128,19 +309,23 @@ public ArrayList getMovies(INotifiableManager manager, Actor actor, int s sb.append(moviesOrderBy(sortBy, sortOrder)); return parseMovies(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movies of a genre from database - * @param genre Display only movies of this genre. - * @param sortBy Sort field, see SortType.* + * + * @param genre Display only movies of this genre. + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies of a genre */ - public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched) { StringBuilder sb = new StringBuilder(); sb.append(SELECT_MOVIES); sb.append(WHERE_MOVIES); - sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND art.media_type='movie' AND art.type='thumb' AND movie.idmovie IN ("); + sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND" + + " " + + "art.media_type='movie' AND art.type='thumb' AND movie.idmovie IN ("); sb.append(" SELECT DISTINCT idMovie "); sb.append(" FROM genrelinkmovie "); sb.append(" WHERE idGenre ="); @@ -150,71 +335,81 @@ public ArrayList getMovies(INotifiableManager manager, Genre genre, int s sb.append(moviesOrderBy(sortBy, sortOrder)); return parseMovies(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movies from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * * @return Updated movie */ public Movie updateMovieDetails(INotifiableManager manager, Movie movie) { StringBuilder sb = new StringBuilder(); sb.append("SELECT c03, c01, c04, c18, c12, c19"); sb.append(WHERE_MOVIES); - sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND art.media_type='movie' AND art.type='thumb' AND movie.idmovie = "); + sb.append(" WHERE movie.idFile=files.idFile AND path.idPath=files.idPath AND movie.idMovie=art.media_id AND " + + "art.media_type='movie' AND art.type='thumb' AND movie.idmovie = "); sb.append(movie.getId()); parseMovieDetails(mConnection.query("QueryVideoDatabase", sb.toString(), manager), movie); sb = new StringBuilder(); sb.append("SELECT actors.idActor, strActor, art.url, strRole"); - sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=idActor AND art.media_type='actor' and art.type='thumb', actorlinkmovie"); + sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=idActor AND art.media_type='actor' and art" + + ".type='thumb', actorlinkmovie"); sb.append(" WHERE actors.idActor = actorlinkmovie.idActor"); sb.append(" AND actorlinkmovie.idMovie ="); sb.append(movie.getId()); movie.actors = parseActorRoles(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); return movie; } - + /** - * Gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. + * Gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * * @return All actors */ public ArrayList getActors(INotifiableManager manager) { StringBuilder sb = new StringBuilder(); sb.append("SELECT idActor, strActor, art.url"); - sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=idActor AND art.media_type='actor' and art.type='thumb'"); + sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=idActor AND art.media_type='actor' and art" + + ".type='thumb'"); sb.append(" ORDER BY upper(strActor), strActor"); return parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movie actors from database + * * @return All movie actors */ public ArrayList getMovieActors(INotifiableManager manager) { StringBuilder sb = new StringBuilder(); sb.append("SELECT DISTINCT actors.idActor, strActor, art.url"); - sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' and art.type='thumb', actorlinkmovie"); + sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' and " + + "art" + + ".type='thumb', actorlinkmovie"); sb.append(" WHERE actorlinkmovie.idActor = actors.idActor"); sb.append(" ORDER BY upper(strActor), strActor"); return parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movie actors from database + * * @return All movie actors */ public ArrayList getTvShowActors(INotifiableManager manager) { StringBuilder sb = new StringBuilder(); sb.append("SELECT DISTINCT actors.idActor, strActor, art.url"); - sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' and art.type='thumb', actorlinktvshow"); + sb.append(" FROM actors LEFT OUTER JOIN art ON art.media_id=actors.idActor AND art.media_type='actor' and " + + "art" + + ".type='thumb', actorlinktvshow"); sb.append(" WHERE actorlinktvshow.idActor = actors.idActor"); sb.append(" ORDER BY upper(strActor), strActor"); return parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movie genres from database + * * @return All movie genres */ public ArrayList getMovieGenres(INotifiableManager manager) { @@ -224,9 +419,10 @@ public ArrayList getMovieGenres(INotifiableManager manager) { sb.append(" ORDER BY upper(strGenre)"); return parseGenres(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all tv show genres from database + * * @return All tv show genres */ public ArrayList getTvShowGenres(INotifiableManager manager) { @@ -241,32 +437,34 @@ public ArrayList getTvShowGenres(INotifiableManager manager) { * Returns a pre-resized movie cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. + * @param cover Cover object + * @param size Minmal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { return getCover(manager, cover, size, Movie.getThumbUri(cover), Movie.getFallbackThumbUri(cover)); } - + /** * Converts query response from HTTP API to a list of Movie objects. Each * row must return the following attributes in the following order: *
      - *
    1. idMovie
    2. - *
    3. c00
    4. (title) - *
    5. c07
    6. (year) - *
    7. strPath
    8. - *
    9. strFileName
    10. - *
    11. c15
    12. (director) - *
    13. c11
    14. (runtime) - *
    15. c14
    16. (genres) - *
    17. c05
    18. (rating) - *
    19. playCount
    20. (numWatched) - *
    21. c09
    22. (imdbId) + *
    23. idMovie
    24. + *
    25. c00
    26. (title) + *
    27. c07
    28. (year) + *
    29. strPath
    30. + *
    31. strFileName
    32. + *
    33. c15
    34. (director) + *
    35. c11
    36. (runtime) + *
    37. c14
    38. (genres) + *
    39. c05
    40. (rating) + *
    41. playCount
    42. (numWatched) + *
    43. c09
    44. (imdbId) *
    45. c08
    46. (art url for hashing to get filename) - *
    + * + * * @param response * @return List of movies */ @@ -275,9 +473,10 @@ private ArrayList parseMovies(String response) { String[] fields = response.split(""); try { for (int row = 1; row < fields.length; row += 12) { //WHen adding a field, be sure to change this # - movies.add(new Movie( // int id, String title, int year, String path, String filename, String director, String runtime, String genres, Double rating, int numWatched, String imdbId - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), + movies.add(new Movie( // int id, String title, int year, String path, String filename, + // String director, String runtime, String genres, Double rating, int numWatched, String imdbId + Connection.trimInt(fields[row]), + Connection.trim(fields[row + 1]), Connection.trimInt(fields[row + 2]), Connection.trim(fields[row + 3]), Connection.trim(fields[row + 4]), @@ -297,19 +496,20 @@ private ArrayList parseMovies(String response) { } return movies; } - + /** * Updates a movie object with some more details. Fields must be the following (in this order): *
      - *
    1. c03
    2. (tagline) - *
    3. c01
    4. (plot) - *
    5. c04
    6. (number of votes) - *
    7. c18
    8. (studio) - *
    9. c12
    10. (parental rating) - *
    11. c19
    12. (trailer) - *
    + *
  • c03
  • (tagline) + *
  • c01
  • (plot) + *
  • c04
  • (number of votes) + *
  • c18
  • (studio) + *
  • c12
  • (parental rating) + *
  • c19
  • (trailer) + * + * * @param response - * @param movie + * @param movie * @return Updated movie object */ private Movie parseMovieDetails(String response, Movie movie) { @@ -328,96 +528,6 @@ private Movie parseMovieDetails(String response, Movie movie) { } return movie; } - - - /** - * Converts query response from HTTP API to a list of Actor objects. Each - * row must return the following columns in the following order: - *
      - *
    1. idActor
    2. - *
    3. strActor
    4. - *
    - * @param response - * @return List of Actors - */ - public static ArrayList parseActors(String response) { - ArrayList actors = new ArrayList(); - String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 3) { - actors.add(new Actor( - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), - Connection.trim(fields[row+2]) - )); - } - } catch (Exception e) { - System.err.println("ERROR: " + e.getMessage()); - System.err.println("response = " + response); - e.printStackTrace(); - } - return actors; - } - - /** - * Converts query response from HTTP API to a list of Actor objects with - * roles attached. Each row must return the following columns in the - * following order: - *
      - *
    1. idActor
    2. - *
    3. strActor
    4. - *
    5. strRole
    6. - *
    - * @param response - * @return List of Actors - */ - public static ArrayList parseActorRoles(String response) { - ArrayList actors = new ArrayList(); - String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 4) { - actors.add(new Actor( - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]), - Connection.trim(fields[row + 2]), - Connection.trim(fields[row + 3]) - )); - } - } catch (Exception e) { - System.err.println("ERROR: " + e.getMessage()); - System.err.println("response = " + response); - e.printStackTrace(); - } - return actors; - } - - /** - * Converts query response from HTTP API to a list of Genre objects. Each - * row must return the following columns in the following order: - *
      - *
    1. idGenre
    2. - *
    3. strGenre
    4. - *
    - * @param response - * @return List of Genres - */ - public static ArrayList parseGenres(String response) { - ArrayList genres = new ArrayList(); - String[] fields = response.split(""); - try { - for (int row = 1; row < fields.length; row += 2) { - genres.add(new Genre( - Connection.trimInt(fields[row]), - Connection.trim(fields[row + 1]) - )); - } - } catch (Exception e) { - System.err.println("ERROR: " + e.getMessage()); - System.err.println("response = " + response); - e.printStackTrace(); - } - return genres; - } private String watchedFilter(boolean hideWatched) { if (hideWatched) { @@ -426,9 +536,10 @@ private String watchedFilter(boolean hideWatched) { return ""; } } - + /** * Returns an SQL String of given sort options of movies query + * * @param sortBy Sort field * @param sortOrder Sort order * @return SQL "ORDER BY" string @@ -437,112 +548,51 @@ private String moviesOrderBy(int sortBy, String sortOrder) { switch (sortBy) { default: case SortType.TITLE: - return " ORDER BY CASE WHEN c10 IS NULL OR c10 = '' THEN replace(lower(c00),'the ','') ELSE replace(lower(c10),'the ','') END " + sortOrder; + return " ORDER BY CASE WHEN c10 IS NULL OR c10 = '' THEN replace(lower(c00),'the ','') ELSE replace" + + "(lower(c10),'the ','') END " + sortOrder; case SortType.YEAR: - return " ORDER BY c07 " + sortOrder + ", CASE WHEN c10 IS NULL OR c10 = '' THEN lower(c00) ELSE lower(c10) END " + sortOrder; + return " ORDER BY c07 " + sortOrder + ", CASE WHEN c10 IS NULL OR c10 = '' THEN lower(c00) ELSE " + + "lower" + + "(c10) END " + sortOrder; case SortType.RATING: return " ORDER BY ROUND(c05, 2) " + sortOrder; case SortType.DATE_ADDED: return " ORDER BY files.idFile " + sortOrder; } } - - static ICurrentlyPlaying getCurrentlyPlaying(final HashMap map) { - - return new ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - String title = map.get("Title"); - if (title != null) - return title; - String[] path = map.get("Filename").replaceAll("\\\\", "/").split("/"); - return path[path.length - 1]; - } - public int getTime() { - return parseTime(map.get("Time")); - } - public int getPlayStatus() { - return PlayStatus.parse(map.get("PlayStatus")); - } - public int getPlaylistPosition() { - return Integer.parseInt(map.get("VideoNo")); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return Integer.valueOf(map.get("Percentage")); - } catch (NumberFormatException e) { } - return Float.valueOf(map.get("Percentage")); - } - public String getFilename() { - return map.get("Filename"); - } - public int getDuration() { - return parseTime(map.get("Duration")); - } - public String getArtist() { - return map.get("Genre"); - } - public String getAlbum() { - String title = map.get("Tagline"); - if (title != null) - return title; - String path = map.get("Filename").replaceAll("\\\\", "/"); - return path.substring(0, path.lastIndexOf("/")); - } - public int getMediaType() { - return MediaType.VIDEO; - } - public boolean isPlaying() { - return PlayStatus.parse(map.get("PlayStatus")) == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - private int parseTime(String time) { - String[] s = time.split(":"); - if (s.length == 2) { - return Integer.parseInt(s[0]) * 60 + Integer.parseInt(s[1]); - } else if (s.length == 3) { - return Integer.parseInt(s[0]) * 3600 + Integer.parseInt(s[1]) * 60 + Integer.parseInt(s[2]); - } else { - return 0; - } - } - }; - } /** * Retrieves the currently playing video number in the playlist. + * * @return Number of items in the playlist */ public int getPlaylistPosition(INotifiableManager manager) { return mConnection.getInt(manager, "GetPlaylistSong"); } - + /** * Sets the media at playlist position to be the next item to be played. + * * @param position New position, starting with 0. * @return True on success, false otherwise. */ public boolean setPlaylistPosition(INotifiableManager manager, int position) { return mConnection.getBoolean(manager, "SetPlaylistSong", String.valueOf(position)); } - + /** - * Returns the first {@link PLAYLIST_LIMIT} videos of the playlist. + * Returns the first videos of the playlist. + * * @return Videos in the playlist. */ public ArrayList getPlaylist(INotifiableManager manager) { return mConnection.getArray(manager, "GetPlaylistContents", PLAYLIST_ID); } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. + * + * @param path Complete path (including filename) of the media to be removed. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, String path) { diff --git a/src/org/xbmc/jsonrpc/Connection.java b/app/src/main/java/org/xbmc/jsonrpc/Connection.java similarity index 85% rename from src/org/xbmc/jsonrpc/Connection.java rename to app/src/main/java/org/xbmc/jsonrpc/Connection.java index ea58e89f..7ca77a7c 100644 --- a/src/org/xbmc/jsonrpc/Connection.java +++ b/app/src/main/java/org/xbmc/jsonrpc/Connection.java @@ -21,17 +21,8 @@ package org.xbmc.jsonrpc; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.Authenticator; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.PasswordAuthentication; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLConnection; +import android.util.Log; + import org.apache.http.HttpException; import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.JsonFactory; @@ -46,37 +37,45 @@ import org.xbmc.httpapi.NoSettingsException; import org.xbmc.jsonrpc.client.Client; -import android.util.Log; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.Authenticator; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.PasswordAuthentication; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; /** * Singleton class. Will be instantiated only once and contains mostly help - * + * * @author Team XBMC */ public class Connection { + public static final String RESULT_FIELD = "result"; + public static final String ERROR_FIELD = "error"; private static final String TAG = "Connection-JsonRpc"; - private static final String XBMC_JSONRPC_BOOTSTRAP = "/jsonrpc"; private static final int SOCKET_CONNECTION_TIMEOUT = 5000; - + ; /** * Singleton class instance */ private static Connection sConnection; - /** * Complete URL without any attached command parameters, for instance: * http://192.168.0.10:8080 */ - private String mUrlSuffix;; - + private String mUrlSuffix; /** * Socket read timeout (connection timeout is default) */ private int mSocketReadTimeout = 0; - /** * Holds the base64 encoded user/pass for http authentication */ @@ -84,17 +83,19 @@ public class Connection { /** * Use getInstance() for public class instantiation + * * @param host XBMC host * @param port Port */ private Connection(String host, int port) { setHost(host, port); } - + /** - * Returns the singleton instance of this connection. Note that host and - * port settings are only looked at the first time. Use {@link setHost()} + * Returns the singleton instance of this connection. Note that host and + * port settings are only looked at the first time. Use {@link #setHost} * if you want to update these parameters. + * * @param host XBMC host * @param port HTTP API / JSON-RPC port (it's the same) * @return Connection instance @@ -108,9 +109,10 @@ public static Connection getInstance(String host, int port) { } return sConnection; } - + /** * Updates host info of the connection instance + * * @param host */ public void setHost(Host host) { @@ -121,9 +123,10 @@ public void setHost(Host host) { setAuth(host.user, host.pass); } } - + /** * Updates host and port parameters of the connection instance. + * * @param host Host or IP address of the host * @param port HTTP port */ @@ -139,9 +142,10 @@ public void setHost(String host, int port) { mUrlSuffix = sb.toString(); } } - + /** * Sets authentication info + * * @param user Username * @param pass Password */ @@ -153,17 +157,18 @@ public void setAuth(String user, String pass) { authEncoded = null; } } - + /** * Sets socket read timeout (connection timeout has constant value) + * * @param timeout Read timeout in milliseconds. */ public void setTimeout(int timeout) { if (timeout > 0) { mSocketReadTimeout = timeout; } - } - + } + public InputStream getThumbInputStream(String thumb, INotifiableManager manager) throws FileNotFoundException { URLConnection uc = null; try { @@ -185,11 +190,10 @@ public InputStream getThumbInputStream(String thumb, INotifiableManager manager) } return null; } - + /** * Returns the full URL of an HTTP API request - * @param command Name of the command to execute - * @param parameters Parameters, separated by ";". + * * @return Absolute URL to HTTP API */ public String getUrl(String path) { @@ -199,28 +203,28 @@ public String getUrl(String path) { sb.append(path); return sb.toString(); } - + public byte[] download(String pathToDownload) throws IOException, URISyntaxException { try { final URL url = new URL(pathToDownload); final URLConnection uc = getUrlConnection(url); - + final InputStream is = uc.getInputStream(); final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - + byte[] data = new byte[8192]; int nRead; while ((nRead = is.read(data, 0, data.length)) != -1) { - buffer.write(data, 0, nRead); - } + buffer.write(data, 0, nRead); + } return buffer.toByteArray(); - + } catch (Exception e) { return null; } } - + /** * Create a new URLConnection with the request headers set, including authentication. * @@ -240,9 +244,10 @@ private URLConnection getUrlConnection(URL url) throws IOException { return uc; } - + /** * Executes a query. + * * @param command Name of the command to execute * @param parameters Parameters * @param manager Reference back to business layer @@ -266,15 +271,15 @@ public JsonNode query(String command, JsonNode parameters, INotifiableManager ma } uc.setRequestProperty("Content-Type", "application/json"); uc.setDoOutput(true); - + final ObjectNode data = Client.obj() - .p("jsonrpc", "2.0") - .p("method", command) - .p("id", "1"); + .p("jsonrpc", "2.0") + .p("method", command) + .p("id", "1"); if (parameters != null) { data.put("params", parameters); } - + final JsonFactory jsonFactory = new JsonFactory(); final JsonGenerator jg = jsonFactory.createJsonGenerator(uc.getOutputStream(), JsonEncoding.UTF8); jg.setCodec(mapper); @@ -282,19 +287,20 @@ public JsonNode query(String command, JsonNode parameters, INotifiableManager ma // POST data jg.writeTree(data); jg.flush(); - + final JsonParser jp = jsonFactory.createJsonParser(uc.getInputStream()); jp.setCodec(mapper); final JsonNode ret = jp.readValueAs(JsonNode.class); return ret; - + } catch (MalformedURLException e) { manager.onError(e); } catch (IOException e) { int responseCode = -1; try { - responseCode = ((HttpURLConnection)uc).getResponseCode(); - } catch (IOException e1) { } // do nothing, getResponse code failed so treat as default i/o exception. + responseCode = ((HttpURLConnection) uc).getResponseCode(); + } catch (IOException e1) { + } // do nothing, getResponse code failed so treat as default i/o exception. if (uc != null && responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { manager.onError(new HttpException(Integer.toString(HttpURLConnection.HTTP_UNAUTHORIZED))); } else { @@ -305,12 +311,13 @@ public JsonNode query(String command, JsonNode parameters, INotifiableManager ma } return new ObjectNode(null); } - + /** * Executes a JSON-RPC command and returns the result as JSON object. - * @param manager Upper layer reference for error posting - * @param method Name of the method to run - * @param parameters Parameters of the method + * + * @param manager Upper layer reference for error posting + * @param method Name of the method to run + * @param parameters Parameters of the method * @return Result */ public JsonNode getJson(INotifiableManager manager, String method, JsonNode parameters) { @@ -320,9 +327,9 @@ public JsonNode getJson(INotifiableManager manager, String method, JsonNode para if (result == null) { if (response.get(ERROR_FIELD) == null) { throw new Exception("Weird JSON response, could not parse error."); - }else if(!response.get(ERROR_FIELD).get("message").getTextValue().equals("Invalid params.")){ + } else if (!response.get(ERROR_FIELD).get("message").getTextValue().equals("Invalid params.")) { throw new Exception(response.get(ERROR_FIELD).get("message").getTextValue()); - }else{ + } else { Log.d(TAG, "Request returned Invalid Params."); } } else { @@ -333,7 +340,7 @@ public JsonNode getJson(INotifiableManager manager, String method, JsonNode para } return Client.obj(); } - + public JsonNode getJson(INotifiableManager manager, String method, JsonNode parameters, String resultField) { try { final JsonNode response = getJson(manager, method, parameters); @@ -348,20 +355,22 @@ public JsonNode getJson(INotifiableManager manager, String method, JsonNode para } return Client.obj(); } - + /** * Executes a JSON-RPC command without parameters and returns the result as * JSON object. - * @param manager Upper layer reference for error posting - * @param method Name of the method to run + * + * @param manager Upper layer reference for error posting + * @param method Name of the method to run * @return Result */ public JsonNode getJson(INotifiableManager manager, String method) { return query(method, null, manager).get(RESULT_FIELD); } - + /** * Executes an JSON-RPC method and returns the result from a field as string. + * * @param manager Upper layer reference for error posting * @param method Name of the method to run * @param parameters Parameters of the method, separated by ";" @@ -369,20 +378,20 @@ public JsonNode getJson(INotifiableManager manager, String method) { * @return Result */ public String getString(INotifiableManager manager, String method, ObjectNode parameters, String returnField) { - final JsonNode result = (JsonNode)query(method, parameters, manager).get(RESULT_FIELD); - if(returnField == null) + final JsonNode result = (JsonNode) query(method, parameters, manager).get(RESULT_FIELD); + if (returnField == null) return result == null ? "" : result.getValueAsText(); else return result == null ? "" : result.get(returnField).getValueAsText(); } - - + public String getString(INotifiableManager manager, String method, ObjectNode parameters) { return getString(manager, method, parameters, null); } - + /** * Executes an JSON-RPC method and returns the result from a field as integer. + * * @param manager Upper layer reference for error posting * @param method Name of the method to run * @param parameters Parameters of the method, separated by ";" @@ -398,8 +407,9 @@ public int getInt(INotifiableManager manager, String method, ObjectNode paramete } /** - * Executes an JSON-RPC method without parameter and returns the result + * Executes an JSON-RPC method without parameter and returns the result * from a field as integer. + * * @param manager Upper layer reference for error posting * @param method Name of the method to run * @param returnField Name of the field to return @@ -408,9 +418,10 @@ public int getInt(INotifiableManager manager, String method, ObjectNode paramete public int getInt(INotifiableManager manager, String method, String returnField) { return getInt(manager, method, null, returnField); } - + /** * Executes an JSON-RPC method and returns the result from a field as boolean. + * * @param manager Upper layer reference for error posting * @param method Name of the method to run * @param parameters Parameters of the method, separated by ";" @@ -420,54 +431,52 @@ public int getInt(INotifiableManager manager, String method, String returnField) public boolean getBoolean(INotifiableManager manager, String method, ObjectNode parameters, String returnField) { return getString(manager, method, parameters, returnField).equals("true"); } - + /** - * Executes an JSON-RPC method without parameters and returns the result + * Executes an JSON-RPC method without parameters and returns the result * from a field as boolean. - * @param manager Upper layer reference for error posting - * @param method Name of the method to run - * @param returnField Name of the field to return + * + * @param manager Upper layer reference for error posting + * @param method Name of the method to run * @return Result as boolean */ public boolean getBoolean(INotifiableManager manager, String method, ObjectNode parameters) { return getBoolean(manager, method, parameters, null); } - + /** * HTTP Authenticator. + * * @author Team XBMC */ - public class HttpAuthenticator extends Authenticator { - public static final int MAX_RETRY = 5; - - private final String mUser; - private final char[] mPass; - private int mRetryCount = 0; - - public HttpAuthenticator(String user, String pass) { - mUser = user; - mPass = pass != null ? pass.toCharArray() : new char[0]; + public class HttpAuthenticator extends Authenticator { + public static final int MAX_RETRY = 5; + + private final String mUser; + private final char[] mPass; + private int mRetryCount = 0; + + public HttpAuthenticator(String user, String pass) { + mUser = user; + mPass = pass != null ? pass.toCharArray() : new char[0]; } - /** - * This method is called when a password-protected URL is accessed - */ - protected PasswordAuthentication getPasswordAuthentication() { - if (mRetryCount < MAX_RETRY) { - mRetryCount++; - return new PasswordAuthentication(mUser, mPass); - } - return null; - } - - /** - * This method has to be called after each successful connection!!! - */ - public void resetCounter() { - mRetryCount = 0; - } - } - - public static final String RESULT_FIELD = "result"; - public static final String ERROR_FIELD = "error"; + /** + * This method is called when a password-protected URL is accessed + */ + protected PasswordAuthentication getPasswordAuthentication() { + if (mRetryCount < MAX_RETRY) { + mRetryCount++; + return new PasswordAuthentication(mUser, mPass); + } + return null; + } + + /** + * This method has to be called after each successful connection!!! + */ + public void resetCounter() { + mRetryCount = 0; + } + } } diff --git a/src/org/xbmc/jsonrpc/JsonRpc.java b/app/src/main/java/org/xbmc/jsonrpc/JsonRpc.java similarity index 99% rename from src/org/xbmc/jsonrpc/JsonRpc.java rename to app/src/main/java/org/xbmc/jsonrpc/JsonRpc.java index 84d264b8..ace1064d 100644 --- a/src/org/xbmc/jsonrpc/JsonRpc.java +++ b/app/src/main/java/org/xbmc/jsonrpc/JsonRpc.java @@ -32,39 +32,40 @@ * Wrapper class for JSON-RPC clients. The idea is to separate the loads of * API method we're going to have into separate classes. The ClientFactory class * instantiates them and keeps them in a central place. - * + * * @author Team XBMC */ public class JsonRpc { - - + + /** * Use this client for anything system related */ public final InfoClient info; - + /** * Use this client for anything music related */ public final MusicClient music; - + /** * Use this client for anything video related */ public final VideoClient video; - + /** * Use this client for anything media controller related */ public final ControlClient control; - + /** * Use this client for anything tv show related */ public final TvShowClient shows; - + /** * Construct with all paramaters + * * @param host Connection data of the host * @param timeout Read timeout */ @@ -83,9 +84,10 @@ public JsonRpc(Host host, int timeout) { control = new ControlClient(connection); shows = new TvShowClient(connection); } - + /** * Updates host info on all clients + * * @param host */ public void setHost(Host host) { diff --git a/src/org/xbmc/jsonrpc/client/Client.java b/app/src/main/java/org/xbmc/jsonrpc/client/Client.java similarity index 91% rename from src/org/xbmc/jsonrpc/client/Client.java rename to app/src/main/java/org/xbmc/jsonrpc/client/Client.java index ec10fda5..526963e9 100644 --- a/src/org/xbmc/jsonrpc/client/Client.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/Client.java @@ -21,13 +21,10 @@ package org.xbmc.jsonrpc.client; -import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.text.DecimalFormat; -import java.util.Iterator; +import android.graphics.Bitmap; +import android.graphics.Bitmap.CompressFormat; +import android.graphics.BitmapFactory; +import android.util.Log; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; @@ -42,18 +39,21 @@ import org.xbmc.api.type.ThumbSize.Dimension; import org.xbmc.jsonrpc.Connection; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Bitmap.CompressFormat; -import android.util.Log; +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.text.DecimalFormat; +import java.util.Iterator; /** * Abstract super class of all (media) clients. - * + * * @author Team XBMC */ public abstract class Client { - + public static final String TAG = "Client-JSON-RPC"; public static final String PARAM_FIELDS = "fields"; public static final String PARAM_PROPERTIES = "properties"; @@ -66,63 +66,156 @@ public abstract class Client { /** * Class constructor needs reference to HTTP client connection + * * @param connection */ Client(Connection connection) { mConnection = connection; } - - public int getActivePlayerId(INotifiableManager manager){ + + /** + * Returns an SQL String of given sort options of albums query + * + * @param sortBy Sort field + * @param sortOrder Sort order + * @return SQL "ORDER BY" string + */ + protected static ObjNode sort(ObjNode params, int sortBy, String sortOrder) { + + + final String order = sortOrder.equals(SortType.ORDER_DESC) ? "descending" : "ascending"; + final String sortby; + switch (sortBy) { + default: + case SortType.ALBUM: + sortby = "label"; + break; + case SortType.ARTIST: + sortby = "artist"; + break; + case SortType.TRACK: + sortby = "track"; + break; + case SortType.TITLE: + sortby = "sorttitle"; + break; + case SortType.YEAR: + sortby = "year"; + break; + case SortType.RATING: + sortby = "rating"; + break; + case SortType.DATE_ADDED: + sortby = "dateadded"; + break; + } + + params.p(PARAM_SORT, obj().p("ignorearticle", true).p("method", sortby).p("order", order)); + return params; + } + + public final static ObjNode obj() { + return new ObjNode(FACTORY); + } + + public final static ArrayNode arr() { + return MAPPER.createArrayNode(); + } + + public final static String getString(JsonNode obj, String key) { + + if (obj.get(key) == null) + return ""; + else if (obj.get(key).isArray()) { + String retval = ""; + for (Iterator i = obj.get(key).getElements(); i.hasNext(); ) { + retval += i.next().getTextValue(); + if (i.hasNext()) + retval += ", "; + } + return retval; + } else + return getString(obj, key, ""); + } + + public final static String getString(JsonNode obj, String key, String ifNullResult) { + return obj.get(key) == null ? ifNullResult : obj.get(key).getTextValue(); + } + + public final static int getInt(JsonNode obj, String key) { + return obj.get(key) == null ? -1 : obj.get(key).getIntValue(); + } + + public final static double getDouble(JsonNode obj, String key) { + + if (obj.get(key) == null) + return -1; + + DecimalFormat twoDForm = new DecimalFormat("#.0"); + + double val = -1; + try { + val = Double.valueOf(twoDForm.format(obj.get(key).getDoubleValue()).replace(',', '.')); + } catch (NumberFormatException e) { + val = -1; + } + + return val; + } + + ; + + public int getActivePlayerId(INotifiableManager manager) { final JsonNode active = mConnection.getJson(manager, "Player.GetActivePlayers", null).get(0); - if(active == null) + if (active == null) return -1; else return getInt(active, "playerid"); } - + /** - * Downloads a cover. - * + * Downloads a cover. + *

    * First, only boundaries are downloaded in order to determine the sample * size. Setting sample size > 1 will do two things: *

    1. Only a fragment of the total size will be downloaded
    2. - *
    3. Resizing will be smooth and not pixelated as before
    + *
  • Resizing will be smooth and not pixelated as before
  • * The returned size is the next bigger (but smaller than the double) size * of the original image. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. - * @param url URL to primary cover - * @param fallbackUrl URL to fallback cover + * @param cover Cover object + * @param size Minmal size to pre-resize to. + * @param url URL to primary cover * @return Bitmap */ protected Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size, String url) { - - if(url == null) + + if (url == null) return null; - + final int mediaType = cover.getMediaType(); // don't fetch small sizes size = size < ThumbSize.BIG ? ThumbSize.MEDIUM : ThumbSize.BIG; InputStream is = null; try { Log.i(TAG, "Starting download (" + url + ")"); - + BitmapFactory.Options opts = prefetch(manager, url, size, mediaType); Dimension dim = ThumbSize.getTargetDimension(size, mediaType, opts.outWidth, opts.outHeight); - + Log.i(TAG, "Pre-fetch: " + opts.outWidth + "x" + opts.outHeight + " => " + dim); if (opts.outWidth < 0) { return null; } final int ss = ImportUtilities.calculateSampleSize(opts, dim); Log.i(TAG, "Sample size: " + ss); - + is = new BufferedInputStream(mConnection.getThumbInputStream(url, manager), 8192); opts.inDither = true; opts.inSampleSize = ss; opts.inJustDecodeBounds = false; - + Bitmap bitmap = BitmapFactory.decodeStream(is, null, opts); if (ss == 1) { bitmap = blowup(bitmap); @@ -144,11 +237,12 @@ protected Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size, if (is != null) { is.close(); } - } catch (IOException e) { } + } catch (IOException e) { + } } return null; } - + private BitmapFactory.Options prefetch(INotifiableManager manager, String url, int size, int mediaType) { BitmapFactory.Options opts = new BitmapFactory.Options(); try { @@ -160,138 +254,52 @@ private BitmapFactory.Options prefetch(INotifiableManager manager, String url, i } return opts; } - + /** - * Doubles the size of a bitmap and re-reads it with samplesize 2. I've + * Doubles the size of a bitmap and re-reads it with samplesize 2. I've * found no other way to smoothely resize images with samplesize = 1. + * * @param source * @return */ private Bitmap blowup(Bitmap source) { if (source != null) { - Bitmap big = Bitmap.createScaledBitmap(source, source.getWidth() * 2, source.getHeight() * 2, true); + Bitmap big = Bitmap.createScaledBitmap(source, source.getWidth() * 2, source.getHeight() * 2, true); BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inSampleSize = 2; - + ByteArrayOutputStream os = new ByteArrayOutputStream(); - big.compress(CompressFormat.PNG, 100, os); - + big.compress(CompressFormat.PNG, 100, os); + byte[] array = os.toByteArray(); return BitmapFactory.decodeByteArray(array, 0, array.length, opts); } return null; - } - - /** - * Returns an SQL String of given sort options of albums query - * @param sortBy Sort field - * @param sortOrder Sort order - * @return SQL "ORDER BY" string - */ - protected static ObjNode sort(ObjNode params, int sortBy, String sortOrder) { - - - - final String order = sortOrder.equals(SortType.ORDER_DESC) ? "descending" : "ascending"; - final String sortby; - switch (sortBy) { - default: - case SortType.ALBUM: - sortby = "label"; - break; - case SortType.ARTIST: - sortby = "artist"; - break; - case SortType.TRACK: - sortby = "track"; - break; - case SortType.TITLE: - sortby = "sorttitle"; - break; - case SortType.YEAR: - sortby = "year"; - break; - case SortType.RATING: - sortby = "rating"; - break; - case SortType.DATE_ADDED: - sortby = "dateadded"; - break; - } - - params.p(PARAM_SORT, obj().p("ignorearticle", true).p("method", sortby).p("order", order)); - return params; - } - - public final static ObjNode obj() { - return new ObjNode(FACTORY); } public static class ObjNode extends ObjectNode { public ObjNode(JsonNodeFactory nc) { super(nc); } + public ObjNode p(String fieldName, Object object) { super.put(fieldName, (JsonNode) object); return this; } + public ObjNode p(String fieldName, String v) { super.put(fieldName, v); return this; } + public ObjNode p(String fieldName, int v) { super.put(fieldName, v); return this; } + public ObjNode p(String fieldName, boolean v) { super.put(fieldName, v); return this; } - }; - - public final static ArrayNode arr() { - return MAPPER.createArrayNode(); - } - - public final static String getString(JsonNode obj, String key) { - - if(obj.get(key) == null) - return ""; - else if(obj.get(key).isArray()){ - String retval = ""; - for (Iterator i = obj.get(key).getElements(); i.hasNext();) { - retval += i.next().getTextValue(); - if(i.hasNext()) - retval += ", "; - } - return retval; - } - else - return getString(obj, key, ""); - } - public final static String getString(JsonNode obj, String key, String ifNullResult) { - return obj.get(key) == null ? ifNullResult : obj.get(key).getTextValue(); - } - - public final static int getInt(JsonNode obj, String key) { - return obj.get(key) == null ? -1 : obj.get(key).getIntValue(); - } - - public final static double getDouble(JsonNode obj, String key) { - - if(obj.get(key) == null) - return -1; - - DecimalFormat twoDForm = new DecimalFormat("#.0"); - - double val = -1; - try{ - val = Double.valueOf(twoDForm.format(obj.get(key).getDoubleValue()).replace(',', '.')); - } - catch(NumberFormatException e){ - val = -1; - } - - return val; } } diff --git a/src/org/xbmc/jsonrpc/client/ControlClient.java b/app/src/main/java/org/xbmc/jsonrpc/client/ControlClient.java similarity index 70% rename from src/org/xbmc/jsonrpc/client/ControlClient.java rename to app/src/main/java/org/xbmc/jsonrpc/client/ControlClient.java index 68cf3f98..a1416f0d 100644 --- a/src/org/xbmc/jsonrpc/client/ControlClient.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/ControlClient.java @@ -22,6 +22,7 @@ package org.xbmc.jsonrpc.client; import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.data.IControlClient; import org.xbmc.api.info.PlayStatus; @@ -34,197 +35,236 @@ * XBMC. These are essentially play controls, navigation controls other actions * the user may wants to execute. It equally reads the information instead of * setting it. - * + * * @author Team XBMC */ public class ControlClient extends Client implements IControlClient { /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public ControlClient(Connection connection) { super(connection); } - + + public static int parseTime(JsonNode node) { + + int time = 0; + time += node.get("hours").getIntValue() * 3600; + time += node.get("minutes").getIntValue() * 60; + time += node.get("seconds").getIntValue(); + + return time; + + } + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - - + /** * Adds a file or folder (fileOrFolder is either a file or a folder) to the current playlist. - * @param manager Manager reference + * + * @param manager Manager reference * @param fileOrFolder * @return true on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, String fileOrFolder, int playlistId) { - + String type = "file"; - if(fileOrFolder.endsWith("/") || fileOrFolder.endsWith("\\")) + if (fileOrFolder.endsWith("/") || fileOrFolder.endsWith("\\")) type = "directory"; - - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", playlistId).p("item", obj().p(type, fileOrFolder))).equals("OK"); + + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", playlistId).p("item", + obj().p(type, fileOrFolder))).equals("OK"); } - - public boolean play(INotifiableManager manager, int playlistId){ - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", playlistId))).equals("OK"); + + public boolean play(INotifiableManager manager, int playlistId) { + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", playlistId))) + .equals("OK"); } + /** * Starts playing the media file filename . - * @param manager Manager reference + * + * @param manager Manager reference * @param filename File to play * @return true on success, false otherwise. */ public boolean playFile(INotifiableManager manager, String filename, int playlistId) { - - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("file", filename)).p("options", obj().p("resume", true))).equals("OK"); -} - + + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("file", filename)).p("options", + obj().p("resume", true))).equals("OK"); + } + /** * Starts playing/showing the next media/image in the current playlist or, - * if currently showing a slideshow, the slideshow playlist. + * if currently showing a slideshow, the slideshow playlist. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean playNext(INotifiableManager manager) { - return mConnection.getString(manager, "Player.GoNext", obj().p("playlistid", getPlaylistId(manager))).equals("OK"); + return mConnection.getString(manager, "Player.GoNext", obj().p("playlistid", getPlaylistId(manager))).equals + ("OK"); } /** * Starts playing/showing the previous media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean playPrevious(INotifiableManager manager) { - return mConnection.getString(manager, "Player.GoPrevious", obj().p("playlistid", getPlaylistId(manager))).equals("OK"); + return mConnection.getString(manager, "Player.GoPrevious", obj().p("playlistid", getPlaylistId(manager))) + .equals("OK"); } - + /** - * Pauses the currently playing media. + * Pauses the currently playing media. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean pause(INotifiableManager manager) { mConnection.getInt(manager, "Player.PlayPause", obj().p("playerid", getActivePlayerId(manager)), "speed"); return true; - + } - + /** - * Stops the currently playing media. + * Stops the currently playing media. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean stop(INotifiableManager manager) { - return mConnection.getString(manager, "Player.Stop", obj().p("playerid", getActivePlayerId(manager))).equals("OK"); + return mConnection.getString(manager, "Player.Stop", obj().p("playerid", getActivePlayerId(manager))).equals + ("OK"); } - + /** * Start playing the media file at the given URL + * * @param manager Manager reference - * @param url An URL pointing to a supported media file + * @param url An URL pointing to a supported media file * @return true on success, false otherwise. */ public boolean playUrl(INotifiableManager manager, String url) { return playFile(manager, url, 1); } - + /** * Show the picture file filename . - * @param manager Manager reference + * + * @param manager Manager reference * @param filename File to show * @return true on success, false otherwise. */ public boolean showPicture(INotifiableManager manager, String filename) { return playNext(manager); - + } - + /** * Send the string text via keys on the virtual keyboard. + * * @param manager Manager reference - * @param text The text string to send. + * @param text The text string to send. * @return true on success, false otherwise. */ public boolean sendText(INotifiableManager manager, String text) { - + boolean done = false; - if(text.endsWith("\n")){ - text = text.substring(0, text.length()-1); + if (text.endsWith("\n")) { + text = text.substring(0, text.length() - 1); done = true; } return mConnection.getString(manager, "Input.SendText", obj().p("text", text).p("done", done)).equals("OK"); } - + /** * Sets the volume as a percentage of the maximum possible. + * * @param manager Manager reference - * @param volume New volume (0-100) + * @param volume New volume (0-100) * @return true on success, false otherwise. */ public boolean setVolume(INotifiableManager manager, int volume) { return mConnection.getString(manager, "Application.SetVolume", obj().p("volume", volume)).equals("OK"); } - + /** * Seeks to a position. If type is *
      - *
    • absolute - Sets the playing position of the currently - * playing media as a percentage of the media�s length.
    • - *
    • relative - Adds/Subtracts the current percentage on to - * the current position in the song
    • - *
    - * - * @param manager Manager reference + *
  • absolute - Sets the playing position of the currently + * playing media as a percentage of the media�s length.
  • + *
  • relative - Adds/Subtracts the current percentage on to + * the current position in the song
  • + * + * + * @param manager Manager reference * @param type Seek type, relative or absolute * @param progress Progress * @return true on success, false otherwise. */ public boolean seek(INotifiableManager manager, SeekType type, int progress) { if (type.compareTo(SeekType.absolute) == 0) - return mConnection.getJson(manager, "Player.Seek", obj().p("playerid", getActivePlayerId(manager)).p("value", progress)).get("percentage")!=null; + return mConnection.getJson(manager, "Player.Seek", obj().p("playerid", + getActivePlayerId(manager)).p("value", progress)).get("percentage") != null; else return false;//mConnection.getBoolean(manager, "SeekPercentageRelative", String.valueOf(progress)); } - + /** * Toggles the sound on/off. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean mute(INotifiableManager manager) { return mConnection.getString(manager, "Application.SetMute", obj().p("volume", 1)).equals("OK"); } - - + /** * Retrieves the current playing position of the currently playing media as - * a percentage of the media's length. + * a percentage of the media's length. + * * @param manager Manager reference * @return Percentage (0-100) */ public int getPercentage(INotifiableManager manager) { - return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p(PARAM_PROPERTIES, arr().add("percentage")), "percentage"); + ArrayNode arr = arr(); + arr.add("percentage"); + return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p + (PARAM_PROPERTIES, arr), "percentage"); } - + /** - * Retrieves the current volume setting as a percentage of the maximum + * Retrieves the current volume setting as a percentage of the maximum * possible value. + * * @param manager Manager reference * @return Volume (0-100) */ public int getVolume(INotifiableManager manager) { - return mConnection.getInt(manager, "Application.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p(PARAM_PROPERTIES, arr().add("volume")), "volume"); + ArrayNode arr = arr(); + arr.add("volume"); + return mConnection.getInt(manager, "Application.GetProperties", obj().p("playerid", getActivePlayerId(manager) + ).p(PARAM_PROPERTIES, arr), "volume"); } - + /** * Navigates... UP! + * * @param manager Manager reference * @return true on success, false otherwise. */ @@ -234,61 +274,66 @@ public boolean navUp(INotifiableManager manager) { /** * Navigates... DOWN! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navDown(INotifiableManager manager) { return mConnection.getString(manager, "Input.Down", null).equals("OK"); } - + /** * Navigates... LEFT! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navLeft(INotifiableManager manager) { return mConnection.getString(manager, "Input.Left", null).equals("OK"); } - + /** * Navigates... RIGHT! + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navRight(INotifiableManager manager) { return mConnection.getString(manager, "Input.Right", null).equals("OK"); } - + /** * Selects current item. + * * @param manager Manager reference * @return true on success, false otherwise. */ public boolean navSelect(INotifiableManager manager) { return mConnection.getString(manager, "Input.Select", null).equals("OK"); } - + /** - * Takes either "video" or "music" as a parameter to begin updating the - * corresponding database. - * + * Takes either "video" or "music" as a parameter to begin updating the + * corresponding database. + *

    * TODO For "video" you can additionally specify a specific path to be scanned. - * - * @param manager Manager reference + * + * @param manager Manager reference * @param mediaType Either video or music. * @return True on success, false otherwise. */ public boolean updateLibrary(INotifiableManager manager, String mediaType) { - if(mediaType == "video") + if (mediaType == "video") return mConnection.getString(manager, "VideoLibrary.Scan", null).equals("OK"); - else if(mediaType == "music") + else if (mediaType == "music") return mConnection.getString(manager, "AudioLibrary.Scan", null).equals("OK"); else return false; } - + /** - * Broadcast a message. Used to test broadcasting feature. + * Broadcast a message. Used to test broadcasting feature. + * * @param manager Manager reference * @param message * @return True on success, false otherwise. @@ -297,14 +342,15 @@ public boolean broadcast(INotifiableManager manager, String message) { //TODO return false;//mConnection.getBoolean(manager, "Broadcast", message); } - + /** * Returns the current broadcast port number, or 0 if deactivated. + * * @param manager Manager reference * @return Current broadcast port number. */ public int getBroadcast(INotifiableManager manager) { - + //TODO /*final String ret[] = mConnection.getString(manager, "GetBroadcast").split(";"); try { @@ -315,18 +361,18 @@ public int getBroadcast(INotifiableManager manager) { }*/ return 0; } - + /** * Sets the brodcast level and port. Level currently only takes three values: - *

      - *
    • 0 - No broadcasts
    • - *
    • 1 - Media playback and startup & shutdown events - *
    • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. - *
    - * - * @param manager Manager reference - * @param port Broadcast port - * @param level Broadcast level + *
      + *
    • 0 - No broadcasts
    • + *
    • 1 - Media playback and startup & shutdown events + *
    • 2 - "OnAction" events (e.g. buttons) as well as level 1 events. + *
    + * + * @param manager Manager reference + * @param port Broadcast port + * @param level Broadcast level * @return True on success, false otherwise. */ public boolean setBroadcast(INotifiableManager manager, int port, int level) { @@ -336,149 +382,215 @@ public boolean setBroadcast(INotifiableManager manager, int port, int level) { /** * Returns current play state + * * @param manager Manager reference * @return */ public int getPlayState(INotifiableManager manager) { - return mConnection.getInt(manager, "Application.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p(PARAM_PROPERTIES, arr().add("speed")), "speed"); + ArrayNode arr = arr(); + arr.add("speed"); + return mConnection.getInt(manager, "Application.GetProperties", obj().p("playerid", getActivePlayerId(manager) + ).p(PARAM_PROPERTIES, arr), "speed"); } - + /** * Returns the current playlist identifier + * * @param manager Manager reference */ public int getPlaylistId(INotifiableManager manager) { - return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p(PARAM_PROPERTIES, arr().add("playlistid")), "playlistid"); + ArrayNode arr = arr(); + arr.add("playlistid"); + return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getActivePlayerId(manager)).p + (PARAM_PROPERTIES, arr), "playlistid"); } - + /** * Sets the current playlist identifier + * * @param manager Manager reference - * @param id Playlist identifier + * @param id Playlist identifier * @return True on success, false otherwise. */ public boolean setPlaylistId(INotifiableManager manager, int id) { return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", id))).equals("OK"); } - + /** * Sets the current playlist position - * @param manager Manager reference0 + * + * @param manager Manager reference0 * @param position New playlist position * @return True on success, false otherwise. */ public boolean setPlaylistPos(INotifiableManager manager, int playlistId, int position) { int playerid = getActivePlayerId(manager); int currentplaylistid = getPlaylistId(manager); - - - if(playerid == -1 || currentplaylistid != playlistId) - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", playlistId).p("position", position))).equals("OK"); + + + if (playerid == -1 || currentplaylistid != playlistId) + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + playlistId).p("position", position))).equals("OK"); else - return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", getActivePlayerId(manager)).p("position", position)).equals("OK"); + return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", + getActivePlayerId(manager)).p("position", position)).equals("OK"); } - + /** * Clears a playlist. - * @param manager Manager reference - * @param int Playlist to clear (0 = music, 1 = video) + * + * @param manager Manager reference + * @param playlistId Playlist to clear (0 = music, 1 = video) * @return True on success, false otherwise. */ public boolean clearPlaylist(INotifiableManager manager, int playlistId) { return mConnection.getString(manager, "Playlist.Clear", obj().p("playlistid", playlistId)).equals("OK"); } - + + /** + * Sets the correct response format to default values + * @param manager Manager reference + * @return True on success, false otherwise. + */ + /** * Sets current playlist - * @param manager Manager reference + * + * @param manager Manager reference * @param playlistId Playlist ID ("0" = music, "1" = video) * @return True on success, false otherwise. */ public boolean setCurrentPlaylist(INotifiableManager manager, int playlistId) { - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", playlistId))).equals("OK"); + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + playlistId))).equals("OK"); } - - /** - * Sets the correct response format to default values - * @param manager Manager reference - * @return True on success, false otherwise. - */ - + /** * Sets the gui setting of XBMC to value - * @param manager + * + * @param manager * @param setting see {@link org.xbmc.api.info.GuiSettings} for the available settings - * @param value the value to set - * @return {@code true} if the value was set successfully + * @param value the value to set + * @return {@code true} if the value was set successfully */ public boolean setGuiSetting(INotifiableManager manager, final int setting, final String value) { - return false;//mConnection.getBoolean(manager, "SetGUISetting", GuiSettings.getType(setting) + ";" + GuiSettings.getName(setting) + ";" + value); + return false;//mConnection.getBoolean(manager, "SetGUISetting", GuiSettings.getType(setting) + ";" + + // GuiSettings.getName(setting) + ";" + value); } - + /** * Returns state and type of the media currently playing. + * * @return */ public ICurrentlyPlaying getCurrentlyPlaying(INotifiableManager manager) { - + final IControlClient.ICurrentlyPlaying nothingPlaying = new IControlClient.ICurrentlyPlaying() { private static final long serialVersionUID = -1554068775915058884L; - public boolean isPlaying() { return false; } - public int getMediaType() { return 0; } - public int getPlaylistPosition() { return -1; } - public String getTitle() { return ""; } - public int getTime() { return 0; } - public int getPlayStatus() { return PlayStatus.STOPPED; } - public float getPercentage() { return 0; } - public String getFilename() { return ""; } - public int getDuration() { return 0; } - public String getArtist() { return ""; } - public String getAlbum() { return ""; } - public int getHeight() { return 0; } - public int getWidth() { return 0; } + + public boolean isPlaying() { + return false; + } + + public int getMediaType() { + return 0; + } + + public int getPlaylistPosition() { + return -1; + } + + public String getTitle() { + return ""; + } + + public int getTime() { + return 0; + } + + public int getPlayStatus() { + return PlayStatus.STOPPED; + } + + public float getPercentage() { + return 0; + } + + public String getFilename() { + return ""; + } + + public int getDuration() { + return 0; + } + + public String getArtist() { + return ""; + } + + public String getAlbum() { + return ""; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } }; final JsonNode active = mConnection.getJson(manager, "Player.GetActivePlayers", null); - if(active.size() == 0) + if (active.size() == 0) return nothingPlaying; - + int playerid = getActivePlayerId(manager); - - final JsonNode player_details = mConnection.getJson(manager, "Player.GetProperties", obj().p("playerid", playerid).p(PARAM_PROPERTIES, arr().add("percentage").add("position").add("speed").add("time").add("totaltime").add("type"))); - - if(player_details != null){ - - final JsonNode file_details = mConnection.getJson(manager, "Player.GetItem", obj().p("playerid", playerid).p(PARAM_PROPERTIES, arr().add("artist").add("album").add("duration").add("episode").add("genre").add("file").add("season").add("showtitle").add("tagline").add("title"))).get("item"); - - if(file_details.get("Filename") != null && file_details.get("Filename").getTextValue().contains("Nothing Playing")) { + + ArrayNode arr = arr(); + arr.add("percentage"); + arr.add("position"); + arr.add("speed"); + arr.add("time"); + arr.add("totaltime"); + arr.add("type"); + final JsonNode player_details = mConnection.getJson(manager, "Player.GetProperties", obj().p("playerid", + playerid).p(PARAM_PROPERTIES, arr)); + + if (player_details != null) { + + ArrayNode arr1 = arr(); + arr1.add("artist"); + arr1.add("album"); + arr1.add("duration"); + arr1.add("episode"); + arr1.add("genre"); + arr1.add("file"); + arr1.add("season"); + arr1.add("showtitle"); + arr1.add("tagline"); + arr1.add("title"); + final JsonNode file_details = mConnection.getJson(manager, "Player.GetItem", obj().p("playerid", + playerid).p(PARAM_PROPERTIES, arr1)).get("item"); + + if (file_details.get("Filename") != null && file_details.get("Filename").getTextValue().contains + ("Nothing" + + " " + + "Playing")) { return nothingPlaying; } - - - if(getString(file_details, "type").equals("episode")){ - return TvShowClient.getCurrentlyPlaying(player_details, file_details); - } - else if(getString(player_details, "type").equals("video")){ - return VideoClient.getCurrentlyPlaying(player_details, file_details); + + + if (getString(file_details, "type").equals("episode")) { + return TvShowClient.getCurrentlyPlaying(player_details, file_details); + } else if (getString(player_details, "type").equals("video")) { + return VideoClient.getCurrentlyPlaying(player_details, file_details); } - if(getString(player_details, "type").equals("audio")){ + if (getString(player_details, "type").equals("audio")) { return MusicClient.getCurrentlyPlaying(player_details, file_details); - } - else + } else return nothingPlaying; - } - else + } else return nothingPlaying; } - - public static int parseTime(JsonNode node) { - - int time=0; - time += node.get("hours").getIntValue() * 3600; - time += node.get("minutes").getIntValue() * 60; - time += node.get("seconds").getIntValue(); - - return time; - - } } diff --git a/src/org/xbmc/jsonrpc/client/InfoClient.java b/app/src/main/java/org/xbmc/jsonrpc/client/InfoClient.java similarity index 72% rename from src/org/xbmc/jsonrpc/client/InfoClient.java rename to app/src/main/java/org/xbmc/jsonrpc/client/InfoClient.java index bbcb0557..53a8c319 100644 --- a/src/org/xbmc/jsonrpc/client/InfoClient.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/InfoClient.java @@ -1,11 +1,7 @@ package org.xbmc.jsonrpc.client; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Iterator; - import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.data.IInfoClient; import org.xbmc.api.object.FileLocation; @@ -15,17 +11,23 @@ import org.xbmc.api.type.SortType; import org.xbmc.jsonrpc.Connection; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Iterator; + /** * The InfoClient basically takes care of everything else not covered by the * other clients (music, video and control). That means its tasks are bound to - * system related stuff like directory listing and so on. - * + * system related stuff like directory listing and so on. + * * @author Team XBMC */ public class InfoClient extends Client implements IInfoClient { - + /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public InfoClient(Connection connection) { @@ -34,147 +36,171 @@ public InfoClient(Connection connection) { /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - + /** * Returns the contents of a directory - * @param path Path to the directory - * @param mask Mask to filter - * @param offset Offset (0 for none) - * @param limit Limit (0 for none) + * + * @param path Path to the directory + * @param mask Mask to filter + * @param offset Offset (0 for none) + * @param limit Limit (0 for none) * @return */ - public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, int offset, int limit, final int mMediaType) { + public ArrayList getDirectory(INotifiableManager manager, String path, DirectoryMask mask, + int offset, int limit, final int mMediaType) { final ArrayList dirs = new ArrayList(); - final JsonNode jsonDirs = mConnection.getJson(manager, "Files.GetDirectory", sort(obj().p("media", "files").p("directory", path), SortType.ALBUM, "descending"), "files"); - for (Iterator i = jsonDirs.getElements(); i.hasNext();) { - JsonNode jsonDir = (JsonNode)i.next(); + final JsonNode jsonDirs = mConnection.getJson(manager, "Files.GetDirectory", sort(obj().p("media", + "files").p("directory", path), SortType.ALBUM, "descending"), "files"); + for (Iterator i = jsonDirs.getElements(); i.hasNext(); ) { + JsonNode jsonDir = (JsonNode) i.next(); dirs.add(new FileLocation(getString(jsonDir, "label"), getString(jsonDir, "file"))); } return dirs; } - + /** * Returns all the contents of a directory - * @param path Path to the directory + * + * @param path Path to the directory * @return */ public ArrayList getDirectory(INotifiableManager manager, String path, int mMediaType) { return getDirectory(manager, path, null, 0, 0, mMediaType); } - + /** * Returns all defined shares of a media type + * * @param mediaType Media type * @return */ public ArrayList getShares(INotifiableManager manager, int mediaType) { - + final ArrayList shares = new ArrayList(); - final JsonNode jsonShares = mConnection.getJson(manager, "Files.GetSources", obj().p("media", MediaType.getName(mediaType))); - if(jsonShares != null){ - for (Iterator i = jsonShares.get("sources").getElements(); i.hasNext();) { - JsonNode jsonShare = (JsonNode)i.next(); + final JsonNode jsonShares = mConnection.getJson(manager, "Files.GetSources", obj().p("media", + MediaType.getName(mediaType))); + if (jsonShares != null) { + for (Iterator i = jsonShares.get("sources").getElements(); i.hasNext(); ) { + JsonNode jsonShare = (JsonNode) i.next(); shares.add(new FileLocation(getString(jsonShare, "label"), getString(jsonShare, "file"))); } } return shares; } - + /** * @TODO Implement for JSON-RPC */ - public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, URISyntaxException { + public String getCurrentlyPlayingThumbURI(INotifiableManager manager) throws MalformedURLException, + URISyntaxException { int playerid = getActivePlayerId(manager); - if(playerid == -1) + if (playerid == -1) return null; - - final JsonNode item = mConnection.getJson(manager, "Player.GetItem", obj().p("playerid", playerid).p(PARAM_PROPERTIES, arr().add("thumbnail"))).get("item"); + + ArrayNode arr = arr(); + arr.add("thumbnail"); + final JsonNode item = mConnection.getJson(manager, "Player.GetItem", obj().p("playerid", + playerid).p(PARAM_PROPERTIES, arr)).get("item"); JsonNode dl = null; - if(getString(item, "thumbnail") != null && !getString(item, "thumbnail").equals("")) + if (getString(item, "thumbnail") != null && !getString(item, "thumbnail").equals("")) dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", getString(item, "thumbnail"))); - if(dl != null){ + if (dl != null) { JsonNode details = dl.get("details"); - if(details != null) + if (details != null) return mConnection.getUrl(getString(details, "path")); else return null; - } - else - return null; + } else + return null; } - + /** * Returns any system info variable, see {@link org.xbmc.api.info.SystemInfo} - * @TODO Wait for JSON-RPC implementation + * * @param field Field to return * @return + * @TODO Wait for JSON-RPC implementation */ public String getSystemInfo(INotifiableManager manager, int field) { - JsonNode version = mConnection.getJson(manager, "Application.GetProperties", obj().p(PARAM_PROPERTIES, arr().add("version"))).get("version"); - return getInt(version, "major") + "." + getInt(version, "minor") + " " + getString(version, "tag") + "\nGit: " + getString(version, "revision"); + ArrayNode arr = arr(); + arr.add("version"); + JsonNode version = mConnection.getJson(manager, "Application.GetProperties", obj().p(PARAM_PROPERTIES, + arr)).get("version"); + return getInt(version, "major") + "." + getInt(version, "minor") + " " + getString(version, + "tag") + "\nGit: " + getString(version, "revision"); } - + /** * Returns a boolean GUI setting - * @TODO Wait for JSON-RPC implementation + * * @param field * @return + * @TODO Wait for JSON-RPC implementation */ public boolean getGuiSettingBool(INotifiableManager manager, int field) { //TODO - //return mConnection.getBoolean(manager, "GetGuiSetting", GuiSettings.MusicLibrary.getType(field) + ";" + GuiSettings.MusicLibrary.getName(field)); + //return mConnection.getBoolean(manager, "GetGuiSetting", GuiSettings.MusicLibrary.getType(field) + ";" + + // GuiSettings.MusicLibrary.getName(field)); return false; } /** * Returns an integer GUI setting - * @TODO Wait for JSON-RPC implementation + * * @param field * @return + * @TODO Wait for JSON-RPC implementation */ public int getGuiSettingInt(INotifiableManager manager, int field) { //TODO - //return mConnection.getInt(manager, "GetGuiSetting", GuiSettings.MusicLibrary.getType(field) + ";" + GuiSettings.MusicLibrary.getName(field)); + //return mConnection.getInt(manager, "GetGuiSetting", GuiSettings.MusicLibrary.getType(field) + ";" + + // GuiSettings.MusicLibrary.getName(field)); return 0; } - + /** * Returns a boolean GUI setting + * * @param field * @param value Value * @return */ public boolean setGuiSettingBool(INotifiableManager manager, int field, boolean value) { //TODO - // return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field) + ";" + value); + // return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings + // .getName(field) + ";" + value); return false; } - + /** * Returns an integer GUI setting + * * @param field * @param value Value * @return */ public boolean setGuiSettingInt(INotifiableManager manager, int field, int value) { //TODO - //return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings.getName(field) + ";" + value); + //return mConnection.getBoolean(manager, "SetGuiSetting", GuiSettings.getType(field) + ";" + GuiSettings + // .getName(field) + ";" + value); return false; } - + /** - * Returns any music info variable see {@link org.xbmc.http.info.MusicInfo} - * @TODO Wait for JSON-RPC implementation + * Returns any music info variable see {@link org.xbmc.api.info.MusicInfo} + * * @param field Field to return * @return + * @TODO Wait for JSON-RPC implementation */ public String getMusicInfo(INotifiableManager manager, int field) { //TODO @@ -183,10 +209,11 @@ public String getMusicInfo(INotifiableManager manager, int field) { } /** - * Returns any video info variable see {@link org.xbmc.http.info.VideoInfo} - * @TODO Wait for JSON-RPC implementation + * Returns any video info variable see {@link org.xbmc.api.info.VideoInfo} + * * @param field Field to return * @return + * @TODO Wait for JSON-RPC implementation */ public String getVideoInfo(INotifiableManager manager, int field) { //TODO diff --git a/src/org/xbmc/jsonrpc/client/MusicClient.java b/app/src/main/java/org/xbmc/jsonrpc/client/MusicClient.java similarity index 73% rename from src/org/xbmc/jsonrpc/client/MusicClient.java rename to app/src/main/java/org/xbmc/jsonrpc/client/MusicClient.java index d500bcba..d724686b 100644 --- a/src/org/xbmc/jsonrpc/client/MusicClient.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/MusicClient.java @@ -21,14 +21,14 @@ package org.xbmc.jsonrpc.client; -import java.util.ArrayList; -import java.util.Iterator; +import android.graphics.Bitmap; import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; import org.xbmc.api.business.INotifiableManager; import org.xbmc.api.data.IControlClient; -import org.xbmc.api.data.IMusicClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.IMusicClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Album; import org.xbmc.api.object.Artist; @@ -40,344 +40,463 @@ import org.xbmc.api.type.SortType; import org.xbmc.jsonrpc.Connection; -import android.graphics.Bitmap; +import java.util.ArrayList; +import java.util.Iterator; /** * Takes care of every music related stuff, notably the music database. - * + * * @author Team XBMC */ public class MusicClient extends Client implements IMusicClient { - + public static final String TAG = "MusicClient"; - + public static final int VIEW_ALBUMS = 1; public static final int VIEW_SONGS = 2; - + public static final int PLAYLIST_ID = 0; public static final String LIBRARY_TYPE = "songs"; - + public static final int PLAYLIST_LIMIT = 100; - + /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public MusicClient(Connection connection) { super(connection); } - + + static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { + return new IControlClient.ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + return getString(item, "title"); + } + + public int getTime() { + return ControlClient.parseTime(player.get("time")); + } + + public int getPlayStatus() { + return getInt(player, "speed"); + } + + public int getPlaylistPosition() { + return getInt(player, "position"); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return getInt(player, "percentage"); + } catch (NumberFormatException e) { + } + return (float) getDouble(player, "percentage"); + } + + public String getFilename() { + return getString(item, "file"); + } + + public int getDuration() { + return getInt(item, "duration"); + } + + public String getArtist() { + return getString(item, "artist"); + } + + public String getAlbum() { + return getString(item, "album"); + } + + public int getMediaType() { + return MediaType.MUSIC; + } + + public boolean isPlaying() { + return getInt(player, "speed") == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + }; + } + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - /** * Adds an album to the current playlist. + * * @param album Album * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Album album, int sortBy, String sortOrder) { - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p("albumid", album.id))).equals("OK"); + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", + obj().p("albumid", album.id))).equals("OK"); } /** * Adds all songs from an artist to the current playlist. + * * @param artist Artist * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p("artist", artist.id))).equals("OK"); + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", + obj().p("artist", artist.id))).equals("OK"); } /** * Adds all songs from a genre to the current playlist. + * * @param genre Genre * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p("genreid", genre.id))).equals("OK"); + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", + obj().p("genreid", genre.id))).equals("OK"); } /** * Adds songs of a genre from an artist to the current playlist. + * * @param artist Artist - * @param genre Genre + * @param genre Genre * @return True on success, false otherwise. */ - public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder) { - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p("genreid", genre.id).p("artistid", artist.id))).equals("OK"); + public boolean addToPlaylist(INotifiableManager manager, Artist artist, Genre genre, int sortBy, + String sortOrder) { + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", + obj().p("genreid", genre.id).p("artistid", artist.id))).equals("OK"); } - + /** * Adds a song to the current playlist. + * * @param song Song to add * @return True on success, false otherwise. */ public boolean addToPlaylist(INotifiableManager manager, Song song) { - return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p("songid", song.id))).equals("OK"); + return mConnection.getString(manager, "Playlist.Add", obj().p("playlistid", PLAYLIST_ID).p("item", obj().p + ("songid", song.id))).equals("OK"); } - + /** * Returns how many items are in the playlist. + * * @return Number of items in the playlist */ public int getPlaylistSize(INotifiableManager manager) { - return mConnection.getInt(manager, "Playlist.GetProperties", obj().p("playlistid", PLAYLIST_ID).p(PARAM_PROPERTIES, arr().add("size")), "size"); + ArrayNode arr = arr(); + arr.add("size"); + return mConnection.getInt(manager, "Playlist.GetProperties", obj().p("playlistid", PLAYLIST_ID).p + (PARAM_PROPERTIES, arr), "size"); } - + /** * Retrieves the currently playing song number in the playlist. + * * @return Number of items in the playlist */ - public int getPlaylistPosition(INotifiableManager manager) { - return mConnection.getInt(manager, "Player.GetItem", obj().p("playerid", getActivePlayerId(manager)).p(PARAM_PROPERTIES, arr().add("position")), "position"); + public int getPlaylistPosition(INotifiableManager manager) { + ArrayNode arr = arr(); + arr.add("position"); + return mConnection.getInt(manager, "Player.GetItem", obj().p("playerid", getActivePlayerId(manager)).p + (PARAM_PROPERTIES, arr), "position"); } - + /** * Sets the media at playlist position position to be the next item to be played. + * * @param position New position, starting with 0. * @return True on success, false otherwise. */ public boolean setPlaylistPosition(INotifiableManager manager, int position) { int playerid = getActivePlayerId(manager); - if(playerid == -1) - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", PLAYLIST_ID).p("position", position))).equals("OK"); + if (playerid == -1) + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + PLAYLIST_ID).p("position", position))).equals("OK"); else - return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", getActivePlayerId(manager)).p("position", position)).equals("OK"); + return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", + getActivePlayerId(manager)).p("position", position)).equals("OK"); } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. + * * @param position Position to remove, starting with 0. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, int position) { - return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", position)).equals("OK"); + return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", + position)).equals("OK"); } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. + * + * @param path Complete path (including filename) of the media to be removed. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, String path) { - - JsonNode playlistitems = mConnection.getJson(manager, "Playlist.GetItems", obj().p("playlistid", PLAYLIST_ID).p(PARAM_PROPERTIES, arr().add("position").add("file"))); - for (Iterator i = playlistitems.getElements(); i.hasNext();) { - JsonNode jsonItem = (JsonNode)i.next(); - if(getString(jsonItem,"file").toLowerCase().equals(path.toLowerCase())) - return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", getInt(jsonItem,"position"))).equals("OK"); + + ArrayNode arr = arr(); + arr.add("position"); + arr.add("file"); + JsonNode playlistitems = mConnection.getJson(manager, "Playlist.GetItems", obj().p("playlistid", + PLAYLIST_ID).p(PARAM_PROPERTIES, arr)); + for (Iterator i = playlistitems.getElements(); i.hasNext(); ) { + JsonNode jsonItem = (JsonNode) i.next(); + if (getString(jsonItem, "file").toLowerCase().equals(path.toLowerCase())) + return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", + PLAYLIST_ID).p("position", getInt(jsonItem, "position"))).equals("OK"); } - + return false; } - + /** - * Returns the first {@link PLAYLIST_LIMIT} songs of the playlist. + * Returns the first songs of the playlist. + * * @return Songs in the playlist. */ public ArrayList getPlaylist(INotifiableManager manager) { - JsonNode jsonItems = mConnection.getJson(manager, "PlayList.GetItems", obj().p("playlistid", PLAYLIST_ID).p("limits", obj().p("start", 0).p("end", PLAYLIST_LIMIT)).p("properties", arr().add("file"))); + ArrayNode arr = arr(); + arr.add("file"); + JsonNode jsonItems = mConnection.getJson(manager, "PlayList.GetItems", obj().p("playlistid", + PLAYLIST_ID).p("limits", obj().p("start", 0).p("end", PLAYLIST_LIMIT)).p("properties", arr)); final JsonNode jsonSongs = jsonItems.get("items"); final ArrayList files = new ArrayList(); if (jsonSongs != null) { - for (Iterator i = jsonSongs.getElements(); i.hasNext();) { - JsonNode jsonSong = (JsonNode)i.next(); + for (Iterator i = jsonSongs.getElements(); i.hasNext(); ) { + JsonNode jsonSong = (JsonNode) i.next(); files.add(getString(jsonSong, "file")); } } return files; } - + /** * Clears current playlist + * * @return True on success, false otherwise. */ public boolean clearPlaylist(INotifiableManager manager) { return mConnection.getString(manager, "Playlist.Clear", obj().p("playlistid", PLAYLIST_ID)).equals("OK"); } - + /** * Adds a song to the current playlist and plays it. + * * @param song Song * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Song song) { - + int size = mConnection.getInt(manager, "Playlist.GetProperties", obj().p("playlistid", PLAYLIST_ID), "size"); - - if(addToPlaylist(manager, song)) + + if (addToPlaylist(manager, song)) return setPlaylistPosition(manager, size); else return false; } - - public boolean play(INotifiableManager manager){ - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", PLAYLIST_ID).p("position", 0))).equals("OK"); + + public boolean play(INotifiableManager manager) { + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + PLAYLIST_ID).p("position", 0))).equals("OK"); } - + /** * Plays an album. Playlist is previously cleared. - * @param album Album to play - * @param sortBy Sort field, see SortType.* + * + * @param album Album to play + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Album album, int sortBy, String sortOrder) { - if(clearPlaylist(manager)) - if(addToPlaylist(manager, album, sortBy, sortOrder)) + if (clearPlaylist(manager)) + if (addToPlaylist(manager, album, sortBy, sortOrder)) return play(manager); else return false; else - return false; + return false; } - + /** * Plays all songs of a genre. Playlist is previously cleared. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { - if(clearPlaylist(manager)) - if(addToPlaylist(manager, genre, sortBy, sortOrder)) + if (clearPlaylist(manager)) + if (addToPlaylist(manager, genre, sortBy, sortOrder)) return play(manager); else return false; else - return false; + return false; } - + /** * Plays all songs from an artist. Playlist is previously cleared. - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { - if(clearPlaylist(manager)) - if(addToPlaylist(manager, artist, sortBy, sortOrder)) + if (clearPlaylist(manager)) + if (addToPlaylist(manager, artist, sortBy, sortOrder)) return play(manager); else return false; else - return false; + return false; } - + /** * Plays songs of a genre from an artist. Playlist is previously cleared. + * * @param artist Artist - * @param genre Genre + * @param genre Genre * @return True on success, false otherwise. */ public boolean play(INotifiableManager manager, Artist artist, Genre genre) { - if(clearPlaylist(manager)) - if(addToPlaylist(manager, artist, genre, SortType.TITLE, "descending")) + if (clearPlaylist(manager)) + if (addToPlaylist(manager, artist, genre, SortType.TITLE, "descending")) return play(manager); else return false; else - return false; + return false; } /** * Starts playing/showing the next media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @return True on success, false otherwise. */ public boolean playNext(INotifiableManager manager) { - return mConnection.getString(manager, "Player.GoNext", obj().p("playerid", getActivePlayerId(manager))).equals("OK"); + return mConnection.getString(manager, "Player.GoNext", obj().p("playerid", getActivePlayerId(manager))).equals + ("OK"); } /** * Starts playing/showing the previous media/image in the current playlist * or, if currently showing a slidshow, the slideshow playlist. + * * @return True on success, false otherwise. */ public boolean playPrev(INotifiableManager manager) { - return mConnection.getString(manager, "Player.GoPrevious", obj().p("playerid", getActivePlayerId(manager))).equals("OK"); + return mConnection.getString(manager, "Player.GoPrevious", obj().p("playerid", getActivePlayerId(manager))) + .equals("OK"); } - + /** - * Sets the media at playlist position position to be the next item to be + * Sets the media at playlist position position to be the next item to be * played. Position starts at 0, so SetPlaylistSong(5) sets the position * to the 6th song in the playlist. + * * @param pos Position * @return true on success, false otherwise. */ public boolean playlistSetSong(INotifiableManager manager, int pos) { return setPlaylistPosition(manager, pos); } - + /** * Sets current playlist to "0" + * * @return True on success, false otherwise. */ public boolean setCurrentPlaylist(INotifiableManager manager) { - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", PLAYLIST_ID))).equals("OK"); + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + PLAYLIST_ID))).equals("OK"); } - - + /** * Gets all albums from database - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All albums */ - public ArrayList getAlbums(INotifiableManager manager, int SortBy, String sortOrder){ - return getAlbums(manager, obj(), SortBy, sortOrder); + public ArrayList getAlbums(INotifiableManager manager, int sortBy, String sortOrder) { + return getAlbums(manager, obj(), sortBy, sortOrder); } - + private ArrayList getAlbums(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder) { - - obj = sort(obj.p(PARAM_PROPERTIES, arr().add("artist").add("year").add("thumbnail")), sortBy, sortOrder); - + + ArrayNode arr = arr(); + arr.add("artist"); + arr.add("year"); + arr.add("thumbnail"); + obj = sort(obj.p(PARAM_PROPERTIES, arr), sortBy, sortOrder); + final ArrayList albums = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetAlbums", obj); final JsonNode jsonAlbums = result.get("albums"); - if(jsonAlbums != null){ - for (Iterator i = jsonAlbums.getElements(); i.hasNext();) { - JsonNode jsonAlbum = (JsonNode)i.next(); + if (jsonAlbums != null) { + for (Iterator i = jsonAlbums.getElements(); i.hasNext(); ) { + JsonNode jsonAlbum = (JsonNode) i.next(); albums.add(new Album( - getInt(jsonAlbum, "albumid"), - getString(jsonAlbum, "label"), - getString(jsonAlbum, "artist"), - getInt(jsonAlbum, "year"), - getString(jsonAlbum, "thumbnail", "") + getInt(jsonAlbum, "albumid"), + getString(jsonAlbum, "label"), + getString(jsonAlbum, "artist"), + getInt(jsonAlbum, "year"), + getString(jsonAlbum, "thumbnail", "") )); } } return albums; } - + /** * Gets all albums with given artist IDs + * * @param artistIDs Array of artist IDs * @return All compilation albums */ public ArrayList getAlbums(INotifiableManager manager, ArrayList artistIDs) { - + final ArrayList albums = new ArrayList(); - for(int id : artistIDs){ - albums.addAll(getAlbums(manager, obj().p("filter", obj().p("artistid", id)), SortType.TITLE, "descending")); + for (int id : artistIDs) { + albums.addAll(getAlbums(manager, obj().p("filter", obj().p("artistid", id)), SortType.TITLE, + "descending")); } - + return albums; } - /** * Gets all albums of an artist from database - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Albums with an artist */ @@ -387,143 +506,171 @@ public ArrayList getAlbums(INotifiableManager manager, Artist artist, int /** * Gets all albums of with at least one song in a genre - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Albums of a genre */ public ArrayList getAlbums(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { return getAlbums(manager, obj().p("filter", obj().p("genreid", genre.id)), sortBy, sortOrder); } - + /** * Gets all artists from database + * * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. * @return All albums */ public ArrayList getArtists(INotifiableManager manager, ObjNode obj, boolean albumArtistsOnly) { - - obj.p(PARAM_PROPERTIES, arr().add("thumbnail")).p("albumartistsonly", albumArtistsOnly); + + ArrayNode arr = arr(); + arr.add("thumbnail"); + obj.p(PARAM_PROPERTIES, arr).p("albumartistsonly", albumArtistsOnly); obj = sort(obj, SortType.ARTIST, "descending"); final ArrayList artists = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetArtists", obj); - if(result != null){ + if (result != null) { final JsonNode jsonArtists = result.get("artists"); - for (Iterator i = jsonArtists.getElements(); i.hasNext();) { - JsonNode jsonArtist = (JsonNode)i.next(); + for (Iterator i = jsonArtists.getElements(); i.hasNext(); ) { + JsonNode jsonArtist = (JsonNode) i.next(); artists.add(new Artist( - getInt(jsonArtist, "artistid"), - getString(jsonArtist, "label"), - getString(jsonArtist, "thumbnail", "") + getInt(jsonArtist, "artistid"), + getString(jsonArtist, "label"), + getString(jsonArtist, "thumbnail", "") )); } } return artists; } - + public ArrayList getArtists(INotifiableManager manager, boolean albumArtistsOnly) { return getArtists(manager, obj(), albumArtistsOnly); } /** * Gets all artists with at least one song of a genre. - * @param genre Genre + * + * @param genre Genre * @param albumArtistsOnly If set to true, hide artists who appear only on compilations. * @return Albums with a genre */ public ArrayList getArtists(INotifiableManager manager, Genre genre, boolean albumArtistsOnly) { return getArtists(manager, obj().p("filter", obj().p("genreid", genre.id)), albumArtistsOnly); } - + /** * Gets all genres from database + * * @return All genres */ public ArrayList getGenres(INotifiableManager manager) { - - + + final ArrayList genres = new ArrayList(); - final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetGenres", sort(obj(), SortType.TITLE, "descending")); + final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetGenres", sort(obj(), SortType.TITLE, + "descending")); final JsonNode jsonGenres = result.get("genres"); - for (Iterator i = jsonGenres.getElements(); i.hasNext();) { - JsonNode jsonGenre = (JsonNode)i.next(); + for (Iterator i = jsonGenres.getElements(); i.hasNext(); ) { + JsonNode jsonGenre = (JsonNode) i.next(); genres.add(new Genre( - getInt(jsonGenre, "genreid"), - getString(jsonGenre, "label") + getInt(jsonGenre, "genreid"), + getString(jsonGenre, "label") )); } return genres; } - + /** * Updates the album object with additional data from the albuminfo table + * * @param album * @return Updated album */ public Album updateAlbumInfo(INotifiableManager manager, Album album) { - - final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetAlbumDetails", obj().p("albumid", album.id).p("properties", arr().add("genre").add("albumlabel").add("rating"))); + + ArrayNode arr = arr(); + arr.add("genre"); + arr.add("albumlabel"); + arr.add("rating"); + final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetAlbumDetails", obj().p("albumid", album + .id).p("properties", arr)); final JsonNode jsonAlbum = result.get("albumdetails"); album.genres = getString(jsonAlbum, "genre"); album.label = getString(jsonAlbum, "albumlabel"); album.rating = getInt(jsonAlbum, "rating"); return album; } - + /** * Updates the artist object with additional data from the artistinfo table + * * @param artist * @return Updated artist */ public Artist updateArtistInfo(INotifiableManager manager, Artist artist) { - - final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetArtistDetails", obj().p("artistid", artist.id).p("properties", arr().add("born").add("formed").add("mood").add("style").add("description"))); + + ArrayNode arr = arr(); + arr.add("born"); + arr.add("formed"); + arr.add("mood"); + arr.add("style"); + arr.add("description"); + final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetArtistDetails", obj().p("artistid", + artist.id).p("properties", arr)); final JsonNode jsonArtist = result.get("artistdetails"); artist.born = getString(jsonArtist, "born"); artist.formed = getString(jsonArtist, "formed"); artist.moods = getString(jsonArtist, "mood"); artist.styles = getString(jsonArtist, "style"); artist.biography = getString(jsonArtist, "description"); - + return artist; } - + /** * Returns a list containing tracks of a certain condition. - * @param sqlCondition SQL condition which tracks to return + * * @return Found tracks - **/ + */ private ArrayList getSongs(INotifiableManager manager, ObjNode obj) { final ArrayList songs = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "AudioLibrary.GetSongs", obj); final JsonNode jsonAlbums = result.get("songs"); - for (Iterator i = jsonAlbums.getElements(); i.hasNext();) { - JsonNode jsonSong = (JsonNode)i.next(); + for (Iterator i = jsonAlbums.getElements(); i.hasNext(); ) { + JsonNode jsonSong = (JsonNode) i.next(); songs.add(new Song( - getInt(jsonSong, "songid"), - getString(jsonSong, "label"), - getString(jsonSong, "artist"), - getString(jsonSong, "album"), - getInt(jsonSong, "track"), - getInt(jsonSong, "duration"), - getString(jsonSong, ""), - getString(jsonSong, "file"), - getString(jsonSong, "thumbnail", "") + getInt(jsonSong, "songid"), + getString(jsonSong, "label"), + getString(jsonSong, "artist"), + getString(jsonSong, "album"), + getInt(jsonSong, "track"), + getInt(jsonSong, "duration"), + getString(jsonSong, ""), + getString(jsonSong, "file"), + getString(jsonSong, "thumbnail", "") )); } return songs; } - + private ArrayList getSongs(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder) { - return getSongs(manager, sort(obj.p(PARAM_PROPERTIES, arr().add("artist").add("album").add("track").add("duration").add("file").add("thumbnail")), sortBy, sortOrder)); + ArrayNode arr = arr(); + arr.add("artist"); + arr.add("album"); + arr.add("track"); + arr.add("duration"); + arr.add("file"); + arr.add("thumbnail"); + return getSongs(manager, sort(obj.p(PARAM_PROPERTIES, arr), sortBy, sortOrder)); } - /** * Returns a list containing all tracks of an album. The list is sorted by filename. - * @param album Album - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * + * @param album Album + * @param sortBy Sort field, see SortType.* + * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of an album */ public ArrayList getSongs(INotifiableManager manager, Album album, int sortBy, String sortOrder) { @@ -532,126 +679,85 @@ public ArrayList getSongs(INotifiableManager manager, Album album, int sor /** * Returns a list containing all tracks of an artist. The list is sorted by album name, filename. - * @param artist Artist - * @param sortBy Sort field, see SortType.* + * + * @param artist Artist + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the artist */ public ArrayList getSongs(INotifiableManager manager, Artist artist, int sortBy, String sortOrder) { return getSongs(manager, obj().p("filter", obj().p("artistid", artist.id)), sortBy, sortOrder); } - + /** * Returns a list containing all tracks of a genre. The list is sorted by artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the genre */ public ArrayList getSongs(INotifiableManager manager, Genre genre, int sortBy, String sortOrder) { return getSongs(manager, obj().p("genreid", genre.id), sortBy, sortOrder); } - + /** - * Returns a list containing all tracks of a genre AND and artist. The list is sorted by + * Returns a list containing all tracks of a genre AND and artist. The list is sorted by * artist, album name, filename. - * @param genre Genre - * @param sortBy Sort field, see SortType.* + * + * @param genre Genre + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All tracks of the genre */ - public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, String sortOrder) { - return getSongs(manager, obj().p("filter", obj().p("artistid", artist.id).p("genreid", genre.id)), sortBy, sortOrder); + public ArrayList getSongs(INotifiableManager manager, Artist artist, Genre genre, int sortBy, + String sortOrder) { + return getSongs(manager, obj().p("filter", obj().p("artistid", artist.id).p("genreid", genre.id)), sortBy, + sortOrder); } - + /** * Returns a pre-resized album cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. + * @param cover Cover object + * @param size Minmal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { String url = null; - if(Album.getThumbUri(cover) != ""){ - final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", Album.getThumbUri(cover))); - if(dl != null){ + if (Album.getThumbUri(cover) != "") { + final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", Album + .getThumbUri(cover))); + if (dl != null) { JsonNode details = dl.get("details"); - if(details != null) + if (details != null) url = mConnection.getUrl(getString(details, "path")); } } return getCover(manager, cover, size, url); } - + /** * Returns a list containing all artist IDs that stand for "compilation". * Best case scenario would be only one ID for "Various Artists", though * there are also just "V.A." or "VA" naming conventions. + * * @return List of compilation artist IDs */ public ArrayList getCompilationArtistIDs(INotifiableManager manager) { - + ArrayList artists = getArtists(manager, sort(obj(), SortType.ARTIST, "ascending"), true); ArrayList ids = new ArrayList(); - for(Artist artist : artists){ - if(artist.name.toLowerCase().equals("various artists") || artist.name.toLowerCase().equals("v.a.") || artist.name.toLowerCase().equals("va")) + for (Artist artist : artists) { + if (artist.name.toLowerCase().equals("various artists") || artist.name.toLowerCase().equals("v.a.") || + artist.name.toLowerCase().equals("va")) ids.add(artist.id); } - + return ids; - - } - - - static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { - return new IControlClient.ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - return getString(item, "title"); - } - public int getTime() { - return ControlClient.parseTime(player.get("time")); - } - public int getPlayStatus() { - return getInt(player, "speed"); - } - public int getPlaylistPosition() { - return getInt(player, "position"); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return getInt(player, "percentage"); - } catch (NumberFormatException e) { } - return (float)getDouble(player, "percentage"); - } - public String getFilename() { - return getString(item, "file"); - } - public int getDuration() { - return getInt(item, "duration"); - } - public String getArtist() { - return getString(item, "artist"); - } - public String getAlbum() { - return getString(item, "album"); - } - public int getMediaType() { - return MediaType.MUSIC; - } - public boolean isPlaying() { - return getInt(player, "speed") == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - }; + } } \ No newline at end of file diff --git a/src/org/xbmc/jsonrpc/client/TvShowClient.java b/app/src/main/java/org/xbmc/jsonrpc/client/TvShowClient.java similarity index 63% rename from src/org/xbmc/jsonrpc/client/TvShowClient.java rename to app/src/main/java/org/xbmc/jsonrpc/client/TvShowClient.java index 45b12034..ac429ef4 100644 --- a/src/org/xbmc/jsonrpc/client/TvShowClient.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/TvShowClient.java @@ -21,13 +21,13 @@ package org.xbmc.jsonrpc.client; -import java.util.ArrayList; -import java.util.Iterator; +import android.graphics.Bitmap; import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.ITvShowClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.ITvShowClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Actor; import org.xbmc.api.object.Episode; @@ -39,12 +39,15 @@ import org.xbmc.api.type.MediaType; import org.xbmc.api.type.SortType; import org.xbmc.jsonrpc.Connection; -import android.graphics.Bitmap; + +import java.util.ArrayList; +import java.util.Iterator; /** * TV show client for JSON RPC. *
      * 
    + * * @author Team XBMC */ public class TvShowClient extends Client implements ITvShowClient { @@ -52,135 +55,225 @@ public class TvShowClient extends Client implements ITvShowClient { public TvShowClient(Connection connection) { super(connection); } - - public ArrayList getTvShows(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { + static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { + return new ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + return getString(item, "showtitle"); + } + + public int getTime() { + return ControlClient.parseTime(player.get("time")); + } + + public int getPlayStatus() { + return getInt(player, "speed"); + } + + public int getPlaylistPosition() { + return getInt(player, "position"); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return getInt(player, "percentage"); + } catch (NumberFormatException e) { + } + return (float) getDouble(player, "percentage"); + } + + public String getFilename() { + return getString(item, "file"); + } + + public int getDuration() { + return ControlClient.parseTime(player.get("totaltime")); + } + + public String getArtist() { + if (getInt(item, "season") == 0) { + return "Specials / Episode " + getInt(item, "episode"); + } else { + return "Season " + getInt(item, "season") + " / Episode " + getInt(item, "episode"); + } + } + + public String getAlbum() { + return getString(item, "title"); + } + + public int getMediaType() { + return MediaType.VIDEO_TVSHOW; + } + + public boolean isPlaying() { + return getInt(player, "speed") == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + }; + } + + public ArrayList getTvShows(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { return getTvShows(manager, obj(), sortBy, sortOrder, hideWatched); - } - public ArrayList getTvShows(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, boolean hideWatched) { - - sort(obj.p(PARAM_PROPERTIES, arr().add("plot").add("rating").add("premiered").add("genre").add("mpaa").add("studio").add("file").add("episode").add("playcount").add("art")), sortBy, sortOrder); - + } + + public ArrayList getTvShows(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, + boolean hideWatched) { + + ArrayNode arr = arr(); + arr.add("plot"); + arr.add("rating"); + arr.add("premiered"); + arr.add("genre"); + arr.add("mpaa"); + arr.add("studio"); + arr.add("file"); + arr.add("episode"); + arr.add("playcount"); + arr.add("art"); + sort(obj.p(PARAM_PROPERTIES, arr), sortBy, sortOrder); + final ArrayList tvshows = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetTvShows", obj); final JsonNode jsonShows = result.get("tvshows"); - if(jsonShows != null){ - for (Iterator i = jsonShows.getElements(); i.hasNext();) { - JsonNode jsonShow = (JsonNode)i.next(); - - int playcount =getInt(jsonShow, "playcount"); - if(playcount > 0 && hideWatched) + if (jsonShows != null) { + for (Iterator i = jsonShows.getElements(); i.hasNext(); ) { + JsonNode jsonShow = (JsonNode) i.next(); + + int playcount = getInt(jsonShow, "playcount"); + if (playcount > 0 && hideWatched) continue; - + tvshows.add(new TvShow( - getInt(jsonShow, "tvshowid"), - getString(jsonShow, "label"), - getString(jsonShow, "plot"), - getDouble(jsonShow, "rating"), - getString(jsonShow, "premiered"), - getString(jsonShow, "genre"), - getString(jsonShow, "mpaa"), - getString(jsonShow, "studio"), - getString(jsonShow, "file"), - getInt(jsonShow, "episode"), - playcount, - getInt(jsonShow, "playcount") > 0, - jsonShow.get("art") != null? getString(jsonShow.get("art"), "banner") : "" + getInt(jsonShow, "tvshowid"), + getString(jsonShow, "label"), + getString(jsonShow, "plot"), + getDouble(jsonShow, "rating"), + getString(jsonShow, "premiered"), + getString(jsonShow, "genre"), + getString(jsonShow, "mpaa"), + getString(jsonShow, "studio"), + getString(jsonShow, "file"), + getInt(jsonShow, "episode"), + playcount, + getInt(jsonShow, "playcount") > 0, + jsonShow.get("art") != null ? getString(jsonShow.get("art"), "banner") : "" )); } } return tvshows; } - + /** * Gets all tv show actors from database + * * @return All tv show actors */ public ArrayList getTvShowActors(INotifiableManager manager) { //TODO return new ArrayList(); } - + /** * Gets all tv show genres from database + * * @return All tv show genres */ public ArrayList getTvShowGenres(INotifiableManager manager) { ObjNode obj = sort(obj().p("type", "tvshow"), SortType.TITLE, "descending"); - + final ArrayList genres = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetGenres", obj); final JsonNode jsonGenres = result.get("genres"); - if(jsonGenres != null){ - for (Iterator i = jsonGenres.getElements(); i.hasNext();) { - JsonNode jsonGenre = (JsonNode)i.next(); + if (jsonGenres != null) { + for (Iterator i = jsonGenres.getElements(); i.hasNext(); ) { + JsonNode jsonGenre = (JsonNode) i.next(); genres.add(new Genre( - getInt(jsonGenre, "genreid"), - getString(jsonGenre, "label") + getInt(jsonGenre, "genreid"), + getString(jsonGenre, "label") )); } } return genres; } - + /** * Gets all tv shows with the specified actor + * * @param manager * @param actor * @return */ - public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched) { - return getTvShows(manager, obj().p("filter", obj().p("actor", actor.name)), sortBy, sortOrder, hideWatched); + public ArrayList getTvShows(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched) { + return getTvShows(manager, obj().p("filter", obj().p("actor", actor.name)), sortBy, sortOrder, hideWatched); } - + /** * Gets all tv shows for the specified genre - * */ - public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched) { - return getTvShows(manager, obj().p("filter", obj().p("genreid", genre.id)), sortBy, sortOrder, hideWatched); + public ArrayList getTvShows(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched) { + return getTvShows(manager, obj().p("filter", obj().p("genreid", genre.id)), sortBy, sortOrder, hideWatched); } - + /** * Gets all seasons for the specified show + * * @param manager * @param show * @return */ public ArrayList getSeasons(INotifiableManager manager, TvShow show, boolean hideWatched) { - - ObjNode obj = sort(obj().p("tvshowid", show.id).p(PARAM_PROPERTIES, arr().add("season").add("playcount").add("thumbnail")), SortType.TITLE, "ascending"); - + + ArrayNode arr = arr(); + arr.add("season"); + arr.add("playcount"); + arr.add("thumbnail"); + ObjNode obj = sort(obj().p("tvshowid", show.id).p(PARAM_PROPERTIES, arr), SortType.TITLE, "ascending"); + final ArrayList seasons = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetSeasons", obj); final JsonNode jsonSeasons = result.get("seasons"); - if(jsonSeasons != null){ - for (Iterator i = jsonSeasons.getElements(); i.hasNext();) { - - JsonNode jsonShow = (JsonNode)i.next(); - - int playcount =getInt(jsonShow, "playcount"); - if(playcount > 0 && hideWatched) + if (jsonSeasons != null) { + for (Iterator i = jsonSeasons.getElements(); i.hasNext(); ) { + + JsonNode jsonShow = (JsonNode) i.next(); + + int playcount = getInt(jsonShow, "playcount"); + if (playcount > 0 && hideWatched) continue; - + seasons.add(new Season( - getInt(jsonShow, "season"), - playcount > 0, - show, - getString(jsonShow, "thumbnail") + getInt(jsonShow, "season"), + playcount > 0, + show, + getString(jsonShow, "thumbnail") )); } } return seasons; } - + /** * Gets all seasons for all shows + * * @param manager - * @param show * @return */ - public ArrayList getSeasons(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getSeasons(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { ArrayList shows = getTvShows(manager, sortBy, sortOrder, hideWatched); ArrayList seasons = new ArrayList(); for (TvShow tvShow : shows) { @@ -188,130 +281,170 @@ public ArrayList getSeasons(INotifiableManager manager, int sortBy, Stri } return seasons; } - + /** * Gets all Episodes for the specified show + * * @param manager * @param show * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, int sortBy, String sortOrder, + boolean hideWatched) { return getEpisodes(manager, show, null, sortBy, sortOrder, hideWatched); } - + /** * Gets all Episodes for the specified season + * * @param manager * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getEpisodes(INotifiableManager manager, Season season, int sortBy, String sortOrder, + boolean hideWatched) { return getEpisodes(manager, season.show, season, sortBy, sortOrder, hideWatched); } - + public ArrayList getRecentlyAddedEpisodes(INotifiableManager manager, boolean hideWatched) { - - ObjNode obj = obj().p(PARAM_PROPERTIES, arr().add("title").add("plot").add("rating").add("writer").add("firstaired").add("playcount").add("director").add("season").add("episode").add("file").add("showtitle").add("thumbnail")); - + + ArrayNode arr = arr(); + arr.add("title"); + arr.add("plot"); + arr.add("rating"); + arr.add("writer"); + arr.add("firstaired"); + arr.add("playcount"); + arr.add("director"); + arr.add("season"); + arr.add("episode"); + arr.add("file"); + arr.add("showtitle"); + arr.add("thumbnail"); + ObjNode obj = obj().p(PARAM_PROPERTIES, arr); + final ArrayList episodes = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetRecentlyAddedEpisodes", obj); final JsonNode jsonEpisodes = result.get("episodes"); - if(episodes != null){ - for (Iterator i = jsonEpisodes.getElements(); i.hasNext();) { - JsonNode jsonEpisode = (JsonNode)i.next(); - - int playcount =getInt(jsonEpisode, "playcount"); - if(playcount > 0 && hideWatched) + if (episodes != null) { + for (Iterator i = jsonEpisodes.getElements(); i.hasNext(); ) { + JsonNode jsonEpisode = (JsonNode) i.next(); + + int playcount = getInt(jsonEpisode, "playcount"); + if (playcount > 0 && hideWatched) continue; - + episodes.add(new Episode( - getInt(jsonEpisode, "episodeid"), - getString(jsonEpisode, "title"), - getString(jsonEpisode, "plot"), - getDouble(jsonEpisode, "rating"), - getString(jsonEpisode, "writer"), - getString(jsonEpisode, "firstaired"), - playcount, - getString(jsonEpisode, "director"), - getInt(jsonEpisode, "season"), - getInt(jsonEpisode, "episode"), - "", - getString(jsonEpisode, "file"), - getString(jsonEpisode, "showtitle"), - getString(jsonEpisode, "thumbnail") + getInt(jsonEpisode, "episodeid"), + getString(jsonEpisode, "title"), + getString(jsonEpisode, "plot"), + getDouble(jsonEpisode, "rating"), + getString(jsonEpisode, "writer"), + getString(jsonEpisode, "firstaired"), + playcount, + getString(jsonEpisode, "director"), + getInt(jsonEpisode, "season"), + getInt(jsonEpisode, "episode"), + "", + getString(jsonEpisode, "file"), + getString(jsonEpisode, "showtitle"), + getString(jsonEpisode, "thumbnail") )); } } return episodes; } - + /** * Gets all Episodes for all shows + * * @param manager * @return */ - public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched){ + public ArrayList getEpisodes(INotifiableManager manager, int sortBy, String sortOrder, + boolean hideWatched) { return getEpisodes(manager, obj(), sortBy, sortOrder, hideWatched); } - public ArrayList getEpisodes(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, boolean hideWatched) { - - obj = sort(obj.p(PARAM_PROPERTIES, arr().add("title").add("plot").add("rating").add("writer").add("firstaired").add("playcount").add("director").add("season").add("episode").add("file").add("showtitle").add("thumbnail")), sortBy, sortOrder); - + + public ArrayList getEpisodes(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, + boolean hideWatched) { + + + ArrayNode arr = arr(); + arr.add("title"); + arr.add("plot"); + arr.add("rating"); + arr.add("writer"); + arr.add("firstaired"); + arr.add("playcount"); + arr.add("director"); + arr.add("season"); + arr.add("episode"); + arr.add("file"); + arr.add("showtitle"); + arr.add("thumbnail"); + obj = sort(obj.p(PARAM_PROPERTIES, arr), sortBy, sortOrder); + final ArrayList episodes = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetEpisodes", obj); final JsonNode jsonEpisodes = result.get("episodes"); - if(jsonEpisodes != null){ - for (Iterator i = jsonEpisodes.getElements(); i.hasNext();) { - JsonNode jsonEpisode = (JsonNode)i.next(); - - int playcount =getInt(jsonEpisode, "playcount"); - if(playcount > 0 && hideWatched) + if (jsonEpisodes != null) { + for (Iterator i = jsonEpisodes.getElements(); i.hasNext(); ) { + JsonNode jsonEpisode = (JsonNode) i.next(); + + int playcount = getInt(jsonEpisode, "playcount"); + if (playcount > 0 && hideWatched) continue; - + episodes.add(new Episode( - getInt(jsonEpisode, "episodeid"), - getString(jsonEpisode, "title"), - getString(jsonEpisode, "plot"), - getDouble(jsonEpisode, "rating"), - getString(jsonEpisode, "writer"), - getString(jsonEpisode, "firstaired"), - playcount, - getString(jsonEpisode, "director"), - getInt(jsonEpisode, "season"), - getInt(jsonEpisode, "episode"), - "", - getString(jsonEpisode, "file"), - getString(jsonEpisode, "showtitle"), - getString(jsonEpisode, "thumbnail") + getInt(jsonEpisode, "episodeid"), + getString(jsonEpisode, "title"), + getString(jsonEpisode, "plot"), + getDouble(jsonEpisode, "rating"), + getString(jsonEpisode, "writer"), + getString(jsonEpisode, "firstaired"), + playcount, + getString(jsonEpisode, "director"), + getInt(jsonEpisode, "season"), + getInt(jsonEpisode, "episode"), + "", + getString(jsonEpisode, "file"), + getString(jsonEpisode, "showtitle"), + getString(jsonEpisode, "thumbnail") )); } } return episodes; } - + /** * Gets all Episodes for the specified show and season + * * @param manager * @param show * @param season * @return */ - public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, String sortOrder, boolean hideWatched) { - return getEpisodes(manager, obj().p("tvshowid", show.id).p("season", season.number), sortBy, sortOrder, hideWatched); + public ArrayList getEpisodes(INotifiableManager manager, TvShow show, Season season, int sortBy, + String sortOrder, boolean hideWatched) { + return getEpisodes(manager, obj().p("tvshowid", show.id).p("season", season.number), sortBy, sortOrder, + hideWatched); } - + public TvShow updateTvShowDetails(INotifiableManager manager, TvShow show) { - - ObjNode obj = obj().p("tvshowid", show.id).p(PARAM_PROPERTIES, arr().add("cast")); - + + ArrayNode arr = arr(); + arr.add("cast"); + ObjNode obj = obj().p("tvshowid", show.id).p(PARAM_PROPERTIES, arr); + final ArrayList actors = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetTvShowDetails", obj); - if(result.size() > 0){ + if (result.size() > 0) { final JsonNode jsonCast = result.get("tvshowdetails").get("cast"); - for (Iterator i = jsonCast.getElements(); i.hasNext();) { - JsonNode jsonActor = (JsonNode)i.next(); + for (Iterator i = jsonCast.getElements(); i.hasNext(); ) { + JsonNode jsonActor = (JsonNode) i.next(); actors.add(new Actor( - getInt(jsonActor,"actorid"), + getInt(jsonActor, "actorid"), getString(jsonActor, "name"), getString(jsonActor, "thumbnail"), getString(jsonActor, "role") @@ -321,18 +454,20 @@ public TvShow updateTvShowDetails(INotifiableManager manager, TvShow show) { } return show; } - + public Episode updateEpisodeDetails(INotifiableManager manager, Episode episode) { - ObjNode obj = obj().p("episodeid", episode.id).p(PARAM_PROPERTIES, arr().add("cast")); - + ArrayNode arr = arr(); + arr.add("cast"); + ObjNode obj = obj().p("episodeid", episode.id).p(PARAM_PROPERTIES, arr); + final ArrayList actors = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetEpisodeDetails", obj); - if(result.size() > 0){ + if (result.size() > 0) { final JsonNode jsonCast = result.get("episodedetails").get("cast"); - for (Iterator i = jsonCast.getElements(); i.hasNext();) { - JsonNode jsonActor = (JsonNode)i.next(); + for (Iterator i = jsonCast.getElements(); i.hasNext(); ) { + JsonNode jsonActor = (JsonNode) i.next(); actors.add(new Actor( - getInt(jsonActor,"actorid"), + getInt(jsonActor, "actorid"), getString(jsonActor, "name"), getString(jsonActor, "thumbnail"), getString(jsonActor, "role") @@ -342,87 +477,36 @@ public Episode updateEpisodeDetails(INotifiableManager manager, Episode episode) } return episode; } - - static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { - return new ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - return getString(item, "showtitle"); - } - public int getTime() { - return ControlClient.parseTime(player.get("time")); - } - public int getPlayStatus() { - return getInt(player, "speed"); - } - public int getPlaylistPosition() { - return getInt(player, "position"); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return getInt(player, "percentage"); - } catch (NumberFormatException e) { } - return (float)getDouble(player, "percentage"); - } - public String getFilename() { - return getString(item, "file"); - } - public int getDuration() { - return ControlClient.parseTime(player.get("totaltime")); - } - public String getArtist() { - if(getInt(item, "season") == 0) { - return "Specials / Episode " + getInt(item, "episode"); - } - else { - return "Season " + getInt(item, "season") + " / Episode " + getInt(item, "episode"); - } - } - public String getAlbum() { - return getString(item, "title"); - } - public int getMediaType() { - return MediaType.VIDEO_TVSHOW; - } - public boolean isPlaying() { - return getInt(player, "speed") == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - }; - } - + /** * Returns a pre-resized movie cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. + * @param cover Cover object + * @param size Minmal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { - + String url = null; - if(!TvShow.getThumbUri(cover).equals("")){ - final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", TvShow.getThumbUri(cover))); - if(dl != null){ + if (!TvShow.getThumbUri(cover).equals("")) { + final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", + TvShow.getThumbUri(cover))); + if (dl != null) { JsonNode details = dl.get("details"); - if(details != null) + if (details != null) url = mConnection.getUrl(getString(details, "path")); } } return getCover(manager, cover, size, url); } - + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { diff --git a/src/org/xbmc/jsonrpc/client/VideoClient.java b/app/src/main/java/org/xbmc/jsonrpc/client/VideoClient.java similarity index 74% rename from src/org/xbmc/jsonrpc/client/VideoClient.java rename to app/src/main/java/org/xbmc/jsonrpc/client/VideoClient.java index 3950a3c8..70bb6d1d 100644 --- a/src/org/xbmc/jsonrpc/client/VideoClient.java +++ b/app/src/main/java/org/xbmc/jsonrpc/client/VideoClient.java @@ -21,13 +21,13 @@ package org.xbmc.jsonrpc.client; -import java.util.ArrayList; -import java.util.Iterator; +import android.graphics.Bitmap; import org.codehaus.jackson.JsonNode; +import org.codehaus.jackson.node.ArrayNode; import org.xbmc.api.business.INotifiableManager; -import org.xbmc.api.data.IVideoClient; import org.xbmc.api.data.IControlClient.ICurrentlyPlaying; +import org.xbmc.api.data.IVideoClient; import org.xbmc.api.info.PlayStatus; import org.xbmc.api.object.Actor; import org.xbmc.api.object.Genre; @@ -37,134 +37,235 @@ import org.xbmc.api.type.MediaType; import org.xbmc.api.type.SortType; import org.xbmc.jsonrpc.Connection; -import android.graphics.Bitmap; + +import java.util.ArrayList; +import java.util.Iterator; /** * Takes care of everything related to the video database. - * + * * @author Team XBMC */ public class VideoClient extends Client implements IVideoClient { - + public static final String TAG = "VideoClient"; public static final int PLAYLIST_ID = 1; - + public static final int PLAYLIST_LIMIT = 100; - + /** * Class constructor needs reference to HTTP client connection + * * @param connection */ public VideoClient(Connection connection) { super(connection); } - + + static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { + + return new ICurrentlyPlaying() { + private static final long serialVersionUID = 5036994329211476714L; + + public String getTitle() { + String title = getString(item, "title"); + if (title != null && !title.equals("")) + return title; + String[] path = getString(item, "file").replaceAll("\\\\", "/").split("/"); + return path[path.length - 1]; + } + + public int getTime() { + return ControlClient.parseTime(player.get("time")); + } + + public int getPlayStatus() { + return getInt(player, "speed"); + } + + public int getPlaylistPosition() { + return getInt(player, "position"); + } + + //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 + public float getPercentage() { + try { + return getInt(player, "percentage"); + } catch (NumberFormatException e) { + } + return (float) getDouble(player, "percentage"); + } + + public String getFilename() { + return getString(item, "file"); + } + + public int getDuration() { + return ControlClient.parseTime(player.get("totaltime")); + } + + public String getArtist() { + return getString(item, "genre"); + } + + public String getAlbum() { + String title = getString(item, "tagline"); + if (title != null) + return title; + String path = getString(item, "file").replaceAll("\\\\", "/"); + return path.substring(0, path.lastIndexOf("/")); + } + + public int getMediaType() { + return MediaType.VIDEO; + } + + public boolean isPlaying() { + return getInt(player, "speed") == PlayStatus.PLAYING; + } + + public int getHeight() { + return 0; + } + + public int getWidth() { + return 0; + } + }; + } + /** * Updates host info on the connection. + * * @param host */ public void setHost(Host host) { mConnection.setHost(host); } - + /** * Gets all movies from database - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies */ public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, boolean hideWatched) { return getMovies(manager, obj(), sortBy, sortOrder, hideWatched); } - - public ArrayList getMovies(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, boolean hideWatched) { - - obj = sort(obj.p(PARAM_PROPERTIES, arr().add("director").add("file").add("genre").add("imdbnumber").add("playcount").add("rating").add("runtime").add("thumbnail").add("year")), sortBy, sortOrder); - + + public ArrayList getMovies(INotifiableManager manager, ObjNode obj, int sortBy, String sortOrder, + boolean hideWatched) { + + ArrayNode arr = arr(); + arr.add("director"); + arr.add("file"); + arr.add("genre"); + arr.add("imdbnumber"); + arr.add("playcount"); + arr.add("rating"); + arr.add("runtime"); + arr.add("thumbnail"); + arr.add("year"); + obj = sort(obj.p(PARAM_PROPERTIES, arr), sortBy, sortOrder); + final ArrayList movies = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetMovies", obj); final JsonNode jsonMovies = result.get("movies"); - if(jsonMovies != null){ - for (Iterator i = jsonMovies.getElements(); i.hasNext();) { - JsonNode jsonMovie = (JsonNode)i.next(); - - int playcount =getInt(jsonMovie, "playcount"); - if(playcount > 0 && hideWatched) + if (jsonMovies != null) { + for (Iterator i = jsonMovies.getElements(); i.hasNext(); ) { + JsonNode jsonMovie = (JsonNode) i.next(); + + int playcount = getInt(jsonMovie, "playcount"); + if (playcount > 0 && hideWatched) continue; - + int runtime = getInt(jsonMovie, "runtime"); String formatted_runtime = ""; - if(runtime != -1){ - if(runtime >= 3600) + if (runtime != -1) { + if (runtime >= 3600) formatted_runtime = (runtime / 3600) + "hr "; - formatted_runtime += ((runtime % 3600) / 60) + "min"; + formatted_runtime += ((runtime % 3600) / 60) + "min"; } - - + + movies.add(new Movie( - getInt(jsonMovie, "movieid"), - getString(jsonMovie, "label"), - getInt(jsonMovie, "year"), - "", - getString(jsonMovie, "file"), - getString(jsonMovie, "director"), - formatted_runtime, - getString(jsonMovie, "genre"), - getDouble(jsonMovie, "rating"), - playcount, - getString(jsonMovie, "imdbnumber"), - getString(jsonMovie, "thumbnail") + getInt(jsonMovie, "movieid"), + getString(jsonMovie, "label"), + getInt(jsonMovie, "year"), + "", + getString(jsonMovie, "file"), + getString(jsonMovie, "director"), + formatted_runtime, + getString(jsonMovie, "genre"), + getDouble(jsonMovie, "rating"), + playcount, + getString(jsonMovie, "imdbnumber"), + getString(jsonMovie, "thumbnail") )); } } return movies; } - + /** * Gets movies from database with offset - * @param sortBy Sort field, see SortType.* + * + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return Movies with offset */ - public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, boolean hideWatched) { - + public ArrayList getMovies(INotifiableManager manager, int sortBy, String sortOrder, int offset, + boolean hideWatched) { + return getMovies(manager, obj().p("limits", obj().p("start", 0)), sortBy, sortOrder, hideWatched); } - + /** * Gets all movies with an actor from database - * @param actor Display only movies with this actor. - * @param sortBy Sort field, see SortType.* + * + * @param actor Display only movies with this actor. + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies with an actor */ - public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, boolean hideWatched) { + public ArrayList getMovies(INotifiableManager manager, Actor actor, int sortBy, String sortOrder, + boolean hideWatched) { return getMovies(manager, obj().p("filter", obj().p("actor", actor.name)), sortBy, sortOrder, hideWatched); } - + /** * Gets all movies of a genre from database - * @param genre Display only movies of this genre. - * @param sortBy Sort field, see SortType.* + * + * @param genre Display only movies of this genre. + * @param sortBy Sort field, see SortType.* * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. * @return All movies of a genre */ - public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, boolean hideWatched) { - + public ArrayList getMovies(INotifiableManager manager, Genre genre, int sortBy, String sortOrder, + boolean hideWatched) { + return getMovies(manager, obj().p("filter", obj().p("genreid", genre.id)), sortBy, sortOrder, hideWatched); } - + /** * Gets all movies from database - * @param sortBy Sort field, see SortType.* - * @param sortOrder Sort order, must be either SortType.ASC or SortType.DESC. + * * @return Updated movie */ public Movie updateMovieDetails(INotifiableManager manager, Movie movie) { - - ObjNode obj = obj().p("movieid", movie.getId()).p(PARAM_PROPERTIES, arr().add("cast").add("mpaa").add("plot").add("studio").add("tagline").add("trailer").add("votes")); - + + ArrayNode arr = arr(); + arr.add("cast"); + arr.add("mpaa"); + arr.add("plot"); + arr.add("studio"); + arr.add("tagline"); + arr.add("trailer"); + arr.add("votes"); + ObjNode obj = obj().p("movieid", movie.getId()).p(PARAM_PROPERTIES, arr); + final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetMovieDetails", obj); final JsonNode jsonMovie = result.get("moviedetails"); movie.tagline = getString(jsonMovie, "tagline"); @@ -172,216 +273,175 @@ public Movie updateMovieDetails(INotifiableManager manager, Movie movie) { movie.numVotes = getInt(jsonMovie, "votes"); movie.studio = getString(jsonMovie, "studio"); movie.rated = getString(jsonMovie, "mpaa"); - movie.trailerUrl = getString(jsonMovie, "trailer"); - - + movie.trailerUrl = getString(jsonMovie, "trailer"); + + ArrayList actors = new ArrayList(); final JsonNode jsonCast = jsonMovie.get("cast"); - for (Iterator i = jsonCast.getElements(); i.hasNext();) { - JsonNode jsonActor = (JsonNode)i.next(); + for (Iterator i = jsonCast.getElements(); i.hasNext(); ) { + JsonNode jsonActor = (JsonNode) i.next(); actors.add(new Actor( - getInt(jsonActor,"actorid"), + getInt(jsonActor, "actorid"), getString(jsonActor, "name"), getString(jsonActor, "thumbnail"), getString(jsonActor, "role") - )); + )); } - + movie.actors = actors; - + return movie; } - + /** - * Gets all actors from database. Use {@link getMovieActors()} and - * {@link getTvActors()} for filtered actors. + * Gets all actors from database. Use {@link #getMovieActors} and + * {@link #getTvShowActors} for filtered actors. + * * @return All actors */ public ArrayList getActors(INotifiableManager manager) { //TODO return new ArrayList(); } - + /** * Gets all movie actors from database + * * @return All movie actors */ public ArrayList getMovieActors(INotifiableManager manager) { //TODO return new ArrayList(); } - + /** * Gets all movie actors from database + * * @return All movie actors */ public ArrayList getTvShowActors(INotifiableManager manager) { return new ArrayList();//parseActors(mConnection.query("QueryVideoDatabase", sb.toString(), manager)); } - + /** * Gets all movie genres from database + * * @return All movie genres */ - + public ArrayList getGenres(INotifiableManager manager, String type) { ObjNode obj = sort(obj().p("type", type), SortType.TITLE, "descending"); - + final ArrayList genres = new ArrayList(); final JsonNode result = mConnection.getJson(manager, "VideoLibrary.GetGenres", obj); final JsonNode jsonGenres = result.get("genres"); - if(jsonGenres != null){ - for (Iterator i = jsonGenres.getElements(); i.hasNext();) { - JsonNode jsonGenre = (JsonNode)i.next(); + if (jsonGenres != null) { + for (Iterator i = jsonGenres.getElements(); i.hasNext(); ) { + JsonNode jsonGenre = (JsonNode) i.next(); genres.add(new Genre( - getInt(jsonGenre, "genreid"), - getString(jsonGenre, "label") + getInt(jsonGenre, "genreid"), + getString(jsonGenre, "label") )); } } return genres; } - public ArrayList getMovieGenres(INotifiableManager manager) { return getGenres(manager, "movie"); } - + /** * Gets all tv show genres from database + * * @return All tv show genres */ public ArrayList getTvShowGenres(INotifiableManager manager) { return getGenres(manager, "tvshow"); } - /** * Returns a pre-resized movie cover. Pre-resizing is done in a way that * the bitmap at least as large as the specified size but not larger than * the double. + * * @param manager Postback manager - * @param cover Cover object - * @param size Minmal size to pre-resize to. + * @param cover Cover object + * @param size Minmal size to pre-resize to. * @return Thumbnail bitmap */ public Bitmap getCover(INotifiableManager manager, ICoverArt cover, int size) { String url = null; - if(Movie.getThumbUri(cover) != ""){ - final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", Movie.getThumbUri(cover))); - if(dl != null){ + if (Movie.getThumbUri(cover) != "") { + final JsonNode dl = mConnection.getJson(manager, "Files.PrepareDownload", obj().p("path", + Movie.getThumbUri(cover))); + if (dl != null) { JsonNode details = dl.get("details"); - if(details != null) + if (details != null) url = mConnection.getUrl(getString(details, "path")); } } return getCover(manager, cover, size, url); } - - - static ICurrentlyPlaying getCurrentlyPlaying(final JsonNode player, final JsonNode item) { - - return new ICurrentlyPlaying() { - private static final long serialVersionUID = 5036994329211476714L; - public String getTitle() { - String title =getString(item, "title"); - if (title != null && !title.equals("")) - return title; - String[] path = getString(item, "file").replaceAll("\\\\", "/").split("/"); - return path[path.length - 1]; - } - public int getTime() { - return ControlClient.parseTime(player.get("time")); - } - public int getPlayStatus() { - return getInt(player, "speed"); - } - public int getPlaylistPosition() { - return getInt(player, "position"); - } - //Workarond for bug in Float.valueOf(): http://code.google.com/p/android/issues/detail?id=3156 - public float getPercentage() { - try{ - return getInt(player, "percentage"); - } catch (NumberFormatException e) { } - return (float)getDouble(player, "percentage"); - } - public String getFilename() { - return getString(item, "file"); - } - public int getDuration() { - return ControlClient.parseTime(player.get("totaltime")); - } - public String getArtist() { - return getString(item, "genre"); - } - public String getAlbum() { - String title = getString(item, "tagline"); - if (title != null) - return title; - String path = getString(item, "file").replaceAll("\\\\", "/"); - return path.substring(0, path.lastIndexOf("/")); - } - public int getMediaType() { - return MediaType.VIDEO; - } - public boolean isPlaying() { - return getInt(player, "speed") == PlayStatus.PLAYING; - } - public int getHeight() { - return 0; - } - public int getWidth() { - return 0; - } - }; - } /** * Retrieves the currently playing video number in the playlist. + * * @return Number of items in the playlist */ public int getPlaylistPosition(INotifiableManager manager) { - final JsonNode active = mConnection.getJson(manager, "Player.GetActivePlayers", null).get(0); - return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getInt(active, "playerid")).p(PARAM_PROPERTIES, arr().add("position")), "position"); + final JsonNode active = mConnection.getJson(manager, "Player.GetActivePlayers", null).get(0); + ArrayNode arr = arr(); + arr.add("position"); + return mConnection.getInt(manager, "Player.GetProperties", obj().p("playerid", getInt(active, + "playerid")).p(PARAM_PROPERTIES, arr), "position"); } - + /** * Sets the media at playlist position to be the next item to be played. + * * @param position New position, starting with 0. * @return True on success, false otherwise. */ public boolean setPlaylistPosition(INotifiableManager manager, int position) { int playerid = getActivePlayerId(manager); - if(playerid == -1) - return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", PLAYLIST_ID).p("position", position))).equals("OK"); + if (playerid == -1) + return mConnection.getString(manager, "Player.Open", obj().p("item", obj().p("playlistid", + PLAYLIST_ID).p("position", position))).equals("OK"); else - return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", getActivePlayerId(manager)).p("position", position)).equals("OK"); + return mConnection.getString(manager, "Player.GoTo", obj().p("playerid", + getActivePlayerId(manager)).p("position", position)).equals("OK"); } - + /** - * Returns the first {@link PLAYLIST_LIMIT} videos of the playlist. + * Returns the first videos of the playlist. + * * @return Videos in the playlist. */ public ArrayList getPlaylist(INotifiableManager manager) { - JsonNode jsonItems = mConnection.getJson(manager, "PlayList.GetItems", obj().p("playlistid", PLAYLIST_ID).p("limits", obj().p("start", 0).p("end", PLAYLIST_LIMIT)).p("properties", arr().add("file"))); + ArrayNode arr = arr(); + arr.add("file"); + JsonNode jsonItems = mConnection.getJson(manager, "PlayList.GetItems", obj().p("playlistid", + PLAYLIST_ID).p("limits", obj().p("start", 0).p("end", PLAYLIST_LIMIT)).p("properties", arr)); JsonNode jsonSongs = jsonItems.get("items"); final ArrayList files = new ArrayList(); if (jsonSongs != null) { - for (Iterator i = jsonSongs.getElements(); i.hasNext();) { - JsonNode jsonSong = (JsonNode)i.next(); + for (Iterator i = jsonSongs.getElements(); i.hasNext(); ) { + JsonNode jsonSong = (JsonNode) i.next(); files.add(getString(jsonSong, "file")); } } return files; } - + /** * Removes media from the current playlist. It is not possible to remove the media if it is currently being played. - * @param position Complete path (including filename) of the media to be removed. + * + * @param path Complete path (including filename) of the media to be removed. * @return True on success, false otherwise. */ public boolean removeFromPlaylist(INotifiableManager manager, String path) { - return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", "position")).equals("OK"); + return mConnection.getString(manager, "Playlist.Remove", obj().p("playlistid", PLAYLIST_ID).p("position", + "position")).equals("OK"); } } diff --git a/app/src/main/res/anim/slide_left.xml b/app/src/main/res/anim/slide_left.xml new file mode 100644 index 00000000..3f3a8b00 --- /dev/null +++ b/app/src/main/res/anim/slide_left.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/anim/slide_right.xml b/app/src/main/res/anim/slide_right.xml new file mode 100644 index 00000000..d59fe5f8 --- /dev/null +++ b/app/src/main/res/anim/slide_right.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/res/drawable-hdpi-v4/about_back.png b/app/src/main/res/drawable-hdpi-v4/about_back.png similarity index 100% rename from res/drawable-hdpi-v4/about_back.png rename to app/src/main/res/drawable-hdpi-v4/about_back.png diff --git a/res/drawable-hdpi-v4/bottom_logo_down.png b/app/src/main/res/drawable-hdpi-v4/bottom_logo_down.png similarity index 100% rename from res/drawable-hdpi-v4/bottom_logo_down.png rename to app/src/main/res/drawable-hdpi-v4/bottom_logo_down.png diff --git a/res/drawable-hdpi-v4/bottom_logo_up.png b/app/src/main/res/drawable-hdpi-v4/bottom_logo_up.png similarity index 100% rename from res/drawable-hdpi-v4/bottom_logo_up.png rename to app/src/main/res/drawable-hdpi-v4/bottom_logo_up.png diff --git a/res/drawable-hdpi-v4/bottom_text_down.9.png b/app/src/main/res/drawable-hdpi-v4/bottom_text_down.9.png similarity index 100% rename from res/drawable-hdpi-v4/bottom_text_down.9.png rename to app/src/main/res/drawable-hdpi-v4/bottom_text_down.9.png diff --git a/res/drawable-hdpi-v4/bottom_text_up.9.png b/app/src/main/res/drawable-hdpi-v4/bottom_text_up.9.png similarity index 100% rename from res/drawable-hdpi-v4/bottom_text_up.9.png rename to app/src/main/res/drawable-hdpi-v4/bottom_text_up.9.png diff --git a/res/drawable-hdpi-v4/bottombar_bg.png b/app/src/main/res/drawable-hdpi-v4/bottombar_bg.png similarity index 100% rename from res/drawable-hdpi-v4/bottombar_bg.png rename to app/src/main/res/drawable-hdpi-v4/bottombar_bg.png diff --git a/res/drawable-hdpi-v4/bubble_add.png b/app/src/main/res/drawable-hdpi-v4/bubble_add.png similarity index 100% rename from res/drawable-hdpi-v4/bubble_add.png rename to app/src/main/res/drawable-hdpi-v4/bubble_add.png diff --git a/res/drawable-hdpi-v4/bubble_del_down.png b/app/src/main/res/drawable-hdpi-v4/bubble_del_down.png similarity index 100% rename from res/drawable-hdpi-v4/bubble_del_down.png rename to app/src/main/res/drawable-hdpi-v4/bubble_del_down.png diff --git a/res/drawable-hdpi-v4/bubble_del_up.png b/app/src/main/res/drawable-hdpi-v4/bubble_del_up.png similarity index 100% rename from res/drawable-hdpi-v4/bubble_del_up.png rename to app/src/main/res/drawable-hdpi-v4/bubble_del_up.png diff --git a/res/drawable-hdpi-v4/coverbox_back.png b/app/src/main/res/drawable-hdpi-v4/coverbox_back.png similarity index 100% rename from res/drawable-hdpi-v4/coverbox_back.png rename to app/src/main/res/drawable-hdpi-v4/coverbox_back.png diff --git a/res/drawable-hdpi-v4/default_album.png b/app/src/main/res/drawable-hdpi-v4/default_album.png similarity index 100% rename from res/drawable-hdpi-v4/default_album.png rename to app/src/main/res/drawable-hdpi-v4/default_album.png diff --git a/res/drawable-hdpi-v4/default_jewel.png b/app/src/main/res/drawable-hdpi-v4/default_jewel.png similarity index 100% rename from res/drawable-hdpi-v4/default_jewel.png rename to app/src/main/res/drawable-hdpi-v4/default_jewel.png diff --git a/res/drawable-hdpi-v4/default_poster.png b/app/src/main/res/drawable-hdpi-v4/default_poster.png similarity index 100% rename from res/drawable-hdpi-v4/default_poster.png rename to app/src/main/res/drawable-hdpi-v4/default_poster.png diff --git a/res/drawable-hdpi-v4/default_season.png b/app/src/main/res/drawable-hdpi-v4/default_season.png similarity index 100% rename from res/drawable-hdpi-v4/default_season.png rename to app/src/main/res/drawable-hdpi-v4/default_season.png diff --git a/res/drawable-hdpi-v4/default_tvshow.png b/app/src/main/res/drawable-hdpi-v4/default_tvshow.png similarity index 100% rename from res/drawable-hdpi-v4/default_tvshow.png rename to app/src/main/res/drawable-hdpi-v4/default_tvshow.png diff --git a/res/drawable-hdpi-v4/icon.png b/app/src/main/res/drawable-hdpi-v4/icon.png similarity index 100% rename from res/drawable-hdpi-v4/icon.png rename to app/src/main/res/drawable-hdpi-v4/icon.png diff --git a/res/drawable-hdpi-v4/icon_album.png b/app/src/main/res/drawable-hdpi-v4/icon_album.png similarity index 100% rename from res/drawable-hdpi-v4/icon_album.png rename to app/src/main/res/drawable-hdpi-v4/icon_album.png diff --git a/res/drawable-hdpi-v4/icon_album_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_album_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_album_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_album_dark.png diff --git a/res/drawable-hdpi-v4/icon_album_dark_big.png b/app/src/main/res/drawable-hdpi-v4/icon_album_dark_big.png similarity index 100% rename from res/drawable-hdpi-v4/icon_album_dark_big.png rename to app/src/main/res/drawable-hdpi-v4/icon_album_dark_big.png diff --git a/res/drawable-hdpi-v4/icon_artist.png b/app/src/main/res/drawable-hdpi-v4/icon_artist.png similarity index 100% rename from res/drawable-hdpi-v4/icon_artist.png rename to app/src/main/res/drawable-hdpi-v4/icon_artist.png diff --git a/res/drawable-hdpi-v4/icon_artist_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_artist_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_artist_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_artist_dark.png diff --git a/res/drawable-hdpi-v4/icon_file.png b/app/src/main/res/drawable-hdpi-v4/icon_file.png similarity index 100% rename from res/drawable-hdpi-v4/icon_file.png rename to app/src/main/res/drawable-hdpi-v4/icon_file.png diff --git a/res/drawable-hdpi-v4/icon_folder.png b/app/src/main/res/drawable-hdpi-v4/icon_folder.png similarity index 100% rename from res/drawable-hdpi-v4/icon_folder.png rename to app/src/main/res/drawable-hdpi-v4/icon_folder.png diff --git a/res/drawable-hdpi-v4/icon_folder_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_folder_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_folder_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_folder_dark.png diff --git a/res/drawable-hdpi-v4/icon_genre.png b/app/src/main/res/drawable-hdpi-v4/icon_genre.png similarity index 100% rename from res/drawable-hdpi-v4/icon_genre.png rename to app/src/main/res/drawable-hdpi-v4/icon_genre.png diff --git a/res/drawable-hdpi-v4/icon_genre_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_genre_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_genre_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_genre_dark.png diff --git a/res/drawable-hdpi-v4/icon_home_movie.png b/app/src/main/res/drawable-hdpi-v4/icon_home_movie.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_movie.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_movie.png diff --git a/res/drawable-hdpi-v4/icon_home_music.png b/app/src/main/res/drawable-hdpi-v4/icon_home_music.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_music.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_music.png diff --git a/res/drawable-hdpi-v4/icon_home_picture.png b/app/src/main/res/drawable-hdpi-v4/icon_home_picture.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_picture.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_picture.png diff --git a/res/drawable-hdpi-v4/icon_home_playing.png b/app/src/main/res/drawable-hdpi-v4/icon_home_playing.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_playing.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_playing.png diff --git a/res/drawable-hdpi-v4/icon_home_power.png b/app/src/main/res/drawable-hdpi-v4/icon_home_power.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_power.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_power.png diff --git a/res/drawable-hdpi-v4/icon_home_reconnect.png b/app/src/main/res/drawable-hdpi-v4/icon_home_reconnect.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_reconnect.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_reconnect.png diff --git a/res/drawable-hdpi-v4/icon_home_remote.png b/app/src/main/res/drawable-hdpi-v4/icon_home_remote.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_remote.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_remote.png diff --git a/res/drawable-hdpi-v4/icon_home_tv.png b/app/src/main/res/drawable-hdpi-v4/icon_home_tv.png similarity index 100% rename from res/drawable-hdpi-v4/icon_home_tv.png rename to app/src/main/res/drawable-hdpi-v4/icon_home_tv.png diff --git a/res/drawable-hdpi-v4/icon_lastfm.png b/app/src/main/res/drawable-hdpi-v4/icon_lastfm.png similarity index 100% rename from res/drawable-hdpi-v4/icon_lastfm.png rename to app/src/main/res/drawable-hdpi-v4/icon_lastfm.png diff --git a/res/drawable-hdpi-v4/icon_movie_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_movie_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_movie_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_movie_dark.png diff --git a/res/drawable-hdpi-v4/icon_picture.png b/app/src/main/res/drawable-hdpi-v4/icon_picture.png similarity index 100% rename from res/drawable-hdpi-v4/icon_picture.png rename to app/src/main/res/drawable-hdpi-v4/icon_picture.png diff --git a/res/drawable-hdpi-v4/icon_play.png b/app/src/main/res/drawable-hdpi-v4/icon_play.png similarity index 100% rename from res/drawable-hdpi-v4/icon_play.png rename to app/src/main/res/drawable-hdpi-v4/icon_play.png diff --git a/res/drawable-hdpi-v4/icon_playlist_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_playlist_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_playlist_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_playlist_dark.png diff --git a/res/drawable-hdpi-v4/icon_shoutcast.png b/app/src/main/res/drawable-hdpi-v4/icon_shoutcast.png similarity index 100% rename from res/drawable-hdpi-v4/icon_shoutcast.png rename to app/src/main/res/drawable-hdpi-v4/icon_shoutcast.png diff --git a/res/drawable-hdpi-v4/icon_song.png b/app/src/main/res/drawable-hdpi-v4/icon_song.png similarity index 100% rename from res/drawable-hdpi-v4/icon_song.png rename to app/src/main/res/drawable-hdpi-v4/icon_song.png diff --git a/res/drawable-hdpi-v4/icon_song_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_song_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_song_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_song_dark.png diff --git a/res/drawable-hdpi-v4/icon_song_light.png b/app/src/main/res/drawable-hdpi-v4/icon_song_light.png similarity index 100% rename from res/drawable-hdpi-v4/icon_song_light.png rename to app/src/main/res/drawable-hdpi-v4/icon_song_light.png diff --git a/res/drawable-hdpi-v4/icon_va_dark.png b/app/src/main/res/drawable-hdpi-v4/icon_va_dark.png similarity index 100% rename from res/drawable-hdpi-v4/icon_va_dark.png rename to app/src/main/res/drawable-hdpi-v4/icon_va_dark.png diff --git a/res/drawable-hdpi-v4/icon_video.png b/app/src/main/res/drawable-hdpi-v4/icon_video.png similarity index 100% rename from res/drawable-hdpi-v4/icon_video.png rename to app/src/main/res/drawable-hdpi-v4/icon_video.png diff --git a/res/drawable-hdpi-v4/jewel_cd.9.png b/app/src/main/res/drawable-hdpi-v4/jewel_cd.9.png similarity index 100% rename from res/drawable-hdpi-v4/jewel_cd.9.png rename to app/src/main/res/drawable-hdpi-v4/jewel_cd.9.png diff --git a/res/drawable-hdpi-v4/jewel_dvd.9.png b/app/src/main/res/drawable-hdpi-v4/jewel_dvd.9.png similarity index 100% rename from res/drawable-hdpi-v4/jewel_dvd.9.png rename to app/src/main/res/drawable-hdpi-v4/jewel_dvd.9.png diff --git a/res/drawable-hdpi-v4/jewel_tv.9.png b/app/src/main/res/drawable-hdpi-v4/jewel_tv.9.png similarity index 100% rename from res/drawable-hdpi-v4/jewel_tv.9.png rename to app/src/main/res/drawable-hdpi-v4/jewel_tv.9.png diff --git a/res/drawable-hdpi-v4/layout_top_bar.9.png b/app/src/main/res/drawable-hdpi-v4/layout_top_bar.9.png similarity index 100% rename from res/drawable-hdpi-v4/layout_top_bar.9.png rename to app/src/main/res/drawable-hdpi-v4/layout_top_bar.9.png diff --git a/res/drawable-hdpi-v4/menu_about.png b/app/src/main/res/drawable-hdpi-v4/menu_about.png similarity index 100% rename from res/drawable-hdpi-v4/menu_about.png rename to app/src/main/res/drawable-hdpi-v4/menu_about.png diff --git a/res/drawable-hdpi-v4/menu_add_host.png b/app/src/main/res/drawable-hdpi-v4/menu_add_host.png similarity index 100% rename from res/drawable-hdpi-v4/menu_add_host.png rename to app/src/main/res/drawable-hdpi-v4/menu_add_host.png diff --git a/res/drawable-hdpi-v4/menu_album.png b/app/src/main/res/drawable-hdpi-v4/menu_album.png similarity index 100% rename from res/drawable-hdpi-v4/menu_album.png rename to app/src/main/res/drawable-hdpi-v4/menu_album.png diff --git a/res/drawable-hdpi-v4/menu_download.png b/app/src/main/res/drawable-hdpi-v4/menu_download.png similarity index 100% rename from res/drawable-hdpi-v4/menu_download.png rename to app/src/main/res/drawable-hdpi-v4/menu_download.png diff --git a/res/drawable-hdpi-v4/menu_exit.png b/app/src/main/res/drawable-hdpi-v4/menu_exit.png similarity index 100% rename from res/drawable-hdpi-v4/menu_exit.png rename to app/src/main/res/drawable-hdpi-v4/menu_exit.png diff --git a/res/drawable-hdpi-v4/menu_gesture_mode.png b/app/src/main/res/drawable-hdpi-v4/menu_gesture_mode.png similarity index 100% rename from res/drawable-hdpi-v4/menu_gesture_mode.png rename to app/src/main/res/drawable-hdpi-v4/menu_gesture_mode.png diff --git a/res/drawable-hdpi-v4/menu_hide_watched.png b/app/src/main/res/drawable-hdpi-v4/menu_hide_watched.png similarity index 100% rename from res/drawable-hdpi-v4/menu_hide_watched.png rename to app/src/main/res/drawable-hdpi-v4/menu_hide_watched.png diff --git a/res/drawable-hdpi-v4/menu_nowplaying.png b/app/src/main/res/drawable-hdpi-v4/menu_nowplaying.png similarity index 100% rename from res/drawable-hdpi-v4/menu_nowplaying.png rename to app/src/main/res/drawable-hdpi-v4/menu_nowplaying.png diff --git a/res/drawable-hdpi-v4/menu_qr_code.png b/app/src/main/res/drawable-hdpi-v4/menu_qr_code.png similarity index 100% rename from res/drawable-hdpi-v4/menu_qr_code.png rename to app/src/main/res/drawable-hdpi-v4/menu_qr_code.png diff --git a/res/drawable-hdpi-v4/menu_refresh.png b/app/src/main/res/drawable-hdpi-v4/menu_refresh.png similarity index 100% rename from res/drawable-hdpi-v4/menu_refresh.png rename to app/src/main/res/drawable-hdpi-v4/menu_refresh.png diff --git a/res/drawable-hdpi-v4/menu_remote.png b/app/src/main/res/drawable-hdpi-v4/menu_remote.png similarity index 100% rename from res/drawable-hdpi-v4/menu_remote.png rename to app/src/main/res/drawable-hdpi-v4/menu_remote.png diff --git a/res/drawable-hdpi-v4/menu_settings.png b/app/src/main/res/drawable-hdpi-v4/menu_settings.png similarity index 100% rename from res/drawable-hdpi-v4/menu_settings.png rename to app/src/main/res/drawable-hdpi-v4/menu_settings.png diff --git a/res/drawable-hdpi-v4/menu_show_watched.png b/app/src/main/res/drawable-hdpi-v4/menu_show_watched.png similarity index 100% rename from res/drawable-hdpi-v4/menu_show_watched.png rename to app/src/main/res/drawable-hdpi-v4/menu_show_watched.png diff --git a/res/drawable-hdpi-v4/menu_song.png b/app/src/main/res/drawable-hdpi-v4/menu_song.png similarity index 100% rename from res/drawable-hdpi-v4/menu_song.png rename to app/src/main/res/drawable-hdpi-v4/menu_song.png diff --git a/res/drawable-hdpi-v4/menu_sort.png b/app/src/main/res/drawable-hdpi-v4/menu_sort.png similarity index 100% rename from res/drawable-hdpi-v4/menu_sort.png rename to app/src/main/res/drawable-hdpi-v4/menu_sort.png diff --git a/res/drawable-hdpi-v4/menu_switch.png b/app/src/main/res/drawable-hdpi-v4/menu_switch.png similarity index 100% rename from res/drawable-hdpi-v4/menu_switch.png rename to app/src/main/res/drawable-hdpi-v4/menu_switch.png diff --git a/res/drawable-hdpi-v4/menu_text_entry.png b/app/src/main/res/drawable-hdpi-v4/menu_text_entry.png similarity index 100% rename from res/drawable-hdpi-v4/menu_text_entry.png rename to app/src/main/res/drawable-hdpi-v4/menu_text_entry.png diff --git a/res/drawable-hdpi-v4/menu_view.png b/app/src/main/res/drawable-hdpi-v4/menu_view.png similarity index 100% rename from res/drawable-hdpi-v4/menu_view.png rename to app/src/main/res/drawable-hdpi-v4/menu_view.png diff --git a/res/drawable-hdpi-v4/menu_xbmc_exit.png b/app/src/main/res/drawable-hdpi-v4/menu_xbmc_exit.png similarity index 100% rename from res/drawable-hdpi-v4/menu_xbmc_exit.png rename to app/src/main/res/drawable-hdpi-v4/menu_xbmc_exit.png diff --git a/res/drawable-hdpi-v4/menu_xbmc_s.png b/app/src/main/res/drawable-hdpi-v4/menu_xbmc_s.png similarity index 100% rename from res/drawable-hdpi-v4/menu_xbmc_s.png rename to app/src/main/res/drawable-hdpi-v4/menu_xbmc_s.png diff --git a/res/drawable-hdpi-v4/now_playing_next_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_next_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_next_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_next_down.png diff --git a/res/drawable-hdpi-v4/now_playing_next_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_next_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_next_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_next_up.png diff --git a/res/drawable-hdpi-v4/now_playing_pause_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_pause_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_pause_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_pause_down.png diff --git a/res/drawable-hdpi-v4/now_playing_pause_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_pause_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_pause_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_pause_up.png diff --git a/res/drawable-hdpi-v4/now_playing_play_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_play_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_play_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_play_down.png diff --git a/res/drawable-hdpi-v4/now_playing_play_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_play_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_play_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_play_up.png diff --git a/res/drawable-hdpi-v4/now_playing_playlist_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_playlist_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_playlist_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_playlist_down.png diff --git a/res/drawable-hdpi-v4/now_playing_playlist_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_playlist_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_playlist_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_playlist_up.png diff --git a/res/drawable-hdpi-v4/now_playing_previous_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_previous_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_previous_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_previous_down.png diff --git a/res/drawable-hdpi-v4/now_playing_previous_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_previous_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_previous_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_previous_up.png diff --git a/res/drawable-hdpi-v4/now_playing_stop_down.png b/app/src/main/res/drawable-hdpi-v4/now_playing_stop_down.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_stop_down.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_stop_down.png diff --git a/res/drawable-hdpi-v4/now_playing_stop_up.png b/app/src/main/res/drawable-hdpi-v4/now_playing_stop_up.png similarity index 100% rename from res/drawable-hdpi-v4/now_playing_stop_up.png rename to app/src/main/res/drawable-hdpi-v4/now_playing_stop_up.png diff --git a/res/drawable-hdpi-v4/pgbar_act.png b/app/src/main/res/drawable-hdpi-v4/pgbar_act.png similarity index 100% rename from res/drawable-hdpi-v4/pgbar_act.png rename to app/src/main/res/drawable-hdpi-v4/pgbar_act.png diff --git a/res/drawable-hdpi-v4/pgbar_thumb.png b/app/src/main/res/drawable-hdpi-v4/pgbar_thumb.png similarity index 100% rename from res/drawable-hdpi-v4/pgbar_thumb.png rename to app/src/main/res/drawable-hdpi-v4/pgbar_thumb.png diff --git a/res/drawable-hdpi-v4/playlist_rightboxes.png b/app/src/main/res/drawable-hdpi-v4/playlist_rightboxes.png similarity index 100% rename from res/drawable-hdpi-v4/playlist_rightboxes.png rename to app/src/main/res/drawable-hdpi-v4/playlist_rightboxes.png diff --git a/res/drawable-hdpi-v4/remote_gest_cursor.png b/app/src/main/res/drawable-hdpi-v4/remote_gest_cursor.png similarity index 100% rename from res/drawable-hdpi-v4/remote_gest_cursor.png rename to app/src/main/res/drawable-hdpi-v4/remote_gest_cursor.png diff --git a/res/drawable-hdpi-v4/remote_xbox__top_left.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox__top_left.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox__top_left.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox__top_left.png diff --git a/res/drawable-hdpi-v4/remote_xbox__top_right.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox__top_right.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox__top_right.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox__top_right.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_back.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_back.xml new file mode 100644 index 00000000..bcaba845 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_back_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_back_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_back_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_back_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_back_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_back_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_back_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_back_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_display.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_display.xml new file mode 100644 index 00000000..72a94953 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_display.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_display_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_display_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_display_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_display_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_display_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_display_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_display_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_display_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_down.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_down.xml new file mode 100644 index 00000000..74d362ee --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_down_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_down_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_down_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_down_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_down_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_down_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_down_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_down_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesture_back_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_back_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesture_back_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_back_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesture_info_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_info_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesture_info_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_info_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesture_menu_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_menu_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesture_menu_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_menu_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesture_title_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_title_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesture_title_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesture_title_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesturezone.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesturezone.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesturezone.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesturezone.png diff --git a/res/drawable-hdpi-v4/remote_xbox_gesturezone_dim.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_gesturezone_dim.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_gesturezone_dim.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_gesturezone_dim.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_images.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_images.xml new file mode 100644 index 00000000..dad4ac16 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_images.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_images_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_images_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_images_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_images_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_images_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_images_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_images_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_images_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_info.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_info.xml new file mode 100644 index 00000000..92f47ee6 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_info.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_info_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_info_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_info_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_info_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_info_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_info_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_info_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_info_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_left.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_left.xml new file mode 100644 index 00000000..cdb13010 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_left.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_left_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_left_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_left_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_left_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_left_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_left_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_left_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_left_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_menu.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_menu.xml new file mode 100644 index 00000000..f7919a97 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_menu.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_menu_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_menu_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_menu_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_menu_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_menu_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_menu_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_menu_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_menu_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_music.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_music.xml new file mode 100644 index 00000000..8d62c0fb --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_music.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_music_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_music_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_music_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_music_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_music_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_music_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_music_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_music_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_next.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_next.xml new file mode 100644 index 00000000..69a29150 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_next.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_next_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_next_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_next_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_next_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_next_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_next_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_next_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_next_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_pause.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_pause.xml new file mode 100644 index 00000000..79b788d1 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_pause.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_pause_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_pause_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_pause_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_pause_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_pause_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_pause_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_pause_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_pause_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_play.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_play.xml new file mode 100644 index 00000000..98362c98 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_play.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_play_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_play_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_play_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_play_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_play_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_play_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_play_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_play_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_previous.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_previous.xml new file mode 100644 index 00000000..bb7b5321 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_previous.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_previous_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_previous_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_previous_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_previous_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_previous_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_previous_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_previous_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_previous_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_right.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_right.xml new file mode 100644 index 00000000..cd052616 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_right.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_right_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_right_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_right_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_right_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_right_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_right_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_right_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_right_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back.xml new file mode 100644 index 00000000..969ba0c6 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_seek_back_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_seek_back_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_back_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward.xml new file mode 100644 index 00000000..bcf23665 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_seek_forward_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_select.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_select.xml new file mode 100644 index 00000000..13de9c66 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_select.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_select_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_select_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_select_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_select_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_select_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_select_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_select_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_select_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_stop.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_stop.xml new file mode 100644 index 00000000..68428b6d --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_stop.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_stop_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_stop_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_stop_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_stop_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_stop_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_stop_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_stop_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_stop_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_title.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_title.xml new file mode 100644 index 00000000..ff070701 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_title.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_title_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_title_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_title_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_title_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_title_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_title_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_title_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_title_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_tv.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_tv.xml new file mode 100644 index 00000000..38333baf --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_tv.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_tv_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_tv_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_tv_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_tv_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_tv_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_tv_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_tv_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_tv_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_up.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_up.xml new file mode 100644 index 00000000..6118eeb3 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_up_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_up_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_up_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_up_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_up_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_up_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_up_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_up_up.png diff --git a/app/src/main/res/drawable-hdpi-v4/remote_xbox_video.xml b/app/src/main/res/drawable-hdpi-v4/remote_xbox_video.xml new file mode 100644 index 00000000..cb79bb03 --- /dev/null +++ b/app/src/main/res/drawable-hdpi-v4/remote_xbox_video.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-hdpi-v4/remote_xbox_video_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_video_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_video_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_video_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_video_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_video_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_video_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_video_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget__top_left.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget__top_left.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget__top_left.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget__top_left.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget__top_right.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget__top_right.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget__top_right.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget__top_right.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_back_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_back_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_back_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_back_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_back_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_back_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_back_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_back_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_display_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_display_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_display_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_display_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_display_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_display_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_display_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_display_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_down_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_down_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_down_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_down_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_down_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_down_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_down_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_down_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_info_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_info_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_info_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_info_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_info_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_info_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_info_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_info_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_left_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_left_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_left_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_left_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_left_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_left_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_left_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_left_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_menu_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_menu_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_menu_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_menu_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_menu_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_menu_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_menu_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_menu_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_next_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_next_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_next_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_next_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_next_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_next_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_next_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_next_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_pause_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_pause_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_pause_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_pause_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_pause_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_pause_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_pause_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_pause_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_play_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_play_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_play_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_play_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_play_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_play_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_play_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_play_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_previous_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_previous_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_previous_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_previous_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_previous_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_previous_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_previous_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_previous_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_right_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_right_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_right_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_right_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_right_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_right_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_right_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_right_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_seek_back_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_seek_back_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_back_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_seek_forward_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_select_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_select_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_select_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_select_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_select_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_select_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_select_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_select_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_stop_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_stop_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_stop_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_stop_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_stop_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_stop_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_stop_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_stop_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_title_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_title_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_title_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_title_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_title_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_title_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_title_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_title_up.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_up_down.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_up_down.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_up_down.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_up_down.png diff --git a/res/drawable-hdpi-v4/remote_xbox_widget_up_up.png b/app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_up_up.png similarity index 100% rename from res/drawable-hdpi-v4/remote_xbox_widget_up_up.png rename to app/src/main/res/drawable-hdpi-v4/remote_xbox_widget_up_up.png diff --git a/res/drawable-hdpi-v4/scrollbar_handle.png b/app/src/main/res/drawable-hdpi-v4/scrollbar_handle.png similarity index 100% rename from res/drawable-hdpi-v4/scrollbar_handle.png rename to app/src/main/res/drawable-hdpi-v4/scrollbar_handle.png diff --git a/res/drawable-hdpi-v4/shiny_black_back.png b/app/src/main/res/drawable-hdpi-v4/shiny_black_back.png similarity index 100% rename from res/drawable-hdpi-v4/shiny_black_back.png rename to app/src/main/res/drawable-hdpi-v4/shiny_black_back.png diff --git a/res/drawable-hdpi-v4/st_actor_off.png b/app/src/main/res/drawable-hdpi-v4/st_actor_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_actor_off.png rename to app/src/main/res/drawable-hdpi-v4/st_actor_off.png diff --git a/res/drawable-hdpi-v4/st_actor_on.png b/app/src/main/res/drawable-hdpi-v4/st_actor_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_actor_on.png rename to app/src/main/res/drawable-hdpi-v4/st_actor_on.png diff --git a/res/drawable-hdpi-v4/st_actor_over.png b/app/src/main/res/drawable-hdpi-v4/st_actor_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_actor_over.png rename to app/src/main/res/drawable-hdpi-v4/st_actor_over.png diff --git a/res/drawable-hdpi-v4/st_album_off.png b/app/src/main/res/drawable-hdpi-v4/st_album_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_album_off.png rename to app/src/main/res/drawable-hdpi-v4/st_album_off.png diff --git a/res/drawable-hdpi-v4/st_album_on.png b/app/src/main/res/drawable-hdpi-v4/st_album_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_album_on.png rename to app/src/main/res/drawable-hdpi-v4/st_album_on.png diff --git a/res/drawable-hdpi-v4/st_album_over.png b/app/src/main/res/drawable-hdpi-v4/st_album_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_album_over.png rename to app/src/main/res/drawable-hdpi-v4/st_album_over.png diff --git a/res/drawable-hdpi-v4/st_artist_off.png b/app/src/main/res/drawable-hdpi-v4/st_artist_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_artist_off.png rename to app/src/main/res/drawable-hdpi-v4/st_artist_off.png diff --git a/res/drawable-hdpi-v4/st_artist_on.png b/app/src/main/res/drawable-hdpi-v4/st_artist_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_artist_on.png rename to app/src/main/res/drawable-hdpi-v4/st_artist_on.png diff --git a/res/drawable-hdpi-v4/st_artist_over.png b/app/src/main/res/drawable-hdpi-v4/st_artist_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_artist_over.png rename to app/src/main/res/drawable-hdpi-v4/st_artist_over.png diff --git a/res/drawable-hdpi-v4/st_background.png b/app/src/main/res/drawable-hdpi-v4/st_background.png similarity index 100% rename from res/drawable-hdpi-v4/st_background.png rename to app/src/main/res/drawable-hdpi-v4/st_background.png diff --git a/res/drawable-hdpi-v4/st_filemode_off.png b/app/src/main/res/drawable-hdpi-v4/st_filemode_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_filemode_off.png rename to app/src/main/res/drawable-hdpi-v4/st_filemode_off.png diff --git a/res/drawable-hdpi-v4/st_filemode_on.png b/app/src/main/res/drawable-hdpi-v4/st_filemode_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_filemode_on.png rename to app/src/main/res/drawable-hdpi-v4/st_filemode_on.png diff --git a/res/drawable-hdpi-v4/st_filemode_over.png b/app/src/main/res/drawable-hdpi-v4/st_filemode_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_filemode_over.png rename to app/src/main/res/drawable-hdpi-v4/st_filemode_over.png diff --git a/res/drawable-hdpi-v4/st_genre_off.png b/app/src/main/res/drawable-hdpi-v4/st_genre_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_genre_off.png rename to app/src/main/res/drawable-hdpi-v4/st_genre_off.png diff --git a/res/drawable-hdpi-v4/st_genre_on.png b/app/src/main/res/drawable-hdpi-v4/st_genre_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_genre_on.png rename to app/src/main/res/drawable-hdpi-v4/st_genre_on.png diff --git a/res/drawable-hdpi-v4/st_genre_over.png b/app/src/main/res/drawable-hdpi-v4/st_genre_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_genre_over.png rename to app/src/main/res/drawable-hdpi-v4/st_genre_over.png diff --git a/res/drawable-hdpi-v4/st_movie_off.png b/app/src/main/res/drawable-hdpi-v4/st_movie_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_movie_off.png rename to app/src/main/res/drawable-hdpi-v4/st_movie_off.png diff --git a/res/drawable-hdpi-v4/st_movie_on.png b/app/src/main/res/drawable-hdpi-v4/st_movie_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_movie_on.png rename to app/src/main/res/drawable-hdpi-v4/st_movie_on.png diff --git a/res/drawable-hdpi-v4/st_movie_over.png b/app/src/main/res/drawable-hdpi-v4/st_movie_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_movie_over.png rename to app/src/main/res/drawable-hdpi-v4/st_movie_over.png diff --git a/res/drawable-hdpi-v4/st_playlist_off.png b/app/src/main/res/drawable-hdpi-v4/st_playlist_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_playlist_off.png rename to app/src/main/res/drawable-hdpi-v4/st_playlist_off.png diff --git a/res/drawable-hdpi-v4/st_playlist_on.png b/app/src/main/res/drawable-hdpi-v4/st_playlist_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_playlist_on.png rename to app/src/main/res/drawable-hdpi-v4/st_playlist_on.png diff --git a/res/drawable-hdpi-v4/st_playlist_over.png b/app/src/main/res/drawable-hdpi-v4/st_playlist_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_playlist_over.png rename to app/src/main/res/drawable-hdpi-v4/st_playlist_over.png diff --git a/res/drawable-hdpi-v4/st_slider.png b/app/src/main/res/drawable-hdpi-v4/st_slider.png similarity index 100% rename from res/drawable-hdpi-v4/st_slider.png rename to app/src/main/res/drawable-hdpi-v4/st_slider.png diff --git a/res/drawable-hdpi-v4/st_song_off.png b/app/src/main/res/drawable-hdpi-v4/st_song_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_song_off.png rename to app/src/main/res/drawable-hdpi-v4/st_song_off.png diff --git a/res/drawable-hdpi-v4/st_song_on.png b/app/src/main/res/drawable-hdpi-v4/st_song_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_song_on.png rename to app/src/main/res/drawable-hdpi-v4/st_song_on.png diff --git a/res/drawable-hdpi-v4/st_song_over.png b/app/src/main/res/drawable-hdpi-v4/st_song_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_song_over.png rename to app/src/main/res/drawable-hdpi-v4/st_song_over.png diff --git a/res/drawable-hdpi-v4/st_tv_off.png b/app/src/main/res/drawable-hdpi-v4/st_tv_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_tv_off.png rename to app/src/main/res/drawable-hdpi-v4/st_tv_off.png diff --git a/res/drawable-hdpi-v4/st_tv_on.png b/app/src/main/res/drawable-hdpi-v4/st_tv_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_tv_on.png rename to app/src/main/res/drawable-hdpi-v4/st_tv_on.png diff --git a/res/drawable-hdpi-v4/st_tv_over.png b/app/src/main/res/drawable-hdpi-v4/st_tv_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_tv_over.png rename to app/src/main/res/drawable-hdpi-v4/st_tv_over.png diff --git a/res/drawable-hdpi-v4/st_va_off.png b/app/src/main/res/drawable-hdpi-v4/st_va_off.png similarity index 100% rename from res/drawable-hdpi-v4/st_va_off.png rename to app/src/main/res/drawable-hdpi-v4/st_va_off.png diff --git a/res/drawable-hdpi-v4/st_va_on.png b/app/src/main/res/drawable-hdpi-v4/st_va_on.png similarity index 100% rename from res/drawable-hdpi-v4/st_va_on.png rename to app/src/main/res/drawable-hdpi-v4/st_va_on.png diff --git a/res/drawable-hdpi-v4/st_va_over.png b/app/src/main/res/drawable-hdpi-v4/st_va_over.png similarity index 100% rename from res/drawable-hdpi-v4/st_va_over.png rename to app/src/main/res/drawable-hdpi-v4/st_va_over.png diff --git a/res/drawable-hdpi-v4/stars_0.png b/app/src/main/res/drawable-hdpi-v4/stars_0.png similarity index 100% rename from res/drawable-hdpi-v4/stars_0.png rename to app/src/main/res/drawable-hdpi-v4/stars_0.png diff --git a/res/drawable-hdpi-v4/stars_1.png b/app/src/main/res/drawable-hdpi-v4/stars_1.png similarity index 100% rename from res/drawable-hdpi-v4/stars_1.png rename to app/src/main/res/drawable-hdpi-v4/stars_1.png diff --git a/res/drawable-hdpi-v4/stars_10.png b/app/src/main/res/drawable-hdpi-v4/stars_10.png similarity index 100% rename from res/drawable-hdpi-v4/stars_10.png rename to app/src/main/res/drawable-hdpi-v4/stars_10.png diff --git a/res/drawable-hdpi-v4/stars_2.png b/app/src/main/res/drawable-hdpi-v4/stars_2.png similarity index 100% rename from res/drawable-hdpi-v4/stars_2.png rename to app/src/main/res/drawable-hdpi-v4/stars_2.png diff --git a/res/drawable-hdpi-v4/stars_3.png b/app/src/main/res/drawable-hdpi-v4/stars_3.png similarity index 100% rename from res/drawable-hdpi-v4/stars_3.png rename to app/src/main/res/drawable-hdpi-v4/stars_3.png diff --git a/res/drawable-hdpi-v4/stars_4.png b/app/src/main/res/drawable-hdpi-v4/stars_4.png similarity index 100% rename from res/drawable-hdpi-v4/stars_4.png rename to app/src/main/res/drawable-hdpi-v4/stars_4.png diff --git a/res/drawable-hdpi-v4/stars_5.png b/app/src/main/res/drawable-hdpi-v4/stars_5.png similarity index 100% rename from res/drawable-hdpi-v4/stars_5.png rename to app/src/main/res/drawable-hdpi-v4/stars_5.png diff --git a/res/drawable-hdpi-v4/stars_6.png b/app/src/main/res/drawable-hdpi-v4/stars_6.png similarity index 100% rename from res/drawable-hdpi-v4/stars_6.png rename to app/src/main/res/drawable-hdpi-v4/stars_6.png diff --git a/res/drawable-hdpi-v4/stars_7.png b/app/src/main/res/drawable-hdpi-v4/stars_7.png similarity index 100% rename from res/drawable-hdpi-v4/stars_7.png rename to app/src/main/res/drawable-hdpi-v4/stars_7.png diff --git a/res/drawable-hdpi-v4/stars_8.png b/app/src/main/res/drawable-hdpi-v4/stars_8.png similarity index 100% rename from res/drawable-hdpi-v4/stars_8.png rename to app/src/main/res/drawable-hdpi-v4/stars_8.png diff --git a/res/drawable-hdpi-v4/stars_9.png b/app/src/main/res/drawable-hdpi-v4/stars_9.png similarity index 100% rename from res/drawable-hdpi-v4/stars_9.png rename to app/src/main/res/drawable-hdpi-v4/stars_9.png diff --git a/res/drawable-hdpi-v4/timeborder.9.png b/app/src/main/res/drawable-hdpi-v4/timeborder.9.png similarity index 100% rename from res/drawable-hdpi-v4/timeborder.9.png rename to app/src/main/res/drawable-hdpi-v4/timeborder.9.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_back_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_back_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_back_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_back_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_back_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_back_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_back_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_back_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_display_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_display_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_display_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_display_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_display_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_display_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_display_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_display_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_down_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_down_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_down_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_down_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_down_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_down_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_down_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_down_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_images_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_images_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_images_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_images_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_images_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_images_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_images_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_images_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_info_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_info_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_info_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_info_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_info_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_info_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_info_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_info_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_left_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_left_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_left_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_left_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_left_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_left_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_left_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_left_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_menu_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_menu_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_menu_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_menu_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_menu_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_menu_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_menu_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_menu_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_music_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_music_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_music_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_music_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_music_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_music_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_music_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_music_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_next_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_next_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_next_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_next_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_next_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_next_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_next_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_next_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_pause_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_pause_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_pause_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_pause_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_pause_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_pause_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_pause_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_pause_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_play_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_play_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_play_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_play_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_play_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_play_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_play_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_play_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_power_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_power_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_power_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_power_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_power_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_power_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_power_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_power_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_previous_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_previous_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_previous_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_previous_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_previous_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_previous_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_previous_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_previous_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_right_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_right_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_right_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_right_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_right_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_right_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_right_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_right_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_seek_back_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_back_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_seek_back_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_back_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_seek_forward_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_select_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_select_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_select_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_select_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_select_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_select_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_select_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_select_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_stop_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_stop_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_stop_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_stop_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_stop_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_stop_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_stop_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_stop_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_title_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_title_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_title_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_title_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_title_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_title_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_title_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_title_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_tv_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_tv_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_tv_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_tv_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_tv_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_tv_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_tv_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_tv_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_up_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_up_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_up_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_up_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_up_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_up_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_up_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_up_up.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_video_down.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_video_down.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_video_down.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_video_down.png diff --git a/res/drawable-land-hdpi-v4/remote_xbox_video_up.png b/app/src/main/res/drawable-land-hdpi-v4/remote_xbox_video_up.png similarity index 100% rename from res/drawable-land-hdpi-v4/remote_xbox_video_up.png rename to app/src/main/res/drawable-land-hdpi-v4/remote_xbox_video_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_back_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_back_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_back_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_back_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_back_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_back_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_back_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_back_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_down_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_down_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_down_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_down_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_down_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_down_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_down_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_down_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_info_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_info_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_info_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_info_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_info_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_info_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_info_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_info_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_left_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_left_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_left_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_left_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_left_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_left_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_left_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_left_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_menu_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_menu_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_menu_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_menu_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_menu_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_menu_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_menu_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_menu_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_next_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_next_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_next_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_next_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_next_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_next_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_next_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_next_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_pause_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_pause_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_pause_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_pause_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_pause_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_pause_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_pause_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_pause_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_play_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_play_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_play_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_play_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_play_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_play_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_play_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_play_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_power_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_power_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_power_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_power_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_power_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_power_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_power_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_power_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_previous_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_previous_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_previous_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_previous_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_previous_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_previous_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_previous_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_previous_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_right_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_right_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_right_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_right_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_right_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_right_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_right_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_right_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_seek_back_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_back_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_seek_back_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_back_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_seek_forward_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_select_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_select_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_select_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_select_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_select_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_select_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_select_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_select_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_stop_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_stop_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_stop_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_stop_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_stop_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_stop_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_stop_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_stop_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_title_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_title_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_title_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_title_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_title_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_title_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_title_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_title_up.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_up_down.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_up_down.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_up_down.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_up_down.png diff --git a/res/drawable-land-ldpi-v4/remote_xbox_up_up.png b/app/src/main/res/drawable-land-ldpi-v4/remote_xbox_up_up.png similarity index 100% rename from res/drawable-land-ldpi-v4/remote_xbox_up_up.png rename to app/src/main/res/drawable-land-ldpi-v4/remote_xbox_up_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_back.xml b/app/src/main/res/drawable-land/remote_xbox_back.xml new file mode 100644 index 00000000..bcaba845 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_back_down.png b/app/src/main/res/drawable-land/remote_xbox_back_down.png similarity index 100% rename from res/drawable-land/remote_xbox_back_down.png rename to app/src/main/res/drawable-land/remote_xbox_back_down.png diff --git a/res/drawable-land/remote_xbox_back_up.png b/app/src/main/res/drawable-land/remote_xbox_back_up.png similarity index 100% rename from res/drawable-land/remote_xbox_back_up.png rename to app/src/main/res/drawable-land/remote_xbox_back_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_display.xml b/app/src/main/res/drawable-land/remote_xbox_display.xml new file mode 100644 index 00000000..72a94953 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_display.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_display_down.png b/app/src/main/res/drawable-land/remote_xbox_display_down.png similarity index 100% rename from res/drawable-land/remote_xbox_display_down.png rename to app/src/main/res/drawable-land/remote_xbox_display_down.png diff --git a/res/drawable-land/remote_xbox_display_up.png b/app/src/main/res/drawable-land/remote_xbox_display_up.png similarity index 100% rename from res/drawable-land/remote_xbox_display_up.png rename to app/src/main/res/drawable-land/remote_xbox_display_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_down.xml b/app/src/main/res/drawable-land/remote_xbox_down.xml new file mode 100644 index 00000000..74d362ee --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_down_down.png b/app/src/main/res/drawable-land/remote_xbox_down_down.png similarity index 100% rename from res/drawable-land/remote_xbox_down_down.png rename to app/src/main/res/drawable-land/remote_xbox_down_down.png diff --git a/res/drawable-land/remote_xbox_down_up.png b/app/src/main/res/drawable-land/remote_xbox_down_up.png similarity index 100% rename from res/drawable-land/remote_xbox_down_up.png rename to app/src/main/res/drawable-land/remote_xbox_down_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_images.xml b/app/src/main/res/drawable-land/remote_xbox_images.xml new file mode 100644 index 00000000..dad4ac16 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_images.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_images_down.png b/app/src/main/res/drawable-land/remote_xbox_images_down.png similarity index 100% rename from res/drawable-land/remote_xbox_images_down.png rename to app/src/main/res/drawable-land/remote_xbox_images_down.png diff --git a/res/drawable-land/remote_xbox_images_up.png b/app/src/main/res/drawable-land/remote_xbox_images_up.png similarity index 100% rename from res/drawable-land/remote_xbox_images_up.png rename to app/src/main/res/drawable-land/remote_xbox_images_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_info.xml b/app/src/main/res/drawable-land/remote_xbox_info.xml new file mode 100644 index 00000000..92f47ee6 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_info.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_info_down.png b/app/src/main/res/drawable-land/remote_xbox_info_down.png similarity index 100% rename from res/drawable-land/remote_xbox_info_down.png rename to app/src/main/res/drawable-land/remote_xbox_info_down.png diff --git a/res/drawable-land/remote_xbox_info_up.png b/app/src/main/res/drawable-land/remote_xbox_info_up.png similarity index 100% rename from res/drawable-land/remote_xbox_info_up.png rename to app/src/main/res/drawable-land/remote_xbox_info_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_left.xml b/app/src/main/res/drawable-land/remote_xbox_left.xml new file mode 100644 index 00000000..cdb13010 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_left.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_left_down.png b/app/src/main/res/drawable-land/remote_xbox_left_down.png similarity index 100% rename from res/drawable-land/remote_xbox_left_down.png rename to app/src/main/res/drawable-land/remote_xbox_left_down.png diff --git a/res/drawable-land/remote_xbox_left_up.png b/app/src/main/res/drawable-land/remote_xbox_left_up.png similarity index 100% rename from res/drawable-land/remote_xbox_left_up.png rename to app/src/main/res/drawable-land/remote_xbox_left_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_menu.xml b/app/src/main/res/drawable-land/remote_xbox_menu.xml new file mode 100644 index 00000000..f7919a97 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_menu.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_menu_down.png b/app/src/main/res/drawable-land/remote_xbox_menu_down.png similarity index 100% rename from res/drawable-land/remote_xbox_menu_down.png rename to app/src/main/res/drawable-land/remote_xbox_menu_down.png diff --git a/res/drawable-land/remote_xbox_menu_up.png b/app/src/main/res/drawable-land/remote_xbox_menu_up.png similarity index 100% rename from res/drawable-land/remote_xbox_menu_up.png rename to app/src/main/res/drawable-land/remote_xbox_menu_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_music.xml b/app/src/main/res/drawable-land/remote_xbox_music.xml new file mode 100644 index 00000000..8d62c0fb --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_music.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_music_down.png b/app/src/main/res/drawable-land/remote_xbox_music_down.png similarity index 100% rename from res/drawable-land/remote_xbox_music_down.png rename to app/src/main/res/drawable-land/remote_xbox_music_down.png diff --git a/res/drawable-land/remote_xbox_music_up.png b/app/src/main/res/drawable-land/remote_xbox_music_up.png similarity index 100% rename from res/drawable-land/remote_xbox_music_up.png rename to app/src/main/res/drawable-land/remote_xbox_music_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_next.xml b/app/src/main/res/drawable-land/remote_xbox_next.xml new file mode 100644 index 00000000..69a29150 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_next.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_next_down.png b/app/src/main/res/drawable-land/remote_xbox_next_down.png similarity index 100% rename from res/drawable-land/remote_xbox_next_down.png rename to app/src/main/res/drawable-land/remote_xbox_next_down.png diff --git a/res/drawable-land/remote_xbox_next_up.png b/app/src/main/res/drawable-land/remote_xbox_next_up.png similarity index 100% rename from res/drawable-land/remote_xbox_next_up.png rename to app/src/main/res/drawable-land/remote_xbox_next_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_pause.xml b/app/src/main/res/drawable-land/remote_xbox_pause.xml new file mode 100644 index 00000000..79b788d1 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_pause.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_pause_down.png b/app/src/main/res/drawable-land/remote_xbox_pause_down.png similarity index 100% rename from res/drawable-land/remote_xbox_pause_down.png rename to app/src/main/res/drawable-land/remote_xbox_pause_down.png diff --git a/res/drawable-land/remote_xbox_pause_up.png b/app/src/main/res/drawable-land/remote_xbox_pause_up.png similarity index 100% rename from res/drawable-land/remote_xbox_pause_up.png rename to app/src/main/res/drawable-land/remote_xbox_pause_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_play.xml b/app/src/main/res/drawable-land/remote_xbox_play.xml new file mode 100644 index 00000000..98362c98 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_play.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_play_down.png b/app/src/main/res/drawable-land/remote_xbox_play_down.png similarity index 100% rename from res/drawable-land/remote_xbox_play_down.png rename to app/src/main/res/drawable-land/remote_xbox_play_down.png diff --git a/res/drawable-land/remote_xbox_play_up.png b/app/src/main/res/drawable-land/remote_xbox_play_up.png similarity index 100% rename from res/drawable-land/remote_xbox_play_up.png rename to app/src/main/res/drawable-land/remote_xbox_play_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_power.xml b/app/src/main/res/drawable-land/remote_xbox_power.xml new file mode 100644 index 00000000..9b6321d0 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_power.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_power_down.png b/app/src/main/res/drawable-land/remote_xbox_power_down.png similarity index 100% rename from res/drawable-land/remote_xbox_power_down.png rename to app/src/main/res/drawable-land/remote_xbox_power_down.png diff --git a/res/drawable-land/remote_xbox_power_up.png b/app/src/main/res/drawable-land/remote_xbox_power_up.png similarity index 100% rename from res/drawable-land/remote_xbox_power_up.png rename to app/src/main/res/drawable-land/remote_xbox_power_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_previous.xml b/app/src/main/res/drawable-land/remote_xbox_previous.xml new file mode 100644 index 00000000..bb7b5321 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_previous.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_previous_down.png b/app/src/main/res/drawable-land/remote_xbox_previous_down.png similarity index 100% rename from res/drawable-land/remote_xbox_previous_down.png rename to app/src/main/res/drawable-land/remote_xbox_previous_down.png diff --git a/res/drawable-land/remote_xbox_previous_up.png b/app/src/main/res/drawable-land/remote_xbox_previous_up.png similarity index 100% rename from res/drawable-land/remote_xbox_previous_up.png rename to app/src/main/res/drawable-land/remote_xbox_previous_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_right.xml b/app/src/main/res/drawable-land/remote_xbox_right.xml new file mode 100644 index 00000000..cd052616 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_right.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_right_down.png b/app/src/main/res/drawable-land/remote_xbox_right_down.png similarity index 100% rename from res/drawable-land/remote_xbox_right_down.png rename to app/src/main/res/drawable-land/remote_xbox_right_down.png diff --git a/res/drawable-land/remote_xbox_right_up.png b/app/src/main/res/drawable-land/remote_xbox_right_up.png similarity index 100% rename from res/drawable-land/remote_xbox_right_up.png rename to app/src/main/res/drawable-land/remote_xbox_right_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_seek_back.xml b/app/src/main/res/drawable-land/remote_xbox_seek_back.xml new file mode 100644 index 00000000..969ba0c6 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_seek_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_seek_back_down.png b/app/src/main/res/drawable-land/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable-land/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable-land/remote_xbox_seek_back_down.png diff --git a/res/drawable-land/remote_xbox_seek_back_up.png b/app/src/main/res/drawable-land/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable-land/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable-land/remote_xbox_seek_back_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_seek_forward.xml b/app/src/main/res/drawable-land/remote_xbox_seek_forward.xml new file mode 100644 index 00000000..bcf23665 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_seek_forward.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable-land/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable-land/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable-land/remote_xbox_seek_forward_down.png diff --git a/res/drawable-land/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable-land/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable-land/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable-land/remote_xbox_seek_forward_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_select.xml b/app/src/main/res/drawable-land/remote_xbox_select.xml new file mode 100644 index 00000000..13de9c66 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_select.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_select_down.png b/app/src/main/res/drawable-land/remote_xbox_select_down.png similarity index 100% rename from res/drawable-land/remote_xbox_select_down.png rename to app/src/main/res/drawable-land/remote_xbox_select_down.png diff --git a/res/drawable-land/remote_xbox_select_up.png b/app/src/main/res/drawable-land/remote_xbox_select_up.png similarity index 100% rename from res/drawable-land/remote_xbox_select_up.png rename to app/src/main/res/drawable-land/remote_xbox_select_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_stop.xml b/app/src/main/res/drawable-land/remote_xbox_stop.xml new file mode 100644 index 00000000..68428b6d --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_stop.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_stop_down.png b/app/src/main/res/drawable-land/remote_xbox_stop_down.png similarity index 100% rename from res/drawable-land/remote_xbox_stop_down.png rename to app/src/main/res/drawable-land/remote_xbox_stop_down.png diff --git a/res/drawable-land/remote_xbox_stop_up.png b/app/src/main/res/drawable-land/remote_xbox_stop_up.png similarity index 100% rename from res/drawable-land/remote_xbox_stop_up.png rename to app/src/main/res/drawable-land/remote_xbox_stop_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_title.xml b/app/src/main/res/drawable-land/remote_xbox_title.xml new file mode 100644 index 00000000..ff070701 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_title.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_title_down.png b/app/src/main/res/drawable-land/remote_xbox_title_down.png similarity index 100% rename from res/drawable-land/remote_xbox_title_down.png rename to app/src/main/res/drawable-land/remote_xbox_title_down.png diff --git a/res/drawable-land/remote_xbox_title_up.png b/app/src/main/res/drawable-land/remote_xbox_title_up.png similarity index 100% rename from res/drawable-land/remote_xbox_title_up.png rename to app/src/main/res/drawable-land/remote_xbox_title_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_tv.xml b/app/src/main/res/drawable-land/remote_xbox_tv.xml new file mode 100644 index 00000000..38333baf --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_tv.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_tv_down.png b/app/src/main/res/drawable-land/remote_xbox_tv_down.png similarity index 100% rename from res/drawable-land/remote_xbox_tv_down.png rename to app/src/main/res/drawable-land/remote_xbox_tv_down.png diff --git a/res/drawable-land/remote_xbox_tv_up.png b/app/src/main/res/drawable-land/remote_xbox_tv_up.png similarity index 100% rename from res/drawable-land/remote_xbox_tv_up.png rename to app/src/main/res/drawable-land/remote_xbox_tv_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_up.xml b/app/src/main/res/drawable-land/remote_xbox_up.xml new file mode 100644 index 00000000..6118eeb3 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_up_down.png b/app/src/main/res/drawable-land/remote_xbox_up_down.png similarity index 100% rename from res/drawable-land/remote_xbox_up_down.png rename to app/src/main/res/drawable-land/remote_xbox_up_down.png diff --git a/res/drawable-land/remote_xbox_up_up.png b/app/src/main/res/drawable-land/remote_xbox_up_up.png similarity index 100% rename from res/drawable-land/remote_xbox_up_up.png rename to app/src/main/res/drawable-land/remote_xbox_up_up.png diff --git a/app/src/main/res/drawable-land/remote_xbox_video.xml b/app/src/main/res/drawable-land/remote_xbox_video.xml new file mode 100644 index 00000000..cb79bb03 --- /dev/null +++ b/app/src/main/res/drawable-land/remote_xbox_video.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable-land/remote_xbox_video_down.png b/app/src/main/res/drawable-land/remote_xbox_video_down.png similarity index 100% rename from res/drawable-land/remote_xbox_video_down.png rename to app/src/main/res/drawable-land/remote_xbox_video_down.png diff --git a/res/drawable-land/remote_xbox_video_up.png b/app/src/main/res/drawable-land/remote_xbox_video_up.png similarity index 100% rename from res/drawable-land/remote_xbox_video_up.png rename to app/src/main/res/drawable-land/remote_xbox_video_up.png diff --git a/res/drawable-ldpi-v4/remote_gest_cursor.png b/app/src/main/res/drawable-ldpi-v4/remote_gest_cursor.png similarity index 100% rename from res/drawable-ldpi-v4/remote_gest_cursor.png rename to app/src/main/res/drawable-ldpi-v4/remote_gest_cursor.png diff --git a/res/drawable-ldpi-v4/remote_xbox__top_left.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox__top_left.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox__top_left.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox__top_left.png diff --git a/res/drawable-ldpi-v4/remote_xbox__top_right.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox__top_right.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox__top_right.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox__top_right.png diff --git a/res/drawable-ldpi-v4/remote_xbox_back_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_back_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_back_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_back_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_back_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_back_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_back_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_back_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_display_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_display_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_display_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_display_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_display_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_display_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_display_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_display_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_down_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_down_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_down_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_down_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_down_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_down_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_down_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_down_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesture_back_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_back_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesture_back_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_back_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesture_info_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_info_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesture_info_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_info_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesture_menu_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_menu_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesture_menu_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_menu_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesture_title_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_title_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesture_title_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesture_title_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesturezone.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesturezone.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesturezone.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesturezone.png diff --git a/res/drawable-ldpi-v4/remote_xbox_gesturezone_dim.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_gesturezone_dim.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_gesturezone_dim.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_gesturezone_dim.png diff --git a/res/drawable-ldpi-v4/remote_xbox_info_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_info_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_info_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_info_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_info_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_info_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_info_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_info_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_left_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_left_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_left_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_left_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_left_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_left_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_left_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_left_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_menu_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_menu_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_menu_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_menu_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_menu_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_menu_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_menu_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_menu_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_next_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_next_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_next_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_next_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_next_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_next_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_next_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_next_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_pause_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_pause_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_pause_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_pause_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_pause_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_pause_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_pause_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_pause_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_play_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_play_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_play_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_play_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_play_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_play_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_play_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_play_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_previous_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_previous_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_previous_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_previous_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_previous_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_previous_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_previous_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_previous_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_right_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_right_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_right_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_right_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_right_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_right_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_right_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_right_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_seek_back_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_back_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_seek_back_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_back_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_forward_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_seek_forward_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_select_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_select_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_select_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_select_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_select_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_select_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_select_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_select_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_stop_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_stop_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_stop_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_stop_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_stop_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_stop_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_stop_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_stop_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_title_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_title_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_title_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_title_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_title_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_title_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_title_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_title_up.png diff --git a/res/drawable-ldpi-v4/remote_xbox_up_down.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_up_down.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_up_down.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_up_down.png diff --git a/res/drawable-ldpi-v4/remote_xbox_up_up.png b/app/src/main/res/drawable-ldpi-v4/remote_xbox_up_up.png similarity index 100% rename from res/drawable-ldpi-v4/remote_xbox_up_up.png rename to app/src/main/res/drawable-ldpi-v4/remote_xbox_up_up.png diff --git a/res/drawable/about_back.png b/app/src/main/res/drawable/about_back.png similarity index 100% rename from res/drawable/about_back.png rename to app/src/main/res/drawable/about_back.png diff --git a/res/drawable/bottom_controls_background.png b/app/src/main/res/drawable/bottom_controls_background.png similarity index 100% rename from res/drawable/bottom_controls_background.png rename to app/src/main/res/drawable/bottom_controls_background.png diff --git a/app/src/main/res/drawable/bottom_logo.xml b/app/src/main/res/drawable/bottom_logo.xml new file mode 100644 index 00000000..0af49a44 --- /dev/null +++ b/app/src/main/res/drawable/bottom_logo.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/bottom_logo_down.png b/app/src/main/res/drawable/bottom_logo_down.png similarity index 100% rename from res/drawable/bottom_logo_down.png rename to app/src/main/res/drawable/bottom_logo_down.png diff --git a/res/drawable/bottom_logo_up.png b/app/src/main/res/drawable/bottom_logo_up.png similarity index 100% rename from res/drawable/bottom_logo_up.png rename to app/src/main/res/drawable/bottom_logo_up.png diff --git a/app/src/main/res/drawable/bottom_text.xml b/app/src/main/res/drawable/bottom_text.xml new file mode 100644 index 00000000..0548e88c --- /dev/null +++ b/app/src/main/res/drawable/bottom_text.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/bottom_text_down.9.png b/app/src/main/res/drawable/bottom_text_down.9.png similarity index 100% rename from res/drawable/bottom_text_down.9.png rename to app/src/main/res/drawable/bottom_text_down.9.png diff --git a/res/drawable/bottom_text_up.9.png b/app/src/main/res/drawable/bottom_text_up.9.png similarity index 100% rename from res/drawable/bottom_text_up.9.png rename to app/src/main/res/drawable/bottom_text_up.9.png diff --git a/res/drawable/bottombar_bg.png b/app/src/main/res/drawable/bottombar_bg.png similarity index 100% rename from res/drawable/bottombar_bg.png rename to app/src/main/res/drawable/bottombar_bg.png diff --git a/res/drawable/bubble_add.png b/app/src/main/res/drawable/bubble_add.png similarity index 100% rename from res/drawable/bubble_add.png rename to app/src/main/res/drawable/bubble_add.png diff --git a/app/src/main/res/drawable/bubble_del.xml b/app/src/main/res/drawable/bubble_del.xml new file mode 100644 index 00000000..b820f682 --- /dev/null +++ b/app/src/main/res/drawable/bubble_del.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/bubble_del_down.png b/app/src/main/res/drawable/bubble_del_down.png similarity index 100% rename from res/drawable/bubble_del_down.png rename to app/src/main/res/drawable/bubble_del_down.png diff --git a/res/drawable/bubble_del_up.png b/app/src/main/res/drawable/bubble_del_up.png similarity index 100% rename from res/drawable/bubble_del_up.png rename to app/src/main/res/drawable/bubble_del_up.png diff --git a/res/drawable/check_mark.png b/app/src/main/res/drawable/check_mark.png similarity index 100% rename from res/drawable/check_mark.png rename to app/src/main/res/drawable/check_mark.png diff --git a/res/drawable/coverbox_back.png b/app/src/main/res/drawable/coverbox_back.png similarity index 100% rename from res/drawable/coverbox_back.png rename to app/src/main/res/drawable/coverbox_back.png diff --git a/res/drawable/default_album.png b/app/src/main/res/drawable/default_album.png similarity index 100% rename from res/drawable/default_album.png rename to app/src/main/res/drawable/default_album.png diff --git a/res/drawable/default_jewel.png b/app/src/main/res/drawable/default_jewel.png similarity index 100% rename from res/drawable/default_jewel.png rename to app/src/main/res/drawable/default_jewel.png diff --git a/res/drawable/default_poster.png b/app/src/main/res/drawable/default_poster.png similarity index 100% rename from res/drawable/default_poster.png rename to app/src/main/res/drawable/default_poster.png diff --git a/res/drawable/default_season.png b/app/src/main/res/drawable/default_season.png similarity index 100% rename from res/drawable/default_season.png rename to app/src/main/res/drawable/default_season.png diff --git a/res/drawable/default_tvshow.png b/app/src/main/res/drawable/default_tvshow.png similarity index 100% rename from res/drawable/default_tvshow.png rename to app/src/main/res/drawable/default_tvshow.png diff --git a/res/drawable/dialog_full_dark.9.png b/app/src/main/res/drawable/dialog_full_dark.9.png similarity index 100% rename from res/drawable/dialog_full_dark.9.png rename to app/src/main/res/drawable/dialog_full_dark.9.png diff --git a/res/drawable/home_bottom.9.png b/app/src/main/res/drawable/home_bottom.9.png similarity index 100% rename from res/drawable/home_bottom.9.png rename to app/src/main/res/drawable/home_bottom.9.png diff --git a/res/drawable/icon.png b/app/src/main/res/drawable/icon.png similarity index 100% rename from res/drawable/icon.png rename to app/src/main/res/drawable/icon.png diff --git a/res/drawable/icon_album.png b/app/src/main/res/drawable/icon_album.png similarity index 100% rename from res/drawable/icon_album.png rename to app/src/main/res/drawable/icon_album.png diff --git a/res/drawable/icon_album_big.png b/app/src/main/res/drawable/icon_album_big.png similarity index 100% rename from res/drawable/icon_album_big.png rename to app/src/main/res/drawable/icon_album_big.png diff --git a/res/drawable/icon_album_dark.png b/app/src/main/res/drawable/icon_album_dark.png similarity index 100% rename from res/drawable/icon_album_dark.png rename to app/src/main/res/drawable/icon_album_dark.png diff --git a/res/drawable/icon_album_dark_big.png b/app/src/main/res/drawable/icon_album_dark_big.png similarity index 100% rename from res/drawable/icon_album_dark_big.png rename to app/src/main/res/drawable/icon_album_dark_big.png diff --git a/res/drawable/icon_artist.png b/app/src/main/res/drawable/icon_artist.png similarity index 100% rename from res/drawable/icon_artist.png rename to app/src/main/res/drawable/icon_artist.png diff --git a/res/drawable/icon_artist_dark.png b/app/src/main/res/drawable/icon_artist_dark.png similarity index 100% rename from res/drawable/icon_artist_dark.png rename to app/src/main/res/drawable/icon_artist_dark.png diff --git a/res/drawable/icon_file.png b/app/src/main/res/drawable/icon_file.png similarity index 100% rename from res/drawable/icon_file.png rename to app/src/main/res/drawable/icon_file.png diff --git a/res/drawable/icon_folder.png b/app/src/main/res/drawable/icon_folder.png similarity index 100% rename from res/drawable/icon_folder.png rename to app/src/main/res/drawable/icon_folder.png diff --git a/res/drawable/icon_folder_dark.png b/app/src/main/res/drawable/icon_folder_dark.png similarity index 100% rename from res/drawable/icon_folder_dark.png rename to app/src/main/res/drawable/icon_folder_dark.png diff --git a/res/drawable/icon_genre.png b/app/src/main/res/drawable/icon_genre.png similarity index 100% rename from res/drawable/icon_genre.png rename to app/src/main/res/drawable/icon_genre.png diff --git a/res/drawable/icon_genre_dark.png b/app/src/main/res/drawable/icon_genre_dark.png similarity index 100% rename from res/drawable/icon_genre_dark.png rename to app/src/main/res/drawable/icon_genre_dark.png diff --git a/res/drawable/icon_home_movie.png b/app/src/main/res/drawable/icon_home_movie.png similarity index 100% rename from res/drawable/icon_home_movie.png rename to app/src/main/res/drawable/icon_home_movie.png diff --git a/res/drawable/icon_home_music.png b/app/src/main/res/drawable/icon_home_music.png similarity index 100% rename from res/drawable/icon_home_music.png rename to app/src/main/res/drawable/icon_home_music.png diff --git a/res/drawable/icon_home_picture.png b/app/src/main/res/drawable/icon_home_picture.png similarity index 100% rename from res/drawable/icon_home_picture.png rename to app/src/main/res/drawable/icon_home_picture.png diff --git a/res/drawable/icon_home_playing.png b/app/src/main/res/drawable/icon_home_playing.png similarity index 100% rename from res/drawable/icon_home_playing.png rename to app/src/main/res/drawable/icon_home_playing.png diff --git a/res/drawable/icon_home_power.png b/app/src/main/res/drawable/icon_home_power.png similarity index 100% rename from res/drawable/icon_home_power.png rename to app/src/main/res/drawable/icon_home_power.png diff --git a/res/drawable/icon_home_reconnect.png b/app/src/main/res/drawable/icon_home_reconnect.png similarity index 100% rename from res/drawable/icon_home_reconnect.png rename to app/src/main/res/drawable/icon_home_reconnect.png diff --git a/res/drawable/icon_home_remote.png b/app/src/main/res/drawable/icon_home_remote.png similarity index 100% rename from res/drawable/icon_home_remote.png rename to app/src/main/res/drawable/icon_home_remote.png diff --git a/res/drawable/icon_home_tv.png b/app/src/main/res/drawable/icon_home_tv.png similarity index 100% rename from res/drawable/icon_home_tv.png rename to app/src/main/res/drawable/icon_home_tv.png diff --git a/res/drawable/icon_home_voice.png b/app/src/main/res/drawable/icon_home_voice.png similarity index 100% rename from res/drawable/icon_home_voice.png rename to app/src/main/res/drawable/icon_home_voice.png diff --git a/res/drawable/icon_lastfm.png b/app/src/main/res/drawable/icon_lastfm.png similarity index 100% rename from res/drawable/icon_lastfm.png rename to app/src/main/res/drawable/icon_lastfm.png diff --git a/res/drawable/icon_movie_dark.png b/app/src/main/res/drawable/icon_movie_dark.png similarity index 100% rename from res/drawable/icon_movie_dark.png rename to app/src/main/res/drawable/icon_movie_dark.png diff --git a/res/drawable/icon_picture.png b/app/src/main/res/drawable/icon_picture.png similarity index 100% rename from res/drawable/icon_picture.png rename to app/src/main/res/drawable/icon_picture.png diff --git a/res/drawable/icon_play.png b/app/src/main/res/drawable/icon_play.png similarity index 100% rename from res/drawable/icon_play.png rename to app/src/main/res/drawable/icon_play.png diff --git a/res/drawable/icon_playing.png b/app/src/main/res/drawable/icon_playing.png similarity index 100% rename from res/drawable/icon_playing.png rename to app/src/main/res/drawable/icon_playing.png diff --git a/res/drawable/icon_playlist_dark.png b/app/src/main/res/drawable/icon_playlist_dark.png similarity index 100% rename from res/drawable/icon_playlist_dark.png rename to app/src/main/res/drawable/icon_playlist_dark.png diff --git a/res/drawable/icon_shoutcast.png b/app/src/main/res/drawable/icon_shoutcast.png similarity index 100% rename from res/drawable/icon_shoutcast.png rename to app/src/main/res/drawable/icon_shoutcast.png diff --git a/res/drawable/icon_song.png b/app/src/main/res/drawable/icon_song.png similarity index 100% rename from res/drawable/icon_song.png rename to app/src/main/res/drawable/icon_song.png diff --git a/res/drawable/icon_song_dark.png b/app/src/main/res/drawable/icon_song_dark.png similarity index 100% rename from res/drawable/icon_song_dark.png rename to app/src/main/res/drawable/icon_song_dark.png diff --git a/res/drawable/icon_song_light.png b/app/src/main/res/drawable/icon_song_light.png similarity index 100% rename from res/drawable/icon_song_light.png rename to app/src/main/res/drawable/icon_song_light.png diff --git a/res/drawable/icon_va_dark.png b/app/src/main/res/drawable/icon_va_dark.png similarity index 100% rename from res/drawable/icon_va_dark.png rename to app/src/main/res/drawable/icon_va_dark.png diff --git a/res/drawable/icon_video.png b/app/src/main/res/drawable/icon_video.png similarity index 100% rename from res/drawable/icon_video.png rename to app/src/main/res/drawable/icon_video.png diff --git a/res/drawable/icon_video_light.png b/app/src/main/res/drawable/icon_video_light.png similarity index 100% rename from res/drawable/icon_video_light.png rename to app/src/main/res/drawable/icon_video_light.png diff --git a/res/drawable/icon_zip.png b/app/src/main/res/drawable/icon_zip.png similarity index 100% rename from res/drawable/icon_zip.png rename to app/src/main/res/drawable/icon_zip.png diff --git a/res/drawable/jewel_cd.9.png b/app/src/main/res/drawable/jewel_cd.9.png similarity index 100% rename from res/drawable/jewel_cd.9.png rename to app/src/main/res/drawable/jewel_cd.9.png diff --git a/res/drawable/jewel_dvd.9.png b/app/src/main/res/drawable/jewel_dvd.9.png similarity index 100% rename from res/drawable/jewel_dvd.9.png rename to app/src/main/res/drawable/jewel_dvd.9.png diff --git a/res/drawable/jewel_tv.9.png b/app/src/main/res/drawable/jewel_tv.9.png similarity index 100% rename from res/drawable/jewel_tv.9.png rename to app/src/main/res/drawable/jewel_tv.9.png diff --git a/res/drawable/layout_top_bar.9.png b/app/src/main/res/drawable/layout_top_bar.9.png similarity index 100% rename from res/drawable/layout_top_bar.9.png rename to app/src/main/res/drawable/layout_top_bar.9.png diff --git a/app/src/main/res/drawable/listitem_bg.xml b/app/src/main/res/drawable/listitem_bg.xml new file mode 100644 index 00000000..a5bafd17 --- /dev/null +++ b/app/src/main/res/drawable/listitem_bg.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/listitem_bottom_rounded.9.png b/app/src/main/res/drawable/listitem_bottom_rounded.9.png similarity index 100% rename from res/drawable/listitem_bottom_rounded.9.png rename to app/src/main/res/drawable/listitem_bottom_rounded.9.png diff --git a/app/src/main/res/drawable/listitem_subtitle.xml b/app/src/main/res/drawable/listitem_subtitle.xml new file mode 100644 index 00000000..753504bd --- /dev/null +++ b/app/src/main/res/drawable/listitem_subtitle.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/listitem_title.xml b/app/src/main/res/drawable/listitem_title.xml new file mode 100644 index 00000000..71bbb3ca --- /dev/null +++ b/app/src/main/res/drawable/listitem_title.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/menu_about.png b/app/src/main/res/drawable/menu_about.png similarity index 100% rename from res/drawable/menu_about.png rename to app/src/main/res/drawable/menu_about.png diff --git a/res/drawable/menu_add_host.png b/app/src/main/res/drawable/menu_add_host.png similarity index 100% rename from res/drawable/menu_add_host.png rename to app/src/main/res/drawable/menu_add_host.png diff --git a/res/drawable/menu_album.png b/app/src/main/res/drawable/menu_album.png similarity index 100% rename from res/drawable/menu_album.png rename to app/src/main/res/drawable/menu_album.png diff --git a/res/drawable/menu_download.png b/app/src/main/res/drawable/menu_download.png similarity index 100% rename from res/drawable/menu_download.png rename to app/src/main/res/drawable/menu_download.png diff --git a/res/drawable/menu_exit.png b/app/src/main/res/drawable/menu_exit.png similarity index 100% rename from res/drawable/menu_exit.png rename to app/src/main/res/drawable/menu_exit.png diff --git a/res/drawable/menu_gesture_mode.png b/app/src/main/res/drawable/menu_gesture_mode.png similarity index 100% rename from res/drawable/menu_gesture_mode.png rename to app/src/main/res/drawable/menu_gesture_mode.png diff --git a/res/drawable/menu_hide_watched.png b/app/src/main/res/drawable/menu_hide_watched.png similarity index 100% rename from res/drawable/menu_hide_watched.png rename to app/src/main/res/drawable/menu_hide_watched.png diff --git a/res/drawable/menu_nowplaying.png b/app/src/main/res/drawable/menu_nowplaying.png similarity index 100% rename from res/drawable/menu_nowplaying.png rename to app/src/main/res/drawable/menu_nowplaying.png diff --git a/res/drawable/menu_qr_code.png b/app/src/main/res/drawable/menu_qr_code.png similarity index 100% rename from res/drawable/menu_qr_code.png rename to app/src/main/res/drawable/menu_qr_code.png diff --git a/res/drawable/menu_refresh.png b/app/src/main/res/drawable/menu_refresh.png similarity index 100% rename from res/drawable/menu_refresh.png rename to app/src/main/res/drawable/menu_refresh.png diff --git a/res/drawable/menu_remote.png b/app/src/main/res/drawable/menu_remote.png similarity index 100% rename from res/drawable/menu_remote.png rename to app/src/main/res/drawable/menu_remote.png diff --git a/res/drawable/menu_settings.png b/app/src/main/res/drawable/menu_settings.png similarity index 100% rename from res/drawable/menu_settings.png rename to app/src/main/res/drawable/menu_settings.png diff --git a/res/drawable/menu_show_watched.png b/app/src/main/res/drawable/menu_show_watched.png similarity index 100% rename from res/drawable/menu_show_watched.png rename to app/src/main/res/drawable/menu_show_watched.png diff --git a/res/drawable/menu_song.png b/app/src/main/res/drawable/menu_song.png similarity index 100% rename from res/drawable/menu_song.png rename to app/src/main/res/drawable/menu_song.png diff --git a/res/drawable/menu_sort.png b/app/src/main/res/drawable/menu_sort.png similarity index 100% rename from res/drawable/menu_sort.png rename to app/src/main/res/drawable/menu_sort.png diff --git a/res/drawable/menu_switch.png b/app/src/main/res/drawable/menu_switch.png similarity index 100% rename from res/drawable/menu_switch.png rename to app/src/main/res/drawable/menu_switch.png diff --git a/res/drawable/menu_text_entry.png b/app/src/main/res/drawable/menu_text_entry.png similarity index 100% rename from res/drawable/menu_text_entry.png rename to app/src/main/res/drawable/menu_text_entry.png diff --git a/res/drawable/menu_view.png b/app/src/main/res/drawable/menu_view.png similarity index 100% rename from res/drawable/menu_view.png rename to app/src/main/res/drawable/menu_view.png diff --git a/res/drawable/menu_xbmc_exit.png b/app/src/main/res/drawable/menu_xbmc_exit.png similarity index 100% rename from res/drawable/menu_xbmc_exit.png rename to app/src/main/res/drawable/menu_xbmc_exit.png diff --git a/res/drawable/menu_xbmc_s.png b/app/src/main/res/drawable/menu_xbmc_s.png similarity index 100% rename from res/drawable/menu_xbmc_s.png rename to app/src/main/res/drawable/menu_xbmc_s.png diff --git a/res/drawable/nocover.png b/app/src/main/res/drawable/nocover.png similarity index 100% rename from res/drawable/nocover.png rename to app/src/main/res/drawable/nocover.png diff --git a/res/drawable/notif_pause.png b/app/src/main/res/drawable/notif_pause.png similarity index 100% rename from res/drawable/notif_pause.png rename to app/src/main/res/drawable/notif_pause.png diff --git a/res/drawable/notif_pic.png b/app/src/main/res/drawable/notif_pic.png similarity index 100% rename from res/drawable/notif_pic.png rename to app/src/main/res/drawable/notif_pic.png diff --git a/res/drawable/notif_play.png b/app/src/main/res/drawable/notif_play.png similarity index 100% rename from res/drawable/notif_play.png rename to app/src/main/res/drawable/notif_play.png diff --git a/app/src/main/res/drawable/now_playing_next.xml b/app/src/main/res/drawable/now_playing_next.xml new file mode 100644 index 00000000..f2385144 --- /dev/null +++ b/app/src/main/res/drawable/now_playing_next.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_next_down.png b/app/src/main/res/drawable/now_playing_next_down.png similarity index 100% rename from res/drawable/now_playing_next_down.png rename to app/src/main/res/drawable/now_playing_next_down.png diff --git a/res/drawable/now_playing_next_up.png b/app/src/main/res/drawable/now_playing_next_up.png similarity index 100% rename from res/drawable/now_playing_next_up.png rename to app/src/main/res/drawable/now_playing_next_up.png diff --git a/app/src/main/res/drawable/now_playing_pause.xml b/app/src/main/res/drawable/now_playing_pause.xml new file mode 100644 index 00000000..7363e6dc --- /dev/null +++ b/app/src/main/res/drawable/now_playing_pause.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_pause_down.png b/app/src/main/res/drawable/now_playing_pause_down.png similarity index 100% rename from res/drawable/now_playing_pause_down.png rename to app/src/main/res/drawable/now_playing_pause_down.png diff --git a/res/drawable/now_playing_pause_up.png b/app/src/main/res/drawable/now_playing_pause_up.png similarity index 100% rename from res/drawable/now_playing_pause_up.png rename to app/src/main/res/drawable/now_playing_pause_up.png diff --git a/app/src/main/res/drawable/now_playing_play.xml b/app/src/main/res/drawable/now_playing_play.xml new file mode 100644 index 00000000..883bd984 --- /dev/null +++ b/app/src/main/res/drawable/now_playing_play.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_play_down.png b/app/src/main/res/drawable/now_playing_play_down.png similarity index 100% rename from res/drawable/now_playing_play_down.png rename to app/src/main/res/drawable/now_playing_play_down.png diff --git a/res/drawable/now_playing_play_up.png b/app/src/main/res/drawable/now_playing_play_up.png similarity index 100% rename from res/drawable/now_playing_play_up.png rename to app/src/main/res/drawable/now_playing_play_up.png diff --git a/app/src/main/res/drawable/now_playing_playlist.xml b/app/src/main/res/drawable/now_playing_playlist.xml new file mode 100644 index 00000000..85d23569 --- /dev/null +++ b/app/src/main/res/drawable/now_playing_playlist.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_playlist_down.png b/app/src/main/res/drawable/now_playing_playlist_down.png similarity index 100% rename from res/drawable/now_playing_playlist_down.png rename to app/src/main/res/drawable/now_playing_playlist_down.png diff --git a/res/drawable/now_playing_playlist_up.png b/app/src/main/res/drawable/now_playing_playlist_up.png similarity index 100% rename from res/drawable/now_playing_playlist_up.png rename to app/src/main/res/drawable/now_playing_playlist_up.png diff --git a/app/src/main/res/drawable/now_playing_previous.xml b/app/src/main/res/drawable/now_playing_previous.xml new file mode 100644 index 00000000..8ab123e2 --- /dev/null +++ b/app/src/main/res/drawable/now_playing_previous.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_previous_down.png b/app/src/main/res/drawable/now_playing_previous_down.png similarity index 100% rename from res/drawable/now_playing_previous_down.png rename to app/src/main/res/drawable/now_playing_previous_down.png diff --git a/res/drawable/now_playing_previous_up.png b/app/src/main/res/drawable/now_playing_previous_up.png similarity index 100% rename from res/drawable/now_playing_previous_up.png rename to app/src/main/res/drawable/now_playing_previous_up.png diff --git a/app/src/main/res/drawable/now_playing_stop.xml b/app/src/main/res/drawable/now_playing_stop.xml new file mode 100644 index 00000000..4924c1f0 --- /dev/null +++ b/app/src/main/res/drawable/now_playing_stop.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/now_playing_stop_down.png b/app/src/main/res/drawable/now_playing_stop_down.png similarity index 100% rename from res/drawable/now_playing_stop_down.png rename to app/src/main/res/drawable/now_playing_stop_down.png diff --git a/res/drawable/now_playing_stop_up.png b/app/src/main/res/drawable/now_playing_stop_up.png similarity index 100% rename from res/drawable/now_playing_stop_up.png rename to app/src/main/res/drawable/now_playing_stop_up.png diff --git a/res/drawable/person.png b/app/src/main/res/drawable/person.png similarity index 100% rename from res/drawable/person.png rename to app/src/main/res/drawable/person.png diff --git a/res/drawable/person_black_small.png b/app/src/main/res/drawable/person_black_small.png similarity index 100% rename from res/drawable/person_black_small.png rename to app/src/main/res/drawable/person_black_small.png diff --git a/res/drawable/person_small.png b/app/src/main/res/drawable/person_small.png similarity index 100% rename from res/drawable/person_small.png rename to app/src/main/res/drawable/person_small.png diff --git a/res/drawable/pgbar_act.png b/app/src/main/res/drawable/pgbar_act.png similarity index 100% rename from res/drawable/pgbar_act.png rename to app/src/main/res/drawable/pgbar_act.png diff --git a/res/drawable/pgbar_inact.png b/app/src/main/res/drawable/pgbar_inact.png similarity index 100% rename from res/drawable/pgbar_inact.png rename to app/src/main/res/drawable/pgbar_inact.png diff --git a/res/drawable/pgbar_thumb.png b/app/src/main/res/drawable/pgbar_thumb.png similarity index 100% rename from res/drawable/pgbar_thumb.png rename to app/src/main/res/drawable/pgbar_thumb.png diff --git a/res/drawable/playlist_rightboxes.png b/app/src/main/res/drawable/playlist_rightboxes.png similarity index 100% rename from res/drawable/playlist_rightboxes.png rename to app/src/main/res/drawable/playlist_rightboxes.png diff --git a/res/drawable/poster_big.png b/app/src/main/res/drawable/poster_big.png similarity index 100% rename from res/drawable/poster_big.png rename to app/src/main/res/drawable/poster_big.png diff --git a/res/drawable/progressbar.xml b/app/src/main/res/drawable/progressbar.xml similarity index 59% rename from res/drawable/progressbar.xml rename to app/src/main/res/drawable/progressbar.xml index 74b40ecc..00f9cc77 100644 --- a/res/drawable/progressbar.xml +++ b/app/src/main/res/drawable/progressbar.xml @@ -1,31 +1,36 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/drawable/remote_gest_border_left.png b/app/src/main/res/drawable/remote_gest_border_left.png similarity index 100% rename from res/drawable/remote_gest_border_left.png rename to app/src/main/res/drawable/remote_gest_border_left.png diff --git a/res/drawable/remote_gest_border_right.png b/app/src/main/res/drawable/remote_gest_border_right.png similarity index 100% rename from res/drawable/remote_gest_border_right.png rename to app/src/main/res/drawable/remote_gest_border_right.png diff --git a/res/drawable/remote_gest_cursor.png b/app/src/main/res/drawable/remote_gest_cursor.png similarity index 100% rename from res/drawable/remote_gest_cursor.png rename to app/src/main/res/drawable/remote_gest_cursor.png diff --git a/res/drawable/remote_xbox__top_left.png b/app/src/main/res/drawable/remote_xbox__top_left.png similarity index 100% rename from res/drawable/remote_xbox__top_left.png rename to app/src/main/res/drawable/remote_xbox__top_left.png diff --git a/res/drawable/remote_xbox__top_right.png b/app/src/main/res/drawable/remote_xbox__top_right.png similarity index 100% rename from res/drawable/remote_xbox__top_right.png rename to app/src/main/res/drawable/remote_xbox__top_right.png diff --git a/app/src/main/res/drawable/remote_xbox_back.xml b/app/src/main/res/drawable/remote_xbox_back.xml new file mode 100644 index 00000000..bcaba845 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_back_down.png b/app/src/main/res/drawable/remote_xbox_back_down.png similarity index 100% rename from res/drawable/remote_xbox_back_down.png rename to app/src/main/res/drawable/remote_xbox_back_down.png diff --git a/res/drawable/remote_xbox_back_up.png b/app/src/main/res/drawable/remote_xbox_back_up.png similarity index 100% rename from res/drawable/remote_xbox_back_up.png rename to app/src/main/res/drawable/remote_xbox_back_up.png diff --git a/app/src/main/res/drawable/remote_xbox_display.xml b/app/src/main/res/drawable/remote_xbox_display.xml new file mode 100644 index 00000000..72a94953 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_display.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_display_down.png b/app/src/main/res/drawable/remote_xbox_display_down.png similarity index 100% rename from res/drawable/remote_xbox_display_down.png rename to app/src/main/res/drawable/remote_xbox_display_down.png diff --git a/res/drawable/remote_xbox_display_up.png b/app/src/main/res/drawable/remote_xbox_display_up.png similarity index 100% rename from res/drawable/remote_xbox_display_up.png rename to app/src/main/res/drawable/remote_xbox_display_up.png diff --git a/app/src/main/res/drawable/remote_xbox_down.xml b/app/src/main/res/drawable/remote_xbox_down.xml new file mode 100644 index 00000000..74d362ee --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_down_down.png b/app/src/main/res/drawable/remote_xbox_down_down.png similarity index 100% rename from res/drawable/remote_xbox_down_down.png rename to app/src/main/res/drawable/remote_xbox_down_down.png diff --git a/res/drawable/remote_xbox_down_up.png b/app/src/main/res/drawable/remote_xbox_down_up.png similarity index 100% rename from res/drawable/remote_xbox_down_up.png rename to app/src/main/res/drawable/remote_xbox_down_up.png diff --git a/res/drawable/remote_xbox_gesture_back_down.png b/app/src/main/res/drawable/remote_xbox_gesture_back_down.png similarity index 100% rename from res/drawable/remote_xbox_gesture_back_down.png rename to app/src/main/res/drawable/remote_xbox_gesture_back_down.png diff --git a/res/drawable/remote_xbox_gesture_info_down.png b/app/src/main/res/drawable/remote_xbox_gesture_info_down.png similarity index 100% rename from res/drawable/remote_xbox_gesture_info_down.png rename to app/src/main/res/drawable/remote_xbox_gesture_info_down.png diff --git a/res/drawable/remote_xbox_gesture_menu_down.png b/app/src/main/res/drawable/remote_xbox_gesture_menu_down.png similarity index 100% rename from res/drawable/remote_xbox_gesture_menu_down.png rename to app/src/main/res/drawable/remote_xbox_gesture_menu_down.png diff --git a/res/drawable/remote_xbox_gesture_title_down.png b/app/src/main/res/drawable/remote_xbox_gesture_title_down.png similarity index 100% rename from res/drawable/remote_xbox_gesture_title_down.png rename to app/src/main/res/drawable/remote_xbox_gesture_title_down.png diff --git a/res/drawable/remote_xbox_gesturezone.png b/app/src/main/res/drawable/remote_xbox_gesturezone.png similarity index 100% rename from res/drawable/remote_xbox_gesturezone.png rename to app/src/main/res/drawable/remote_xbox_gesturezone.png diff --git a/res/drawable/remote_xbox_gesturezone_dim.png b/app/src/main/res/drawable/remote_xbox_gesturezone_dim.png similarity index 100% rename from res/drawable/remote_xbox_gesturezone_dim.png rename to app/src/main/res/drawable/remote_xbox_gesturezone_dim.png diff --git a/app/src/main/res/drawable/remote_xbox_info.xml b/app/src/main/res/drawable/remote_xbox_info.xml new file mode 100644 index 00000000..92f47ee6 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_info.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_info_down.png b/app/src/main/res/drawable/remote_xbox_info_down.png similarity index 100% rename from res/drawable/remote_xbox_info_down.png rename to app/src/main/res/drawable/remote_xbox_info_down.png diff --git a/res/drawable/remote_xbox_info_up.png b/app/src/main/res/drawable/remote_xbox_info_up.png similarity index 100% rename from res/drawable/remote_xbox_info_up.png rename to app/src/main/res/drawable/remote_xbox_info_up.png diff --git a/app/src/main/res/drawable/remote_xbox_left.xml b/app/src/main/res/drawable/remote_xbox_left.xml new file mode 100644 index 00000000..cdb13010 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_left.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_left_down.png b/app/src/main/res/drawable/remote_xbox_left_down.png similarity index 100% rename from res/drawable/remote_xbox_left_down.png rename to app/src/main/res/drawable/remote_xbox_left_down.png diff --git a/res/drawable/remote_xbox_left_up.png b/app/src/main/res/drawable/remote_xbox_left_up.png similarity index 100% rename from res/drawable/remote_xbox_left_up.png rename to app/src/main/res/drawable/remote_xbox_left_up.png diff --git a/app/src/main/res/drawable/remote_xbox_menu.xml b/app/src/main/res/drawable/remote_xbox_menu.xml new file mode 100644 index 00000000..f7919a97 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_menu.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_menu_down.png b/app/src/main/res/drawable/remote_xbox_menu_down.png similarity index 100% rename from res/drawable/remote_xbox_menu_down.png rename to app/src/main/res/drawable/remote_xbox_menu_down.png diff --git a/res/drawable/remote_xbox_menu_up.png b/app/src/main/res/drawable/remote_xbox_menu_up.png similarity index 100% rename from res/drawable/remote_xbox_menu_up.png rename to app/src/main/res/drawable/remote_xbox_menu_up.png diff --git a/app/src/main/res/drawable/remote_xbox_next.xml b/app/src/main/res/drawable/remote_xbox_next.xml new file mode 100644 index 00000000..69a29150 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_next.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_next_down.png b/app/src/main/res/drawable/remote_xbox_next_down.png similarity index 100% rename from res/drawable/remote_xbox_next_down.png rename to app/src/main/res/drawable/remote_xbox_next_down.png diff --git a/res/drawable/remote_xbox_next_up.png b/app/src/main/res/drawable/remote_xbox_next_up.png similarity index 100% rename from res/drawable/remote_xbox_next_up.png rename to app/src/main/res/drawable/remote_xbox_next_up.png diff --git a/app/src/main/res/drawable/remote_xbox_pause.xml b/app/src/main/res/drawable/remote_xbox_pause.xml new file mode 100644 index 00000000..79b788d1 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_pause.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_pause_down.png b/app/src/main/res/drawable/remote_xbox_pause_down.png similarity index 100% rename from res/drawable/remote_xbox_pause_down.png rename to app/src/main/res/drawable/remote_xbox_pause_down.png diff --git a/res/drawable/remote_xbox_pause_up.png b/app/src/main/res/drawable/remote_xbox_pause_up.png similarity index 100% rename from res/drawable/remote_xbox_pause_up.png rename to app/src/main/res/drawable/remote_xbox_pause_up.png diff --git a/app/src/main/res/drawable/remote_xbox_play.xml b/app/src/main/res/drawable/remote_xbox_play.xml new file mode 100644 index 00000000..98362c98 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_play.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_play_down.png b/app/src/main/res/drawable/remote_xbox_play_down.png similarity index 100% rename from res/drawable/remote_xbox_play_down.png rename to app/src/main/res/drawable/remote_xbox_play_down.png diff --git a/res/drawable/remote_xbox_play_up.png b/app/src/main/res/drawable/remote_xbox_play_up.png similarity index 100% rename from res/drawable/remote_xbox_play_up.png rename to app/src/main/res/drawable/remote_xbox_play_up.png diff --git a/app/src/main/res/drawable/remote_xbox_previous.xml b/app/src/main/res/drawable/remote_xbox_previous.xml new file mode 100644 index 00000000..bb7b5321 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_previous.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_previous_down.png b/app/src/main/res/drawable/remote_xbox_previous_down.png similarity index 100% rename from res/drawable/remote_xbox_previous_down.png rename to app/src/main/res/drawable/remote_xbox_previous_down.png diff --git a/res/drawable/remote_xbox_previous_up.png b/app/src/main/res/drawable/remote_xbox_previous_up.png similarity index 100% rename from res/drawable/remote_xbox_previous_up.png rename to app/src/main/res/drawable/remote_xbox_previous_up.png diff --git a/app/src/main/res/drawable/remote_xbox_right.xml b/app/src/main/res/drawable/remote_xbox_right.xml new file mode 100644 index 00000000..cd052616 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_right.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_right_down.png b/app/src/main/res/drawable/remote_xbox_right_down.png similarity index 100% rename from res/drawable/remote_xbox_right_down.png rename to app/src/main/res/drawable/remote_xbox_right_down.png diff --git a/res/drawable/remote_xbox_right_up.png b/app/src/main/res/drawable/remote_xbox_right_up.png similarity index 100% rename from res/drawable/remote_xbox_right_up.png rename to app/src/main/res/drawable/remote_xbox_right_up.png diff --git a/app/src/main/res/drawable/remote_xbox_seek_back.xml b/app/src/main/res/drawable/remote_xbox_seek_back.xml new file mode 100644 index 00000000..969ba0c6 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_seek_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_seek_back_down.png b/app/src/main/res/drawable/remote_xbox_seek_back_down.png similarity index 100% rename from res/drawable/remote_xbox_seek_back_down.png rename to app/src/main/res/drawable/remote_xbox_seek_back_down.png diff --git a/res/drawable/remote_xbox_seek_back_up.png b/app/src/main/res/drawable/remote_xbox_seek_back_up.png similarity index 100% rename from res/drawable/remote_xbox_seek_back_up.png rename to app/src/main/res/drawable/remote_xbox_seek_back_up.png diff --git a/app/src/main/res/drawable/remote_xbox_seek_forward.xml b/app/src/main/res/drawable/remote_xbox_seek_forward.xml new file mode 100644 index 00000000..bcf23665 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_seek_forward.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_seek_forward_down.png b/app/src/main/res/drawable/remote_xbox_seek_forward_down.png similarity index 100% rename from res/drawable/remote_xbox_seek_forward_down.png rename to app/src/main/res/drawable/remote_xbox_seek_forward_down.png diff --git a/res/drawable/remote_xbox_seek_forward_up.png b/app/src/main/res/drawable/remote_xbox_seek_forward_up.png similarity index 100% rename from res/drawable/remote_xbox_seek_forward_up.png rename to app/src/main/res/drawable/remote_xbox_seek_forward_up.png diff --git a/app/src/main/res/drawable/remote_xbox_select.xml b/app/src/main/res/drawable/remote_xbox_select.xml new file mode 100644 index 00000000..13de9c66 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_select.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_select_down.png b/app/src/main/res/drawable/remote_xbox_select_down.png similarity index 100% rename from res/drawable/remote_xbox_select_down.png rename to app/src/main/res/drawable/remote_xbox_select_down.png diff --git a/res/drawable/remote_xbox_select_up.png b/app/src/main/res/drawable/remote_xbox_select_up.png similarity index 100% rename from res/drawable/remote_xbox_select_up.png rename to app/src/main/res/drawable/remote_xbox_select_up.png diff --git a/app/src/main/res/drawable/remote_xbox_stop.xml b/app/src/main/res/drawable/remote_xbox_stop.xml new file mode 100644 index 00000000..68428b6d --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_stop.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_stop_down.png b/app/src/main/res/drawable/remote_xbox_stop_down.png similarity index 100% rename from res/drawable/remote_xbox_stop_down.png rename to app/src/main/res/drawable/remote_xbox_stop_down.png diff --git a/res/drawable/remote_xbox_stop_up.png b/app/src/main/res/drawable/remote_xbox_stop_up.png similarity index 100% rename from res/drawable/remote_xbox_stop_up.png rename to app/src/main/res/drawable/remote_xbox_stop_up.png diff --git a/app/src/main/res/drawable/remote_xbox_title.xml b/app/src/main/res/drawable/remote_xbox_title.xml new file mode 100644 index 00000000..ff070701 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_title.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_title_down.png b/app/src/main/res/drawable/remote_xbox_title_down.png similarity index 100% rename from res/drawable/remote_xbox_title_down.png rename to app/src/main/res/drawable/remote_xbox_title_down.png diff --git a/res/drawable/remote_xbox_title_up.png b/app/src/main/res/drawable/remote_xbox_title_up.png similarity index 100% rename from res/drawable/remote_xbox_title_up.png rename to app/src/main/res/drawable/remote_xbox_title_up.png diff --git a/app/src/main/res/drawable/remote_xbox_up.xml b/app/src/main/res/drawable/remote_xbox_up.xml new file mode 100644 index 00000000..6118eeb3 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_up_down.png b/app/src/main/res/drawable/remote_xbox_up_down.png similarity index 100% rename from res/drawable/remote_xbox_up_down.png rename to app/src/main/res/drawable/remote_xbox_up_down.png diff --git a/res/drawable/remote_xbox_up_up.png b/app/src/main/res/drawable/remote_xbox_up_up.png similarity index 100% rename from res/drawable/remote_xbox_up_up.png rename to app/src/main/res/drawable/remote_xbox_up_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_back.xml b/app/src/main/res/drawable/remote_xbox_widget_back.xml new file mode 100644 index 00000000..4040b61c --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_back_down.png b/app/src/main/res/drawable/remote_xbox_widget_back_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_back_down.png rename to app/src/main/res/drawable/remote_xbox_widget_back_down.png diff --git a/res/drawable/remote_xbox_widget_back_up.png b/app/src/main/res/drawable/remote_xbox_widget_back_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_back_up.png rename to app/src/main/res/drawable/remote_xbox_widget_back_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_display.xml b/app/src/main/res/drawable/remote_xbox_widget_display.xml new file mode 100644 index 00000000..554ae766 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_display.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_display_down.png b/app/src/main/res/drawable/remote_xbox_widget_display_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_display_down.png rename to app/src/main/res/drawable/remote_xbox_widget_display_down.png diff --git a/res/drawable/remote_xbox_widget_display_up.png b/app/src/main/res/drawable/remote_xbox_widget_display_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_display_up.png rename to app/src/main/res/drawable/remote_xbox_widget_display_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_down.xml b/app/src/main/res/drawable/remote_xbox_widget_down.xml new file mode 100644 index 00000000..87a3164b --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_down.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_down_down.png b/app/src/main/res/drawable/remote_xbox_widget_down_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_down_down.png rename to app/src/main/res/drawable/remote_xbox_widget_down_down.png diff --git a/res/drawable/remote_xbox_widget_down_up.png b/app/src/main/res/drawable/remote_xbox_widget_down_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_down_up.png rename to app/src/main/res/drawable/remote_xbox_widget_down_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_info.xml b/app/src/main/res/drawable/remote_xbox_widget_info.xml new file mode 100644 index 00000000..819126f1 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_info.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_info_down.png b/app/src/main/res/drawable/remote_xbox_widget_info_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_info_down.png rename to app/src/main/res/drawable/remote_xbox_widget_info_down.png diff --git a/res/drawable/remote_xbox_widget_info_up.png b/app/src/main/res/drawable/remote_xbox_widget_info_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_info_up.png rename to app/src/main/res/drawable/remote_xbox_widget_info_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_left.xml b/app/src/main/res/drawable/remote_xbox_widget_left.xml new file mode 100644 index 00000000..9b430407 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_left.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_left_down.png b/app/src/main/res/drawable/remote_xbox_widget_left_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_left_down.png rename to app/src/main/res/drawable/remote_xbox_widget_left_down.png diff --git a/res/drawable/remote_xbox_widget_left_up.png b/app/src/main/res/drawable/remote_xbox_widget_left_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_left_up.png rename to app/src/main/res/drawable/remote_xbox_widget_left_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_menu.xml b/app/src/main/res/drawable/remote_xbox_widget_menu.xml new file mode 100644 index 00000000..2f741516 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_menu.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_menu_down.png b/app/src/main/res/drawable/remote_xbox_widget_menu_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_menu_down.png rename to app/src/main/res/drawable/remote_xbox_widget_menu_down.png diff --git a/res/drawable/remote_xbox_widget_menu_up.png b/app/src/main/res/drawable/remote_xbox_widget_menu_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_menu_up.png rename to app/src/main/res/drawable/remote_xbox_widget_menu_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_next.xml b/app/src/main/res/drawable/remote_xbox_widget_next.xml new file mode 100644 index 00000000..779d1a14 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_next.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_next_down.png b/app/src/main/res/drawable/remote_xbox_widget_next_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_next_down.png rename to app/src/main/res/drawable/remote_xbox_widget_next_down.png diff --git a/res/drawable/remote_xbox_widget_next_up.png b/app/src/main/res/drawable/remote_xbox_widget_next_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_next_up.png rename to app/src/main/res/drawable/remote_xbox_widget_next_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_pause.xml b/app/src/main/res/drawable/remote_xbox_widget_pause.xml new file mode 100644 index 00000000..5d39f032 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_pause.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_pause_down.png b/app/src/main/res/drawable/remote_xbox_widget_pause_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_pause_down.png rename to app/src/main/res/drawable/remote_xbox_widget_pause_down.png diff --git a/res/drawable/remote_xbox_widget_pause_up.png b/app/src/main/res/drawable/remote_xbox_widget_pause_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_pause_up.png rename to app/src/main/res/drawable/remote_xbox_widget_pause_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_play.xml b/app/src/main/res/drawable/remote_xbox_widget_play.xml new file mode 100644 index 00000000..c4694be1 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_play.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_play_down.png b/app/src/main/res/drawable/remote_xbox_widget_play_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_play_down.png rename to app/src/main/res/drawable/remote_xbox_widget_play_down.png diff --git a/res/drawable/remote_xbox_widget_play_up.png b/app/src/main/res/drawable/remote_xbox_widget_play_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_play_up.png rename to app/src/main/res/drawable/remote_xbox_widget_play_up.png diff --git a/res/drawable/remote_xbox_widget_preview.png b/app/src/main/res/drawable/remote_xbox_widget_preview.png similarity index 100% rename from res/drawable/remote_xbox_widget_preview.png rename to app/src/main/res/drawable/remote_xbox_widget_preview.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_previous.xml b/app/src/main/res/drawable/remote_xbox_widget_previous.xml new file mode 100644 index 00000000..0464ada8 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_previous.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_previous_down.png b/app/src/main/res/drawable/remote_xbox_widget_previous_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_previous_down.png rename to app/src/main/res/drawable/remote_xbox_widget_previous_down.png diff --git a/res/drawable/remote_xbox_widget_previous_up.png b/app/src/main/res/drawable/remote_xbox_widget_previous_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_previous_up.png rename to app/src/main/res/drawable/remote_xbox_widget_previous_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_right.xml b/app/src/main/res/drawable/remote_xbox_widget_right.xml new file mode 100644 index 00000000..fd4adc71 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_right.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_right_down.png b/app/src/main/res/drawable/remote_xbox_widget_right_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_right_down.png rename to app/src/main/res/drawable/remote_xbox_widget_right_down.png diff --git a/res/drawable/remote_xbox_widget_right_up.png b/app/src/main/res/drawable/remote_xbox_widget_right_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_right_up.png rename to app/src/main/res/drawable/remote_xbox_widget_right_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_seek_back.xml b/app/src/main/res/drawable/remote_xbox_widget_seek_back.xml new file mode 100644 index 00000000..e7ccdc3a --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_seek_back.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_seek_back_down.png b/app/src/main/res/drawable/remote_xbox_widget_seek_back_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_seek_back_down.png rename to app/src/main/res/drawable/remote_xbox_widget_seek_back_down.png diff --git a/res/drawable/remote_xbox_widget_seek_back_up.png b/app/src/main/res/drawable/remote_xbox_widget_seek_back_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_seek_back_up.png rename to app/src/main/res/drawable/remote_xbox_widget_seek_back_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_seek_forward.xml b/app/src/main/res/drawable/remote_xbox_widget_seek_forward.xml new file mode 100644 index 00000000..a00eac2f --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_seek_forward.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_seek_forward_down.png b/app/src/main/res/drawable/remote_xbox_widget_seek_forward_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_seek_forward_down.png rename to app/src/main/res/drawable/remote_xbox_widget_seek_forward_down.png diff --git a/res/drawable/remote_xbox_widget_seek_forward_up.png b/app/src/main/res/drawable/remote_xbox_widget_seek_forward_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_seek_forward_up.png rename to app/src/main/res/drawable/remote_xbox_widget_seek_forward_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_select.xml b/app/src/main/res/drawable/remote_xbox_widget_select.xml new file mode 100644 index 00000000..1bb4f669 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_select.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_select_down.png b/app/src/main/res/drawable/remote_xbox_widget_select_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_select_down.png rename to app/src/main/res/drawable/remote_xbox_widget_select_down.png diff --git a/res/drawable/remote_xbox_widget_select_up.png b/app/src/main/res/drawable/remote_xbox_widget_select_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_select_up.png rename to app/src/main/res/drawable/remote_xbox_widget_select_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_stop.xml b/app/src/main/res/drawable/remote_xbox_widget_stop.xml new file mode 100644 index 00000000..ce2f5a7d --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_stop.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_stop_down.png b/app/src/main/res/drawable/remote_xbox_widget_stop_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_stop_down.png rename to app/src/main/res/drawable/remote_xbox_widget_stop_down.png diff --git a/res/drawable/remote_xbox_widget_stop_up.png b/app/src/main/res/drawable/remote_xbox_widget_stop_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_stop_up.png rename to app/src/main/res/drawable/remote_xbox_widget_stop_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_title.xml b/app/src/main/res/drawable/remote_xbox_widget_title.xml new file mode 100644 index 00000000..8ced45f3 --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_title.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_title_down.png b/app/src/main/res/drawable/remote_xbox_widget_title_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_title_down.png rename to app/src/main/res/drawable/remote_xbox_widget_title_down.png diff --git a/res/drawable/remote_xbox_widget_title_up.png b/app/src/main/res/drawable/remote_xbox_widget_title_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_title_up.png rename to app/src/main/res/drawable/remote_xbox_widget_title_up.png diff --git a/app/src/main/res/drawable/remote_xbox_widget_up.xml b/app/src/main/res/drawable/remote_xbox_widget_up.xml new file mode 100644 index 00000000..f8a3addd --- /dev/null +++ b/app/src/main/res/drawable/remote_xbox_widget_up.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/res/drawable/remote_xbox_widget_up_down.png b/app/src/main/res/drawable/remote_xbox_widget_up_down.png similarity index 100% rename from res/drawable/remote_xbox_widget_up_down.png rename to app/src/main/res/drawable/remote_xbox_widget_up_down.png diff --git a/res/drawable/remote_xbox_widget_up_up.png b/app/src/main/res/drawable/remote_xbox_widget_up_up.png similarity index 100% rename from res/drawable/remote_xbox_widget_up_up.png rename to app/src/main/res/drawable/remote_xbox_widget_up_up.png diff --git a/res/drawable/scrollbar_handle.png b/app/src/main/res/drawable/scrollbar_handle.png similarity index 100% rename from res/drawable/scrollbar_handle.png rename to app/src/main/res/drawable/scrollbar_handle.png diff --git a/res/drawable/scrollbar_handle_accelerated_anim2.9.png b/app/src/main/res/drawable/scrollbar_handle_accelerated_anim2.9.png similarity index 100% rename from res/drawable/scrollbar_handle_accelerated_anim2.9.png rename to app/src/main/res/drawable/scrollbar_handle_accelerated_anim2.9.png diff --git a/res/drawable/selected.9.png b/app/src/main/res/drawable/selected.9.png similarity index 100% rename from res/drawable/selected.9.png rename to app/src/main/res/drawable/selected.9.png diff --git a/res/drawable/shiny_black_back.png b/app/src/main/res/drawable/shiny_black_back.png similarity index 100% rename from res/drawable/shiny_black_back.png rename to app/src/main/res/drawable/shiny_black_back.png diff --git a/res/drawable/smallborder.9.png b/app/src/main/res/drawable/smallborder.9.png similarity index 100% rename from res/drawable/smallborder.9.png rename to app/src/main/res/drawable/smallborder.9.png diff --git a/res/drawable/st_actor_off.png b/app/src/main/res/drawable/st_actor_off.png similarity index 100% rename from res/drawable/st_actor_off.png rename to app/src/main/res/drawable/st_actor_off.png diff --git a/res/drawable/st_actor_on.png b/app/src/main/res/drawable/st_actor_on.png similarity index 100% rename from res/drawable/st_actor_on.png rename to app/src/main/res/drawable/st_actor_on.png diff --git a/res/drawable/st_actor_over.png b/app/src/main/res/drawable/st_actor_over.png similarity index 100% rename from res/drawable/st_actor_over.png rename to app/src/main/res/drawable/st_actor_over.png diff --git a/res/drawable/st_album_off.png b/app/src/main/res/drawable/st_album_off.png similarity index 100% rename from res/drawable/st_album_off.png rename to app/src/main/res/drawable/st_album_off.png diff --git a/res/drawable/st_album_on.png b/app/src/main/res/drawable/st_album_on.png similarity index 100% rename from res/drawable/st_album_on.png rename to app/src/main/res/drawable/st_album_on.png diff --git a/res/drawable/st_album_over.png b/app/src/main/res/drawable/st_album_over.png similarity index 100% rename from res/drawable/st_album_over.png rename to app/src/main/res/drawable/st_album_over.png diff --git a/res/drawable/st_artist_off.png b/app/src/main/res/drawable/st_artist_off.png similarity index 100% rename from res/drawable/st_artist_off.png rename to app/src/main/res/drawable/st_artist_off.png diff --git a/res/drawable/st_artist_on.png b/app/src/main/res/drawable/st_artist_on.png similarity index 100% rename from res/drawable/st_artist_on.png rename to app/src/main/res/drawable/st_artist_on.png diff --git a/res/drawable/st_artist_over.png b/app/src/main/res/drawable/st_artist_over.png similarity index 100% rename from res/drawable/st_artist_over.png rename to app/src/main/res/drawable/st_artist_over.png diff --git a/res/drawable/st_background.png b/app/src/main/res/drawable/st_background.png similarity index 100% rename from res/drawable/st_background.png rename to app/src/main/res/drawable/st_background.png diff --git a/res/drawable/st_filemode_off.png b/app/src/main/res/drawable/st_filemode_off.png similarity index 100% rename from res/drawable/st_filemode_off.png rename to app/src/main/res/drawable/st_filemode_off.png diff --git a/res/drawable/st_filemode_on.png b/app/src/main/res/drawable/st_filemode_on.png similarity index 100% rename from res/drawable/st_filemode_on.png rename to app/src/main/res/drawable/st_filemode_on.png diff --git a/res/drawable/st_filemode_over.png b/app/src/main/res/drawable/st_filemode_over.png similarity index 100% rename from res/drawable/st_filemode_over.png rename to app/src/main/res/drawable/st_filemode_over.png diff --git a/res/drawable/st_genre_off.png b/app/src/main/res/drawable/st_genre_off.png similarity index 100% rename from res/drawable/st_genre_off.png rename to app/src/main/res/drawable/st_genre_off.png diff --git a/res/drawable/st_genre_on.png b/app/src/main/res/drawable/st_genre_on.png similarity index 100% rename from res/drawable/st_genre_on.png rename to app/src/main/res/drawable/st_genre_on.png diff --git a/res/drawable/st_genre_over.png b/app/src/main/res/drawable/st_genre_over.png similarity index 100% rename from res/drawable/st_genre_over.png rename to app/src/main/res/drawable/st_genre_over.png diff --git a/res/drawable/st_movie_off.png b/app/src/main/res/drawable/st_movie_off.png similarity index 100% rename from res/drawable/st_movie_off.png rename to app/src/main/res/drawable/st_movie_off.png diff --git a/res/drawable/st_movie_on.png b/app/src/main/res/drawable/st_movie_on.png similarity index 100% rename from res/drawable/st_movie_on.png rename to app/src/main/res/drawable/st_movie_on.png diff --git a/res/drawable/st_movie_over.png b/app/src/main/res/drawable/st_movie_over.png similarity index 100% rename from res/drawable/st_movie_over.png rename to app/src/main/res/drawable/st_movie_over.png diff --git a/res/drawable/st_playlist_off.png b/app/src/main/res/drawable/st_playlist_off.png similarity index 100% rename from res/drawable/st_playlist_off.png rename to app/src/main/res/drawable/st_playlist_off.png diff --git a/res/drawable/st_playlist_on.png b/app/src/main/res/drawable/st_playlist_on.png similarity index 100% rename from res/drawable/st_playlist_on.png rename to app/src/main/res/drawable/st_playlist_on.png diff --git a/res/drawable/st_playlist_over.png b/app/src/main/res/drawable/st_playlist_over.png similarity index 100% rename from res/drawable/st_playlist_over.png rename to app/src/main/res/drawable/st_playlist_over.png diff --git a/res/drawable/st_slider.png b/app/src/main/res/drawable/st_slider.png similarity index 100% rename from res/drawable/st_slider.png rename to app/src/main/res/drawable/st_slider.png diff --git a/res/drawable/st_song_off.png b/app/src/main/res/drawable/st_song_off.png similarity index 100% rename from res/drawable/st_song_off.png rename to app/src/main/res/drawable/st_song_off.png diff --git a/res/drawable/st_song_on.png b/app/src/main/res/drawable/st_song_on.png similarity index 100% rename from res/drawable/st_song_on.png rename to app/src/main/res/drawable/st_song_on.png diff --git a/res/drawable/st_song_over.png b/app/src/main/res/drawable/st_song_over.png similarity index 100% rename from res/drawable/st_song_over.png rename to app/src/main/res/drawable/st_song_over.png diff --git a/res/drawable/st_tv_off.png b/app/src/main/res/drawable/st_tv_off.png similarity index 100% rename from res/drawable/st_tv_off.png rename to app/src/main/res/drawable/st_tv_off.png diff --git a/res/drawable/st_tv_on.png b/app/src/main/res/drawable/st_tv_on.png similarity index 100% rename from res/drawable/st_tv_on.png rename to app/src/main/res/drawable/st_tv_on.png diff --git a/res/drawable/st_tv_over.png b/app/src/main/res/drawable/st_tv_over.png similarity index 100% rename from res/drawable/st_tv_over.png rename to app/src/main/res/drawable/st_tv_over.png diff --git a/res/drawable/st_va_off.png b/app/src/main/res/drawable/st_va_off.png similarity index 100% rename from res/drawable/st_va_off.png rename to app/src/main/res/drawable/st_va_off.png diff --git a/res/drawable/st_va_on.png b/app/src/main/res/drawable/st_va_on.png similarity index 100% rename from res/drawable/st_va_on.png rename to app/src/main/res/drawable/st_va_on.png diff --git a/res/drawable/st_va_over.png b/app/src/main/res/drawable/st_va_over.png similarity index 100% rename from res/drawable/st_va_over.png rename to app/src/main/res/drawable/st_va_over.png diff --git a/res/drawable/stars_0.png b/app/src/main/res/drawable/stars_0.png similarity index 100% rename from res/drawable/stars_0.png rename to app/src/main/res/drawable/stars_0.png diff --git a/res/drawable/stars_1.png b/app/src/main/res/drawable/stars_1.png similarity index 100% rename from res/drawable/stars_1.png rename to app/src/main/res/drawable/stars_1.png diff --git a/res/drawable/stars_10.png b/app/src/main/res/drawable/stars_10.png similarity index 100% rename from res/drawable/stars_10.png rename to app/src/main/res/drawable/stars_10.png diff --git a/res/drawable/stars_2.png b/app/src/main/res/drawable/stars_2.png similarity index 100% rename from res/drawable/stars_2.png rename to app/src/main/res/drawable/stars_2.png diff --git a/res/drawable/stars_3.png b/app/src/main/res/drawable/stars_3.png similarity index 100% rename from res/drawable/stars_3.png rename to app/src/main/res/drawable/stars_3.png diff --git a/res/drawable/stars_4.png b/app/src/main/res/drawable/stars_4.png similarity index 100% rename from res/drawable/stars_4.png rename to app/src/main/res/drawable/stars_4.png diff --git a/res/drawable/stars_5.png b/app/src/main/res/drawable/stars_5.png similarity index 100% rename from res/drawable/stars_5.png rename to app/src/main/res/drawable/stars_5.png diff --git a/res/drawable/stars_6.png b/app/src/main/res/drawable/stars_6.png similarity index 100% rename from res/drawable/stars_6.png rename to app/src/main/res/drawable/stars_6.png diff --git a/res/drawable/stars_7.png b/app/src/main/res/drawable/stars_7.png similarity index 100% rename from res/drawable/stars_7.png rename to app/src/main/res/drawable/stars_7.png diff --git a/res/drawable/stars_8.png b/app/src/main/res/drawable/stars_8.png similarity index 100% rename from res/drawable/stars_8.png rename to app/src/main/res/drawable/stars_8.png diff --git a/res/drawable/stars_9.png b/app/src/main/res/drawable/stars_9.png similarity index 100% rename from res/drawable/stars_9.png rename to app/src/main/res/drawable/stars_9.png diff --git a/res/drawable/timeborder.9.png b/app/src/main/res/drawable/timeborder.9.png similarity index 100% rename from res/drawable/timeborder.9.png rename to app/src/main/res/drawable/timeborder.9.png diff --git a/res/drawable/waiting.png b/app/src/main/res/drawable/waiting.png similarity index 100% rename from res/drawable/waiting.png rename to app/src/main/res/drawable/waiting.png diff --git a/app/src/main/res/layout-land-hdpi-v4/remote_xbox.xml b/app/src/main/res/layout-land-hdpi-v4/remote_xbox.xml new file mode 100644 index 00000000..999b3763 --- /dev/null +++ b/app/src/main/res/layout-land-hdpi-v4/remote_xbox.xml @@ -0,0 +1,236 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/albumtracks.xml b/app/src/main/res/layout/albumtracks.xml new file mode 100644 index 00000000..61c32bfe --- /dev/null +++ b/app/src/main/res/layout/albumtracks.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/artistinfo.xml b/app/src/main/res/layout/artistinfo.xml new file mode 100644 index 00000000..ad90b97d --- /dev/null +++ b/app/src/main/res/layout/artistinfo.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/blankgrid.xml b/app/src/main/res/layout/blankgrid.xml new file mode 100644 index 00000000..5584a2fd --- /dev/null +++ b/app/src/main/res/layout/blankgrid.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/blanklist.xml b/app/src/main/res/layout/blanklist.xml new file mode 100644 index 00000000..b3712a7e --- /dev/null +++ b/app/src/main/res/layout/blanklist.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/home.xml b/app/src/main/res/layout/home.xml new file mode 100644 index 00000000..f5b29083 --- /dev/null +++ b/app/src/main/res/layout/home.xml @@ -0,0 +1,50 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/setup_page_login.xml b/app/src/main/res/layout/setup_page_login.xml new file mode 100644 index 00000000..027abaa5 --- /dev/null +++ b/app/src/main/res/layout/setup_page_login.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/setup_wizard.xml b/app/src/main/res/layout/setup_wizard.xml new file mode 100644 index 00000000..06b226fa --- /dev/null +++ b/app/src/main/res/layout/setup_wizard.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + android:padding="7dip" + android:text="Play Episode"> + + android:padding="7dip" + android:text="Queue Episode"> diff --git a/app/src/main/res/layout/tvlibrary.xml b/app/src/main/res/layout/tvlibrary.xml new file mode 100644 index 00000000..ca3d1592 --- /dev/null +++ b/app/src/main/res/layout/tvlibrary.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/widget_xbox.xml b/app/src/main/res/layout/widget_xbox.xml new file mode 100644 index 00000000..307a8971 --- /dev/null +++ b/app/src/main/res/layout/widget_xbox.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + +