Formatting fixes.
- add braces to if/for - indent with tabs instead of spaces - remove trailing whitespaces
This commit is contained in:
parent
59df28b2bd
commit
105bb9de94
30 changed files with 980 additions and 913 deletions
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.v4.view.ViewPager
|
<android.support.v4.view.ViewPager
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/pager"
|
android:id="@+id/pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
|
@ -1,38 +1,38 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
android:orientation="horizontal" >
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
<com.github.nutomic.controldlna.utility.RemoteImageView
|
<com.github.nutomic.controldlna.utility.RemoteImageView
|
||||||
android:id="@+id/image"
|
android:id="@+id/image"
|
||||||
android:layout_width="?android:attr/listPreferredItemHeight"
|
android:layout_width="?android:attr/listPreferredItemHeight"
|
||||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||||
android:padding="4dip"
|
android:padding="4dip"
|
||||||
android:contentDescription="@string/album_art" />
|
android:contentDescription="@string/album_art" />
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="fill_parent"
|
android:layout_height="fill_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_marginTop="4dip" >
|
android:layout_marginTop="4dip" >
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:ellipsize="end" />
|
android:ellipsize="end" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/subtitle"
|
android:id="@+id/subtitle"
|
||||||
android:layout_width="fill_parent"
|
android:layout_width="fill_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
android:lines="1"
|
android:lines="1"
|
||||||
android:ellipsize="end" />
|
android:ellipsize="end" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -1,102 +1,102 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical" >
|
android:orientation="vertical" >
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@+id/listview"
|
android:id="@+id/listview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_above="@+id/controls"
|
android:layout_above="@+id/controls"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignParentTop="true" />
|
android:layout_alignParentTop="true" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/android:empty"
|
android:id="@id/android:empty"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dip"
|
android:layout_margin="10dip"
|
||||||
android:text="@string/route_list_empty"
|
android:text="@string/route_list_empty"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:id="@+id/controls"
|
android:id="@+id/controls"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
android:background="@android:color/white" >
|
android:background="@android:color/white" >
|
||||||
|
|
||||||
<SeekBar
|
<SeekBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingLeft="10dip"
|
android:paddingLeft="10dip"
|
||||||
android:paddingRight="10dip" >
|
android:paddingRight="10dip" >
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/current_time"
|
android:id="@+id/current_time"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentLeft="true"
|
android:layout_alignParentLeft="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:gravity="right"
|
android:gravity="right"
|
||||||
android:minEms="2" />
|
android:minEms="2" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/shuffle"
|
android:id="@+id/shuffle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/shuffle"
|
android:contentDescription="@string/shuffle"
|
||||||
android:layout_toLeftOf="@+id/previous" />
|
android:layout_toLeftOf="@+id/previous" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/previous"
|
android:id="@+id/previous"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/previous"
|
android:contentDescription="@string/previous"
|
||||||
android:layout_toLeftOf="@+id/playpause" />
|
android:layout_toLeftOf="@+id/playpause" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/playpause"
|
android:id="@+id/playpause"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/play"
|
android:contentDescription="@string/play"
|
||||||
android:layout_centerHorizontal="true"/>
|
android:layout_centerHorizontal="true"/>
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/next"
|
android:id="@+id/next"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/next"
|
android:contentDescription="@string/next"
|
||||||
android:layout_toRightOf="@id/playpause" />
|
android:layout_toRightOf="@id/playpause" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/repeat"
|
android:id="@+id/repeat"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="@string/repeat"
|
android:contentDescription="@string/repeat"
|
||||||
android:layout_toRightOf="@id/next" />
|
android:layout_toRightOf="@id/next" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/total_time"
|
android:id="@+id/total_time"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentRight="true"
|
android:layout_alignParentRight="true"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:gravity="right"
|
android:gravity="right"
|
||||||
android:minEms="2"/>
|
android:minEms="2"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical" >
|
android:orientation="vertical" >
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
android:id="@id/android:list"
|
android:id="@id/android:list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent" />
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@id/android:empty"
|
android:id="@id/android:empty"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_margin="10dip"
|
android:layout_margin="10dip"
|
||||||
android:text="@string/device_list_empty"
|
android:text="@string/device_list_empty"
|
||||||
android:layout_centerInParent="true"
|
android:layout_centerInParent="true"
|
||||||
android:gravity="center" />
|
android:gravity="center" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/preferences"
|
android:id="@+id/preferences"
|
||||||
android:title="@string/settings_title" />
|
android:title="@string/settings_title" />
|
||||||
|
|
||||||
</menu>
|
</menu>
|
|
@ -1,8 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<array name="enable_wifi_values">
|
<array name="enable_wifi_values">
|
||||||
<item>yes</item>
|
<item>yes</item>
|
||||||
<item>no</item>
|
<item>no</item>
|
||||||
<item>ask</item>
|
<item>ask</item>
|
||||||
</array>
|
</array>
|
||||||
</resources>
|
</resources>
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="currently_playing_background">#BB99CC00</color>
|
<color name="currently_playing_background">#BB99CC00</color>
|
||||||
<color name="button_highlight">#ff33b5e5</color>
|
<color name="button_highlight">#ff33b5e5</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!-- Default screen margins, per the Android Design guidelines. -->
|
<!-- Default screen margins, per the Android Design guidelines. -->
|
||||||
<dimen name="activity_horizontal_margin">16dp</dimen>
|
<dimen name="activity_horizontal_margin">16dp</dimen>
|
||||||
<dimen name="activity_vertical_margin">16dp</dimen>
|
<dimen name="activity_vertical_margin">16dp</dimen>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,42 +1,42 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<string name="app_name">ControlDLNA</string>
|
<string name="app_name">ControlDLNA</string>
|
||||||
|
|
||||||
<!-- Server Fragment -->
|
<!-- Server Fragment -->
|
||||||
<string name="title_server">Server</string>
|
<string name="title_server">Server</string>
|
||||||
<string name="folder_list_empty">Folder is empty</string>
|
<string name="folder_list_empty">Folder is empty</string>
|
||||||
<string name="device_list_empty">No UPNP devices found.
|
<string name="device_list_empty">No UPNP devices found.
|
||||||
\nNew devices will be added automatically when they are available.</string>
|
\nNew devices will be added automatically when they are available.</string>
|
||||||
|
|
||||||
<!-- Route Fragment -->
|
<!-- Route Fragment -->
|
||||||
<string name="title_route">Route</string>
|
<string name="title_route">Route</string>
|
||||||
<string name="playlist_empty">Playlist is empty</string>
|
<string name="playlist_empty">Playlist is empty</string>
|
||||||
<string name="route_list_empty">No routes found.
|
<string name="route_list_empty">No routes found.
|
||||||
\nNew routes will be added automatically when they are available.</string>
|
\nNew routes will be added automatically when they are available.</string>
|
||||||
|
|
||||||
<!-- Playback controls -->
|
<!-- Playback controls -->
|
||||||
<string name="play">Play</string>
|
<string name="play">Play</string>
|
||||||
<string name="pause">Pause</string>
|
<string name="pause">Pause</string>
|
||||||
<string name="previous">Previous</string>
|
<string name="previous">Previous</string>
|
||||||
<string name="next">Next</string>
|
<string name="next">Next</string>
|
||||||
<string name="shuffle">Shuffle</string>
|
<string name="shuffle">Shuffle</string>
|
||||||
<string name="repeat">Repeat</string>
|
<string name="repeat">Repeat</string>
|
||||||
|
|
||||||
<!-- Toasts/Dialogs -->
|
<!-- Toasts/Dialogs -->
|
||||||
<string name="exit_renderer">Do you really want to exit the renderer?
|
<string name="exit_renderer">Do you really want to exit the renderer?
|
||||||
Playback will be stopped.</string>
|
Playback will be stopped.</string>
|
||||||
<string name="select_route">Please select a route</string>
|
<string name="select_route">Please select a route</string>
|
||||||
<string name="enable_wifi_dialog">Wifi needs to be connected for playback.
|
<string name="enable_wifi_dialog">Wifi needs to be connected for playback.
|
||||||
Do you want to enable it now?</string>
|
Do you want to enable it now?</string>
|
||||||
|
|
||||||
<!-- Description for local playback device -->
|
<!-- Description for local playback device -->
|
||||||
<string name="local_device">Local Device</string>
|
<string name="local_device">Local Device</string>
|
||||||
|
|
||||||
<!-- Image alt text -->
|
<!-- Image alt text -->
|
||||||
<string name="album_art">Album Art</string>
|
<string name="album_art">Album Art</string>
|
||||||
|
|
||||||
<!-- MediaRouter strings -->
|
<!-- MediaRouter strings -->
|
||||||
<string name="upnp_route_provider_service">UPNP Route Provider Service</string>
|
<string name="upnp_route_provider_service">UPNP Route Provider Service</string>
|
||||||
|
|
||||||
<!-- Developer contact mail with '@', '.' replaced -->
|
<!-- Developer contact mail with '@', '.' replaced -->
|
||||||
|
@ -45,18 +45,18 @@
|
||||||
<!-- Title for the SettingsActivity -->
|
<!-- Title for the SettingsActivity -->
|
||||||
<string name="settings_title">Preferences</string>
|
<string name="settings_title">Preferences</string>
|
||||||
|
|
||||||
<!-- Title for preference to enable wifi on start -->
|
<!-- Title for preference to enable wifi on start -->
|
||||||
<string name="enable_wifi_title">Automatically enable Wifi on start</string>
|
<string name="enable_wifi_title">Automatically enable Wifi on start</string>
|
||||||
|
|
||||||
<!-- Values for preference to auto-enable wifi on start -->
|
<!-- Values for preference to auto-enable wifi on start -->
|
||||||
<string-array name="enable_wifi_value_titles">
|
<string-array name="enable_wifi_value_titles">
|
||||||
<item>yes</item>
|
<item>yes</item>
|
||||||
<item>no</item>
|
<item>no</item>
|
||||||
<item>ask</item>
|
<item>ask</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<!-- Title for the pause playback on call preference -->
|
<!-- Title for the pause playback on call preference -->
|
||||||
<string name="incoming_phone_call_pause">Pause playback on incoming phone call</string>
|
<string name="incoming_phone_call_pause">Pause playback on incoming phone call</string>
|
||||||
|
|
||||||
<!-- Title for the contact developer preference -->
|
<!-- Title for the contact developer preference -->
|
||||||
<string name="contact_dev_title">Contact Developer</string>
|
<string name="contact_dev_title">Contact Developer</string>
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
<resources>
|
<resources>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Base application theme, dependent on API level. This theme is replaced
|
Base application theme, dependent on API level. This theme is replaced
|
||||||
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
|
||||||
-->
|
-->
|
||||||
<style name="AppBaseTheme" parent="android:Theme.Light">
|
<style name="AppBaseTheme" parent="android:Theme.Light">
|
||||||
<!--
|
<!--
|
||||||
Theme customizations available in newer API levels can go in
|
Theme customizations available in newer API levels can go in
|
||||||
res/values-vXX/styles.xml, while customizations related to
|
res/values-vXX/styles.xml, while customizations related to
|
||||||
backward-compatibility can go here.
|
backward-compatibility can go here.
|
||||||
-->
|
-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Application theme. -->
|
<!-- Application theme. -->
|
||||||
<style name="AppTheme" parent="AppBaseTheme">
|
<style name="AppTheme" parent="AppBaseTheme">
|
||||||
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:key="enable_wifi_on_start"
|
android:key="enable_wifi_on_start"
|
||||||
android:title="@string/enable_wifi_title"
|
android:title="@string/enable_wifi_title"
|
||||||
android:entries="@array/enable_wifi_value_titles"
|
android:entries="@array/enable_wifi_value_titles"
|
||||||
android:entryValues="@array/enable_wifi_values"
|
android:entryValues="@array/enable_wifi_values"
|
||||||
android:defaultValue="ask"/>
|
android:defaultValue="ask"/>
|
||||||
|
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
android:key="incoming_phone_call_pause"
|
android:key="incoming_phone_call_pause"
|
||||||
android:title="@string/incoming_phone_call_pause"
|
android:title="@string/incoming_phone_call_pause"
|
||||||
android:defaultValue="true" />
|
android:defaultValue="true" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="contact_dev"
|
android:key="contact_dev"
|
||||||
android:title="@string/contact_dev_title" />
|
android:title="@string/contact_dev_title" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,17 +27,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.gui;
|
package com.github.nutomic.controldlna.gui;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.teleal.cling.support.model.item.Item;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.ConnectivityManager;
|
|
||||||
import android.net.NetworkInfo;
|
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
@ -50,17 +43,16 @@ import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.ActionBar.Tab;
|
import android.support.v7.app.ActionBar.Tab;
|
||||||
import android.support.v7.app.ActionBar.TabListener;
|
import android.support.v7.app.ActionBar.TabListener;
|
||||||
import android.support.v7.app.ActionBarActivity;
|
import android.support.v7.app.ActionBarActivity;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.widget.CheckBox;
|
|
||||||
import android.widget.CompoundButton;
|
|
||||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
|
||||||
|
|
||||||
import com.github.nutomic.controldlna.R;
|
import com.github.nutomic.controldlna.R;
|
||||||
|
|
||||||
|
import org.teleal.cling.support.model.item.Item;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main activity, with tabs for media servers and media routes.
|
* Main activity, with tabs for media servers and media routes.
|
||||||
*
|
*
|
||||||
|
@ -114,8 +106,7 @@ public class MainActivity extends ActionBarActivity {
|
||||||
|
|
||||||
mViewPager = (ViewPager) findViewById(R.id.pager);
|
mViewPager = (ViewPager) findViewById(R.id.pager);
|
||||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||||
mViewPager.setOnPageChangeListener(
|
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
|
||||||
new ViewPager.SimpleOnPageChangeListener() {
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageSelected(int position) {
|
public void onPageSelected(int position) {
|
||||||
actionBar.setSelectedNavigationItem(position);
|
actionBar.setSelectedNavigationItem(position);
|
||||||
|
@ -143,27 +134,27 @@ public class MainActivity extends ActionBarActivity {
|
||||||
.setText(R.string.title_route)
|
.setText(R.string.title_route)
|
||||||
.setTabListener(tabListener));
|
.setTabListener(tabListener));
|
||||||
|
|
||||||
final WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
|
final WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
|
||||||
if (!wifi.isWifiEnabled()){
|
if (!wifi.isWifiEnabled()) {
|
||||||
String value = PreferenceManager.getDefaultSharedPreferences(this)
|
String value = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.getString(PreferencesActivity.KEY_ENABLE_WIFI_ON_START, "ask");
|
.getString(PreferencesActivity.KEY_ENABLE_WIFI_ON_START, "ask");
|
||||||
if (value.equals("yes")) {
|
if (value.equals("yes")) {
|
||||||
wifi.setWifiEnabled(true);
|
wifi.setWifiEnabled(true);
|
||||||
}
|
}
|
||||||
else if (value.equals("ask")) {
|
else if (value.equals("ask")) {
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setMessage(R.string.enable_wifi_dialog)
|
.setMessage(R.string.enable_wifi_dialog)
|
||||||
.setPositiveButton(android.R.string.yes,
|
.setPositiveButton(android.R.string.yes,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialogInterface, int i) {
|
public void onClick(DialogInterface dialogInterface, int i) {
|
||||||
wifi.setWifiEnabled(true);
|
wifi.setWifiEnabled(true);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
|
@ -181,30 +172,30 @@ public class MainActivity extends ActionBarActivity {
|
||||||
onNewIntent(getIntent());
|
onNewIntent(getIntent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(Menu menu) {
|
public boolean onCreateOptionsMenu(Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.menu, menu);
|
getMenuInflater().inflate(R.menu.menu, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.preferences:
|
case R.id.preferences:
|
||||||
Intent i = new Intent(this, PreferencesActivity.class);
|
Intent i = new Intent(this, PreferencesActivity.class);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the RouteFragment immediately (instead of ServerFragment).
|
* Displays the RouteFragment immediately (instead of ServerFragment).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void onNewIntent(Intent intent) {
|
protected void onNewIntent(Intent intent) {
|
||||||
if (intent.getAction().equals("showRouteFragment")) {
|
if (intent.getAction() != null && intent.getAction().equals("showRouteFragment")) {
|
||||||
mViewPager.setCurrentItem(1);
|
mViewPager.setCurrentItem(1);
|
||||||
mRouteFragment.scrollToCurrent();
|
mRouteFragment.scrollToCurrent();
|
||||||
}
|
}
|
||||||
|
@ -216,13 +207,13 @@ public class MainActivity extends ActionBarActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
// Avoid crash if called during startup.
|
// Avoid crash if called during startup.
|
||||||
if (mServerFragment != null && mRouteFragment != null) {
|
if (mServerFragment != null && mRouteFragment != null) {
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
FragmentManager fm = getSupportFragmentManager();
|
||||||
fm.putFragment(outState, ServerFragment.class.getName(), mServerFragment);
|
fm.putFragment(outState, ServerFragment.class.getName(), mServerFragment);
|
||||||
fm.putFragment(outState, RouteFragment.class.getName(), mRouteFragment);
|
fm.putFragment(outState, RouteFragment.class.getName(), mRouteFragment);
|
||||||
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
outState.putInt("currentTab", mViewPager.getCurrentItem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,8 +224,9 @@ public class MainActivity extends ActionBarActivity {
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
OnBackPressedListener currentFragment = (OnBackPressedListener)
|
OnBackPressedListener currentFragment = (OnBackPressedListener)
|
||||||
mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
|
mSectionsPagerAdapter.getItem(mViewPager.getCurrentItem());
|
||||||
if (!currentFragment.onBackPressed())
|
if (!currentFragment.onBackPressed()) {
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -244,12 +236,14 @@ public class MainActivity extends ActionBarActivity {
|
||||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||||
switch (event.getKeyCode()) {
|
switch (event.getKeyCode()) {
|
||||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
mRouteFragment.increaseVolume();
|
mRouteFragment.increaseVolume();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN)
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
mRouteFragment.decreaseVolume();
|
mRouteFragment.decreaseVolume();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.dispatchKeyEvent(event);
|
return super.dispatchKeyEvent(event);
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -43,73 +43,72 @@ import android.view.MenuItem;
|
||||||
import com.github.nutomic.controldlna.R;
|
import com.github.nutomic.controldlna.R;
|
||||||
|
|
||||||
public class PreferencesActivity extends PreferenceActivity
|
public class PreferencesActivity extends PreferenceActivity
|
||||||
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||||
|
|
||||||
public static final String KEY_ENABLE_WIFI_ON_START = "enable_wifi_on_start";
|
public static final String KEY_ENABLE_WIFI_ON_START = "enable_wifi_on_start";
|
||||||
public static final String KEY_INCOMING_PHONE_CALL_PAUSE = "incoming_phone_call_pause";
|
public static final String KEY_INCOMING_PHONE_CALL_PAUSE = "incoming_phone_call_pause";
|
||||||
private static final String KEY_CONTACT_DEV = "contact_dev";
|
private static final String KEY_CONTACT_DEV = "contact_dev";
|
||||||
|
|
||||||
private ListPreference mEnableWifiOnStart;
|
private ListPreference mEnableWifiOnStart;
|
||||||
private Preference mContactDev;
|
private Preference mContactDev;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes preferences from xml.
|
* Initializes preferences from xml.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
// There is currently no way to get ActionBar in PreferenceActivity on pre-honeycomb with
|
// There is currently no way to get ActionBar in PreferenceActivity on pre-honeycomb with
|
||||||
// compatibility library, so we'll have to do a version check.
|
// compatibility library, so we'll have to do a version check.
|
||||||
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(this)
|
PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
.registerOnSharedPreferenceChangeListener(this);
|
.registerOnSharedPreferenceChangeListener(this);
|
||||||
addPreferencesFromResource(R.xml.preferences);
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
final PreferenceScreen screen = getPreferenceScreen();
|
final PreferenceScreen screen = getPreferenceScreen();
|
||||||
mEnableWifiOnStart = (ListPreference) screen.findPreference(KEY_ENABLE_WIFI_ON_START);
|
mEnableWifiOnStart = (ListPreference) screen.findPreference(KEY_ENABLE_WIFI_ON_START);
|
||||||
mEnableWifiOnStart.setSummary(mEnableWifiOnStart.getEntry());
|
mEnableWifiOnStart.setSummary(mEnableWifiOnStart.getEntry());
|
||||||
mContactDev = screen.findPreference(KEY_CONTACT_DEV);
|
mContactDev = screen.findPreference(KEY_CONTACT_DEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates up from activity on ActionBar back click.
|
* Navigates up from activity on ActionBar back click.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
NavUtils.navigateUpFromSameTask(this);
|
NavUtils.navigateUpFromSameTask(this);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends mail intent on contact dev preference click.
|
* Sends mail intent on contact dev preference click.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
|
||||||
Preference preference) {
|
Preference preference) {
|
||||||
if (preference == mContactDev) {
|
if (preference == mContactDev) {
|
||||||
Intent i = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
|
startActivity(new Intent(Intent.ACTION_SENDTO, Uri.fromParts(
|
||||||
"mailto", getString(R.string.contact_mail, "@", "."), null));
|
"mailto", getString(R.string.contact_mail, "@", "."), null)));
|
||||||
startActivity(i);
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
return super.onPreferenceTreeClick(preferenceScreen, preference);
|
||||||
return super.onPreferenceTreeClick(preferenceScreen, preference);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates summary of list preference (from current item).
|
* Updates summary of list preference (from current item).
|
||||||
*/
|
*/
|
||||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||||
if (key.equals(KEY_ENABLE_WIFI_ON_START)) {
|
if (key.equals(KEY_ENABLE_WIFI_ON_START)) {
|
||||||
mEnableWifiOnStart.setSummary(mEnableWifiOnStart.getEntry());
|
mEnableWifiOnStart.setSummary(mEnableWifiOnStart.getEntry());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,10 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.gui;
|
package com.github.nutomic.controldlna.gui;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.teleal.cling.support.model.item.Item;
|
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -49,7 +45,6 @@ import android.support.v7.media.MediaRouter;
|
||||||
import android.support.v7.media.MediaRouter.Callback;
|
import android.support.v7.media.MediaRouter.Callback;
|
||||||
import android.support.v7.media.MediaRouter.ProviderInfo;
|
import android.support.v7.media.MediaRouter.ProviderInfo;
|
||||||
import android.support.v7.media.MediaRouter.RouteInfo;
|
import android.support.v7.media.MediaRouter.RouteInfo;
|
||||||
import android.util.Log;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
@ -73,6 +68,10 @@ import com.github.nutomic.controldlna.mediarouter.MediaRouterPlayServiceBinder;
|
||||||
import com.github.nutomic.controldlna.utility.FileArrayAdapter;
|
import com.github.nutomic.controldlna.utility.FileArrayAdapter;
|
||||||
import com.github.nutomic.controldlna.utility.RouteAdapter;
|
import com.github.nutomic.controldlna.utility.RouteAdapter;
|
||||||
|
|
||||||
|
import org.teleal.cling.support.model.item.Item;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls media playback by showing a list of routes, and after selecting one,
|
* Controls media playback by showing a list of routes, and after selecting one,
|
||||||
* the current playlist and playback controls.
|
* the current playlist and playback controls.
|
||||||
|
@ -81,8 +80,8 @@ import com.github.nutomic.controldlna.utility.RouteAdapter;
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class RouteFragment extends MediaRouteDiscoveryFragment implements
|
public class RouteFragment extends MediaRouteDiscoveryFragment implements
|
||||||
OnBackPressedListener, OnItemClickListener, OnClickListener,
|
OnBackPressedListener, OnItemClickListener, OnClickListener,
|
||||||
OnSeekBarChangeListener, OnScrollListener {
|
OnSeekBarChangeListener, OnScrollListener {
|
||||||
|
|
||||||
private ListView mListView;
|
private ListView mListView;
|
||||||
|
|
||||||
|
@ -93,6 +92,7 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
private ImageButton mRepeat;
|
private ImageButton mRepeat;
|
||||||
private TextView mCurrentTimeView;
|
private TextView mCurrentTimeView;
|
||||||
private TextView mTotalTimeView;
|
private TextView mTotalTimeView;
|
||||||
|
private TextView mEmptyView;
|
||||||
|
|
||||||
private View mCurrentTrackView;
|
private View mCurrentTrackView;
|
||||||
|
|
||||||
|
@ -126,8 +126,9 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
mPlaylistAdapter.add(mMediaRouterPlayService.getPlaylist());
|
mPlaylistAdapter.add(mMediaRouterPlayService.getPlaylist());
|
||||||
applyColors();
|
applyColors();
|
||||||
RouteInfo currentRoute = mMediaRouterPlayService.getCurrentRoute();
|
RouteInfo currentRoute = mMediaRouterPlayService.getCurrentRoute();
|
||||||
if (currentRoute != null)
|
if (currentRoute != null) {
|
||||||
playlistMode(currentRoute);
|
playlistMode(currentRoute);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onServiceDisconnected(ComponentName className) {
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
@ -168,7 +169,9 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
mListView.setAdapter(mRouteAdapter);
|
mListView.setAdapter(mRouteAdapter);
|
||||||
mListView.setOnItemClickListener(this);
|
mListView.setOnItemClickListener(this);
|
||||||
mListView.setOnScrollListener(this);
|
mListView.setOnScrollListener(this);
|
||||||
mListView.setEmptyView(getView().findViewById(android.R.id.empty));
|
|
||||||
|
mEmptyView = (TextView) getView().findViewById(android.R.id.empty);
|
||||||
|
mListView.setEmptyView(mEmptyView);
|
||||||
|
|
||||||
mControls = getView().findViewById(R.id.controls);
|
mControls = getView().findViewById(R.id.controls);
|
||||||
mProgressBar = (SeekBar) getView().findViewById(R.id.progressBar);
|
mProgressBar = (SeekBar) getView().findViewById(R.id.progressBar);
|
||||||
|
@ -201,19 +204,17 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
new Intent(getActivity(), MediaRouterPlayService.class));
|
new Intent(getActivity(), MediaRouterPlayService.class));
|
||||||
getActivity().getApplicationContext().bindService(
|
getActivity().getApplicationContext().bindService(
|
||||||
new Intent(getActivity(), MediaRouterPlayService.class),
|
new Intent(getActivity(), MediaRouterPlayService.class),
|
||||||
mPlayServiceConnection,
|
mPlayServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
Context.BIND_AUTO_CREATE
|
|
||||||
);
|
|
||||||
|
|
||||||
if (savedInstanceState != null)
|
if (savedInstanceState != null) {
|
||||||
mListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_state"));
|
mListView.onRestoreInstanceState(savedInstanceState.getParcelable("list_state"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSaveInstanceState(Bundle outState) {
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
|
|
||||||
//outState.putBoolean("route_selected", mSelectedRoute != null);
|
|
||||||
outState.putParcelable("list_state", mListView.onSaveInstanceState());
|
outState.putParcelable("list_state", mListView.onSaveInstanceState());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,8 +230,8 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int onPrepareCallbackFlags() {
|
public int onPrepareCallbackFlags() {
|
||||||
return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY
|
return MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY |
|
||||||
| MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN;
|
MediaRouter.CALLBACK_FLAG_PERFORM_ACTIVE_SCAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -238,16 +239,18 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
return new MediaRouter.Callback() {
|
return new MediaRouter.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onRouteAdded(MediaRouter router, RouteInfo route) {
|
public void onRouteAdded(MediaRouter router, RouteInfo route) {
|
||||||
for (int i = 0; i < mRouteAdapter.getCount(); i++)
|
for (int i = 0; i < mRouteAdapter.getCount(); i++) {
|
||||||
if (mRouteAdapter.getItem(i).getId().equals(route.getId())) {
|
if (mRouteAdapter.getItem(i).getId().equals(route.getId())) {
|
||||||
mRouteAdapter.remove(mRouteAdapter.getItem(i));
|
mRouteAdapter.remove(mRouteAdapter.getItem(i));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
mRouteAdapter.add(route);
|
mRouteAdapter.add(route);
|
||||||
|
|
||||||
RouteInfo current = mMediaRouterPlayService.getCurrentRoute();
|
RouteInfo current = mMediaRouterPlayService.getCurrentRoute();
|
||||||
if (current != null && route.getId().equals(current.getId()))
|
if (current != null && route.getId().equals(current.getId())) {
|
||||||
playlistMode(current);
|
playlistMode(current);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -301,8 +304,9 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> a, View v, final int position, long id) {
|
public void onItemClick(AdapterView<?> a, View v, final int position, long id) {
|
||||||
if (mListView.getAdapter() == mRouteAdapter)
|
if (mListView.getAdapter() == mRouteAdapter) {
|
||||||
playlistMode(mRouteAdapter.getItem(position));
|
playlistMode(mRouteAdapter.getItem(position));
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
mMediaRouterPlayService.play(position);
|
mMediaRouterPlayService.play(position);
|
||||||
changePlayPauseState(true);
|
changePlayPauseState(true);
|
||||||
|
@ -317,8 +321,7 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
mListView.setAdapter(mRouteAdapter);
|
mListView.setAdapter(mRouteAdapter);
|
||||||
disableTrackHighlight();
|
disableTrackHighlight();
|
||||||
mSelectedRoute = null;
|
mSelectedRoute = null;
|
||||||
TextView emptyView = (TextView) mListView.getEmptyView();
|
mEmptyView.setText(R.string.route_list_empty);
|
||||||
emptyView.setText(R.string.route_list_empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -334,37 +337,39 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
changePlayPauseState(true);
|
changePlayPauseState(true);
|
||||||
mStartPlayingOnSelect = -1;
|
mStartPlayingOnSelect = -1;
|
||||||
}
|
}
|
||||||
TextView emptyView = (TextView) mListView.getEmptyView();
|
mEmptyView.setText(R.string.playlist_empty);
|
||||||
emptyView.setText(R.string.playlist_empty);
|
mListView.post(new Runnable() {
|
||||||
mListView.post(new Runnable() {
|
@Override
|
||||||
@Override
|
public void run() {
|
||||||
public void run() {
|
scrollToCurrent();
|
||||||
scrollToCurrent();
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets colored background on the item that is currently playing.
|
* Sets colored background on the item that is currently playing.
|
||||||
*/
|
*/
|
||||||
private void enableTrackHighlight() {
|
private void enableTrackHighlight() {
|
||||||
if (mListView.getAdapter() == mRouteAdapter || mMediaRouterPlayService == null || !isVisible())
|
if (mListView.getAdapter() == mRouteAdapter ||
|
||||||
|
mMediaRouterPlayService == null || !isVisible())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
disableTrackHighlight();
|
disableTrackHighlight();
|
||||||
mCurrentTrackView = mListView.getChildAt(mMediaRouterPlayService.getCurrentTrack()
|
mCurrentTrackView = mListView.getChildAt(mMediaRouterPlayService.getCurrentTrack()
|
||||||
- mListView.getFirstVisiblePosition() + mListView.getHeaderViewsCount());
|
- mListView.getFirstVisiblePosition() + mListView.getHeaderViewsCount());
|
||||||
if (mCurrentTrackView != null)
|
if (mCurrentTrackView != null) {
|
||||||
mCurrentTrackView.setBackgroundColor(
|
mCurrentTrackView.setBackgroundColor(
|
||||||
getResources().getColor(R.color.currently_playing_background));
|
getResources().getColor(R.color.currently_playing_background));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes highlight from the item that was last highlighted.
|
* Removes highlight from the item that was last highlighted.
|
||||||
*/
|
*/
|
||||||
private void disableTrackHighlight() {
|
private void disableTrackHighlight() {
|
||||||
if (mCurrentTrackView != null)
|
if (mCurrentTrackView != null) {
|
||||||
mCurrentTrackView.setBackgroundColor(Color.TRANSPARENT);
|
mCurrentTrackView.setBackgroundColor(Color.TRANSPARENT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -373,24 +378,25 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
@Override
|
@Override
|
||||||
public boolean onBackPressed() {
|
public boolean onBackPressed() {
|
||||||
if (mListView.getAdapter() == mPlaylistAdapter) {
|
if (mListView.getAdapter() == mPlaylistAdapter) {
|
||||||
if (mPlaying)
|
if (mPlaying) {
|
||||||
new AlertDialog.Builder(getActivity())
|
new AlertDialog.Builder(getActivity())
|
||||||
.setMessage(R.string.exit_renderer)
|
.setMessage(R.string.exit_renderer)
|
||||||
.setPositiveButton(android.R.string.yes,
|
.setPositiveButton(android.R.string.yes,
|
||||||
new DialogInterface.OnClickListener() {
|
new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
@Override
|
public void onClick(DialogInterface dialog,
|
||||||
public void onClick(DialogInterface dialog,
|
int which) {
|
||||||
int which) {
|
mMediaRouterPlayService.stop();
|
||||||
mMediaRouterPlayService.stop();
|
changePlayPauseState(false);
|
||||||
changePlayPauseState(false);
|
deviceListMode();
|
||||||
deviceListMode();
|
}
|
||||||
}
|
})
|
||||||
})
|
.setNegativeButton(android.R.string.no, null)
|
||||||
.setNegativeButton(android.R.string.no, null)
|
.show();
|
||||||
.show();
|
}
|
||||||
else
|
else {
|
||||||
deviceListMode();
|
deviceListMode();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -470,8 +476,9 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
@Override
|
@Override
|
||||||
public void onProgressChanged(SeekBar seekBar, int progress,
|
public void onProgressChanged(SeekBar seekBar, int progress,
|
||||||
boolean fromUser) {
|
boolean fromUser) {
|
||||||
if (fromUser)
|
if (fromUser) {
|
||||||
mMediaRouterPlayService.seek(progress);
|
mMediaRouterPlayService.seek(progress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -514,9 +521,10 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
if (mSelectedRoute != null) {
|
if (mSelectedRoute != null) {
|
||||||
mMediaRouterPlayService.play(start);
|
mMediaRouterPlayService.play(start);
|
||||||
changePlayPauseState(true);
|
changePlayPauseState(true);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
Toast.makeText(getActivity(), R.string.select_route, Toast.LENGTH_SHORT)
|
Toast.makeText(getActivity(), R.string.select_route, Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
mStartPlayingOnSelect = start;
|
mStartPlayingOnSelect = start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -528,16 +536,17 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
* @return Formatted time string.
|
* @return Formatted time string.
|
||||||
*/
|
*/
|
||||||
private String generateTimeString(int time) {
|
private String generateTimeString(int time) {
|
||||||
assert(time >= 0);
|
|
||||||
int seconds = time % 60;
|
int seconds = time % 60;
|
||||||
int minutes = time / 60;
|
int minutes = time / 60;
|
||||||
if (minutes > 99)
|
if (minutes > 99) {
|
||||||
return "99:99";
|
return "99:99";
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
return Integer.toString(minutes) + ":" +
|
return Integer.toString(minutes) + ":" +
|
||||||
((seconds > 9)
|
((seconds > 9)
|
||||||
? seconds
|
? seconds
|
||||||
: "0" + Integer.toString(seconds));
|
: "0" + Integer.toString(seconds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -559,13 +568,16 @@ OnSeekBarChangeListener, OnScrollListener {
|
||||||
|
|
||||||
if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_PLAYING ||
|
if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_PLAYING ||
|
||||||
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_BUFFERING ||
|
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_BUFFERING ||
|
||||||
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_PENDING)
|
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_PENDING) {
|
||||||
changePlayPauseState(true);
|
changePlayPauseState(true);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
changePlayPauseState(false);
|
changePlayPauseState(false);
|
||||||
|
}
|
||||||
|
|
||||||
if (mListView.getAdapter() == mPlaylistAdapter)
|
if (mListView.getAdapter() == mPlaylistAdapter) {
|
||||||
enableTrackHighlight();
|
enableTrackHighlight();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,24 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.gui;
|
package com.github.nutomic.controldlna.gui;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Stack;
|
|
||||||
|
|
||||||
import org.teleal.cling.android.AndroidUpnpService;
|
|
||||||
import org.teleal.cling.android.AndroidUpnpServiceImpl;
|
|
||||||
import org.teleal.cling.model.action.ActionInvocation;
|
|
||||||
import org.teleal.cling.model.message.UpnpResponse;
|
|
||||||
import org.teleal.cling.model.meta.Device;
|
|
||||||
import org.teleal.cling.model.meta.Service;
|
|
||||||
import org.teleal.cling.model.types.ServiceType;
|
|
||||||
import org.teleal.cling.model.types.UDN;
|
|
||||||
import org.teleal.cling.support.contentdirectory.callback.Browse;
|
|
||||||
import org.teleal.cling.support.model.BrowseFlag;
|
|
||||||
import org.teleal.cling.support.model.DIDLContent;
|
|
||||||
import org.teleal.cling.support.model.container.Container;
|
|
||||||
import org.teleal.cling.support.model.item.Item;
|
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
@ -70,6 +52,24 @@ import com.github.nutomic.controldlna.gui.MainActivity.OnBackPressedListener;
|
||||||
import com.github.nutomic.controldlna.utility.DeviceArrayAdapter;
|
import com.github.nutomic.controldlna.utility.DeviceArrayAdapter;
|
||||||
import com.github.nutomic.controldlna.utility.FileArrayAdapter;
|
import com.github.nutomic.controldlna.utility.FileArrayAdapter;
|
||||||
|
|
||||||
|
import org.teleal.cling.android.AndroidUpnpService;
|
||||||
|
import org.teleal.cling.android.AndroidUpnpServiceImpl;
|
||||||
|
import org.teleal.cling.model.action.ActionInvocation;
|
||||||
|
import org.teleal.cling.model.message.UpnpResponse;
|
||||||
|
import org.teleal.cling.model.meta.Device;
|
||||||
|
import org.teleal.cling.model.meta.Service;
|
||||||
|
import org.teleal.cling.model.types.ServiceType;
|
||||||
|
import org.teleal.cling.model.types.UDN;
|
||||||
|
import org.teleal.cling.support.contentdirectory.callback.Browse;
|
||||||
|
import org.teleal.cling.support.model.BrowseFlag;
|
||||||
|
import org.teleal.cling.support.model.DIDLContent;
|
||||||
|
import org.teleal.cling.support.model.container.Container;
|
||||||
|
import org.teleal.cling.support.model.item.Item;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a list of media servers, upon selecting one, allows browsing their
|
* Shows a list of media servers, upon selecting one, allows browsing their
|
||||||
* directories.
|
* directories.
|
||||||
|
@ -107,6 +107,8 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
*/
|
*/
|
||||||
private Stack<String> mCurrentPath = new Stack<String>();
|
private Stack<String> mCurrentPath = new Stack<String>();
|
||||||
|
|
||||||
|
private TextView mEmptyView;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds the scroll position in the list view at each directory level.
|
* Holds the scroll position in the list view at each directory level.
|
||||||
*/
|
*/
|
||||||
|
@ -148,7 +150,6 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
return inflater.inflate(R.layout.server_fragment, null);
|
return inflater.inflate(R.layout.server_fragment, null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,21 +167,23 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
setListAdapter(mServerAdapter);
|
setListAdapter(mServerAdapter);
|
||||||
getActivity().getApplicationContext().bindService(
|
getActivity().getApplicationContext().bindService(
|
||||||
new Intent(getActivity(), AndroidUpnpServiceImpl.class),
|
new Intent(getActivity(), AndroidUpnpServiceImpl.class),
|
||||||
mUpnpServiceConnection,
|
mUpnpServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
Context.BIND_AUTO_CREATE
|
|
||||||
);
|
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||||
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
getActivity().registerReceiver(mWifiReceiver, filter);
|
getActivity().registerReceiver(mWifiReceiver, filter);
|
||||||
|
|
||||||
|
mEmptyView = (TextView) getListView().getEmptyView();
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
mRestoreServer = savedInstanceState.getString("current_server");
|
mRestoreServer = savedInstanceState.getString("current_server");
|
||||||
mCurrentPath.addAll(savedInstanceState.getStringArrayList("path"));
|
mCurrentPath.addAll(savedInstanceState.getStringArrayList("path"));
|
||||||
mListState.addAll(savedInstanceState.getParcelableArrayList("list_state"));
|
mListState.addAll(savedInstanceState.getParcelableArrayList("list_state"));
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
mListState.push(getListView().onSaveInstanceState());
|
mListState.push(getListView().onSaveInstanceState());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,7 +194,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
outState.putString("current_server", (mCurrentServer != null)
|
outState.putString("current_server", (mCurrentServer != null)
|
||||||
? mCurrentServer.getIdentity().getUdn().toString()
|
? mCurrentServer.getIdentity().getUdn().toString()
|
||||||
: "");
|
: "");
|
||||||
outState.putStringArrayList("path", new ArrayList<String>(mCurrentPath));
|
outState.putStringArrayList("path", new ArrayList<String>(mCurrentPath));
|
||||||
mListState.pop();
|
mListState.pop();
|
||||||
mListState.push(getListView().onSaveInstanceState());
|
mListState.push(getListView().onSaveInstanceState());
|
||||||
|
@ -210,19 +213,23 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||||
if (getListAdapter() == mServerAdapter)
|
if (getListAdapter() == mServerAdapter) {
|
||||||
browsingMode(mServerAdapter.getItem(position));
|
browsingMode(mServerAdapter.getItem(position));
|
||||||
else if (getListAdapter() == mFileAdapter)
|
}
|
||||||
|
else if (getListAdapter() == mFileAdapter) {
|
||||||
if (mFileAdapter.getItem(position) instanceof Container)
|
if (mFileAdapter.getItem(position) instanceof Container)
|
||||||
getFiles(((Container) mFileAdapter.getItem(position)).getId());
|
getFiles(((Container) mFileAdapter.getItem(position)).getId());
|
||||||
else {
|
else {
|
||||||
List<Item> playlist = new ArrayList<Item>();
|
List<Item> playlist = new ArrayList<Item>();
|
||||||
for (int i = 0; i < mFileAdapter.getCount(); i++)
|
for (int i = 0; i < mFileAdapter.getCount(); i++) {
|
||||||
if (mFileAdapter.getItem(i) instanceof Item)
|
if (mFileAdapter.getItem(i) instanceof Item) {
|
||||||
playlist.add((Item) mFileAdapter.getItem(i));
|
playlist.add((Item) mFileAdapter.getItem(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
MainActivity activity = (MainActivity) getActivity();
|
MainActivity activity = (MainActivity) getActivity();
|
||||||
activity.play(playlist, position);
|
activity.play(playlist, position);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -231,8 +238,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
private void serverMode() {
|
private void serverMode() {
|
||||||
setListAdapter(mServerAdapter);
|
setListAdapter(mServerAdapter);
|
||||||
mCurrentServer = null;
|
mCurrentServer = null;
|
||||||
TextView emptyView = (TextView) getListView().getEmptyView();
|
mEmptyView.setText(R.string.device_list_empty);
|
||||||
emptyView.setText(R.string.device_list_empty);
|
|
||||||
getListView().onRestoreInstanceState(mListState.pop());
|
getListView().onRestoreInstanceState(mListState.pop());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,8 +249,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
setListAdapter(mFileAdapter);
|
setListAdapter(mFileAdapter);
|
||||||
mCurrentServer = server;
|
mCurrentServer = server;
|
||||||
getFiles(ROOT_DIRECTORY);
|
getFiles(ROOT_DIRECTORY);
|
||||||
TextView emptyView = (TextView) getListView().getEmptyView();
|
mEmptyView.setText(R.string.folder_list_empty);
|
||||||
emptyView.setText(R.string.folder_list_empty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -281,14 +286,18 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
mFileAdapter.clear();
|
mFileAdapter.clear();
|
||||||
for (Container c : didl.getContainers())
|
for (Container c : didl.getContainers()) {
|
||||||
mFileAdapter.add(c);
|
mFileAdapter.add(c);
|
||||||
for (Item i : didl.getItems())
|
}
|
||||||
|
for (Item i : didl.getItems()) {
|
||||||
mFileAdapter.add(i);
|
mFileAdapter.add(i);
|
||||||
if (restoreListState)
|
}
|
||||||
|
if (restoreListState) {
|
||||||
getListView().onRestoreInstanceState(mListState.pop());
|
getListView().onRestoreInstanceState(mListState.pop());
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
getListView().setSelectionFromTop(0, 0);
|
getListView().setSelectionFromTop(0, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -317,10 +326,12 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mCurrentPath.pop();
|
mCurrentPath.pop();
|
||||||
if (mCurrentPath.empty())
|
if (mCurrentPath.empty()) {
|
||||||
serverMode();
|
serverMode();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
getFiles(true);
|
getFiles(true);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,11 +351,13 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
if (wifi.isConnected()) {
|
if (wifi.isConnected()) {
|
||||||
if (mUpnpService != null) {
|
if (mUpnpService != null) {
|
||||||
for (Device<?, ?, ?> d : mUpnpService.getControlPoint()
|
for (Device<?, ?, ?> d : mUpnpService.getControlPoint()
|
||||||
.getRegistry().getDevices())
|
.getRegistry().getDevices()) {
|
||||||
mServerAdapter.deviceAdded(d);
|
mServerAdapter.deviceAdded(d);
|
||||||
|
}
|
||||||
mUpnpService.getControlPoint().search();
|
mUpnpService.getControlPoint().search();
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
for (int i = 0; i < mServerAdapter.getCount(); i++) {
|
for (int i = 0; i < mServerAdapter.getCount(); i++) {
|
||||||
Device<?, ?, ?> d = mServerAdapter.getItem(i);
|
Device<?, ?, ?> d = mServerAdapter.getItem(i);
|
||||||
UDN udn = new UDN(d.getIdentity().getUdn().toString());
|
UDN udn = new UDN(d.getIdentity().getUdn().toString());
|
||||||
|
@ -358,6 +371,7 @@ public class ServerFragment extends ListFragment implements OnBackPressedListene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,14 +4,14 @@ All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,8 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.localroute;
|
package com.github.nutomic.controldlna.localroute;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
|
@ -41,6 +39,8 @@ import android.support.v7.media.MediaRouteProvider;
|
||||||
import android.support.v7.media.MediaRouter.ControlRequestCallback;
|
import android.support.v7.media.MediaRouter.ControlRequestCallback;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receives control intents through media route and executes them on a MediaPlayer.
|
* Receives control intents through media route and executes them on a MediaPlayer.
|
||||||
*
|
*
|
||||||
|
@ -56,103 +56,105 @@ public class Controller extends MediaRouteProvider.RouteController implements
|
||||||
|
|
||||||
private AudioManager mAudio;
|
private AudioManager mAudio;
|
||||||
|
|
||||||
AudioManager.OnAudioFocusChangeListener mFocusListener;
|
AudioManager.OnAudioFocusChangeListener mFocusListener;
|
||||||
|
|
||||||
private final String mRouteId;
|
private final String mRouteId;
|
||||||
|
|
||||||
private String mItemId;
|
private String mItemId;
|
||||||
|
|
||||||
private int mState;
|
private int mState;
|
||||||
|
|
||||||
private MediaPlayer mPlayer = new MediaPlayer();
|
private MediaPlayer mPlayer = new MediaPlayer();
|
||||||
|
|
||||||
public Controller(String routeId, Context context) {
|
public Controller(String routeId, Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mRouteId = routeId;
|
mRouteId = routeId;
|
||||||
mAudio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
mAudio = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||||
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
|
||||||
mPlayer.setOnPreparedListener(this);
|
mPlayer.setOnPreparedListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRelease() {
|
public void onRelease() {
|
||||||
mPlayer.release();
|
mPlayer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSelect() {
|
public void onSelect() {
|
||||||
mAudio.requestAudioFocus(mFocusListener, AudioManager.STREAM_MUSIC,
|
mAudio.requestAudioFocus(mFocusListener, AudioManager.STREAM_MUSIC,
|
||||||
AudioManager.AUDIOFOCUS_GAIN);
|
AudioManager.AUDIOFOCUS_GAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUnselect() {
|
public void onUnselect() {
|
||||||
mAudio.abandonAudioFocus(mFocusListener);
|
mAudio.abandonAudioFocus(mFocusListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetVolume(int volume) {
|
public void onSetVolume(int volume) {
|
||||||
mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
|
mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdateVolume(int delta) {
|
public void onUpdateVolume(int delta) {
|
||||||
int currentVolume = mAudio.getStreamVolume(AudioManager.STREAM_MUSIC);
|
int currentVolume = mAudio.getStreamVolume(AudioManager.STREAM_MUSIC);
|
||||||
mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume + delta, 0);
|
mAudio.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume + delta, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
|
public boolean onControlRequest(Intent intent, ControlRequestCallback callback) {
|
||||||
String sessionId = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
|
String sessionId = intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID);
|
||||||
String itemId = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
|
String itemId = intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID);
|
||||||
if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) {
|
if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) {
|
||||||
try {
|
try {
|
||||||
mPlayer.reset();
|
mPlayer.reset();
|
||||||
mPlayer.setDataSource(mContext, intent.getData());
|
mPlayer.setDataSource(mContext, intent.getData());
|
||||||
mPlayer.prepareAsync();
|
mPlayer.prepareAsync();
|
||||||
mItemId = intent.getDataString();
|
mItemId = intent.getDataString();
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_BUFFERING;
|
mState = MediaItemStatus.PLAYBACK_STATE_BUFFERING;
|
||||||
getStatus(mItemId, mRouteId, callback);
|
getStatus(mItemId, mRouteId, callback);
|
||||||
return true;
|
return true;
|
||||||
} catch (IllegalArgumentException e) {
|
}
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_ERROR;
|
catch (IllegalArgumentException e) {
|
||||||
Log.d(TAG, "Failed to start playback", e);
|
|
||||||
} catch (IOException e) {
|
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_ERROR;
|
mState = MediaItemStatus.PLAYBACK_STATE_ERROR;
|
||||||
Log.d(TAG, "Failed to start playback", e);
|
Log.d(TAG, "Failed to start playback", e);
|
||||||
}
|
}
|
||||||
}
|
catch (IOException e) {
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) {
|
mState = MediaItemStatus.PLAYBACK_STATE_ERROR;
|
||||||
mPlayer.pause();
|
Log.d(TAG, "Failed to start playback", e);
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_PAUSED;
|
}
|
||||||
return true;
|
}
|
||||||
}
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) {
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_RESUME)) {
|
mPlayer.pause();
|
||||||
mPlayer.start();
|
mState = MediaItemStatus.PLAYBACK_STATE_PAUSED;
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_RESUME)) {
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_STOP)) {
|
mPlayer.start();
|
||||||
mPlayer.stop();
|
mState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_CANCELED;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_STOP)) {
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) {
|
mPlayer.stop();
|
||||||
mPlayer.seekTo((int) intent.getLongExtra(
|
mState = MediaItemStatus.PLAYBACK_STATE_CANCELED;
|
||||||
MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0));
|
return true;
|
||||||
getStatus(itemId, sessionId, callback);
|
}
|
||||||
return true;
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) {
|
||||||
}
|
mPlayer.seekTo((int) intent.getLongExtra(
|
||||||
else if(intent.getAction().equals(MediaControlIntent.ACTION_GET_STATUS)) {
|
MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0));
|
||||||
getStatus(itemId, sessionId, callback);
|
getStatus(itemId, sessionId, callback);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
else if(intent.getAction().equals(MediaControlIntent.ACTION_GET_STATUS)) {
|
||||||
|
getStatus(itemId, sessionId, callback);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getStatus(String itemId, String sessionId, ControlRequestCallback callback) {
|
private void getStatus(String itemId, String sessionId, ControlRequestCallback callback) {
|
||||||
if (callback == null)
|
if (callback == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Bundle status = null;
|
Bundle status = null;
|
||||||
|
|
||||||
|
@ -161,24 +163,26 @@ public class Controller extends MediaRouteProvider.RouteController implements
|
||||||
.setContentPosition(mPlayer.getCurrentPosition())
|
.setContentPosition(mPlayer.getCurrentPosition())
|
||||||
.setContentDuration(mPlayer.getDuration())
|
.setContentDuration(mPlayer.getDuration())
|
||||||
.setTimestamp(SystemClock.elapsedRealtime())
|
.setTimestamp(SystemClock.elapsedRealtime())
|
||||||
.build().asBundle();
|
.build()
|
||||||
|
.asBundle();
|
||||||
|
|
||||||
status.putString(MediaControlIntent.EXTRA_SESSION_ID, mRouteId);
|
status.putString(MediaControlIntent.EXTRA_SESSION_ID, mRouteId);
|
||||||
status.putString(MediaControlIntent.EXTRA_ITEM_ID, mItemId);
|
status.putString(MediaControlIntent.EXTRA_ITEM_ID, mItemId);
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
status = new MediaItemStatus.Builder(MediaItemStatus.PLAYBACK_STATE_INVALIDATED)
|
status = new MediaItemStatus.Builder(MediaItemStatus.PLAYBACK_STATE_INVALIDATED)
|
||||||
.build().asBundle();
|
.build().asBundle();
|
||||||
|
}
|
||||||
|
|
||||||
callback.onResult(status);
|
callback.onResult(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets state to finished.
|
* Sets state to finished.
|
||||||
*
|
*
|
||||||
* Note: Do not set the listener before play() is called
|
* Note: Do not set the listener before play() is called
|
||||||
* (or this will be called immediately).
|
* (or this will be called immediately).
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onCompletion(MediaPlayer mp) {
|
public void onCompletion(MediaPlayer mp) {
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_FINISHED;
|
mState = MediaItemStatus.PLAYBACK_STATE_FINISHED;
|
||||||
|
@ -191,7 +195,7 @@ public class Controller extends MediaRouteProvider.RouteController implements
|
||||||
@Override
|
@Override
|
||||||
public void onPrepared(MediaPlayer mp) {
|
public void onPrepared(MediaPlayer mp) {
|
||||||
mPlayer.start();
|
mPlayer.start();
|
||||||
mState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
mState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
||||||
mPlayer.setOnCompletionListener(this);
|
mPlayer.setOnCompletionListener(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,14 @@ All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -51,55 +51,56 @@ import com.github.nutomic.controldlna.R;
|
||||||
*/
|
*/
|
||||||
final class Provider extends MediaRouteProvider {
|
final class Provider extends MediaRouteProvider {
|
||||||
|
|
||||||
private static final String ROUTE_ID = "local_route";
|
private static final String ROUTE_ID = "local_route";
|
||||||
|
|
||||||
AudioManager mAudio = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
AudioManager mAudio = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
|
||||||
|
|
||||||
private static final ArrayList<IntentFilter> CONTROL_FILTERS;
|
private static final ArrayList<IntentFilter> CONTROL_FILTERS;
|
||||||
static {
|
static {
|
||||||
IntentFilter f = new IntentFilter();
|
IntentFilter f = new IntentFilter();
|
||||||
f.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
|
f.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
|
||||||
f.addAction(MediaControlIntent.ACTION_PLAY);
|
f.addAction(MediaControlIntent.ACTION_PLAY);
|
||||||
f.addAction(MediaControlIntent.ACTION_PAUSE);
|
f.addAction(MediaControlIntent.ACTION_PAUSE);
|
||||||
f.addAction(MediaControlIntent.ACTION_SEEK);
|
f.addAction(MediaControlIntent.ACTION_SEEK);
|
||||||
f.addAction(MediaControlIntent.ACTION_STOP);
|
f.addAction(MediaControlIntent.ACTION_STOP);
|
||||||
f.addDataScheme("http");
|
f.addDataScheme("http");
|
||||||
f.addDataScheme("https");
|
f.addDataScheme("https");
|
||||||
addDataTypeUnchecked(f, "audio/*");
|
addDataTypeUnchecked(f, "audio/*");
|
||||||
|
|
||||||
CONTROL_FILTERS = new ArrayList<IntentFilter>();
|
CONTROL_FILTERS = new ArrayList<IntentFilter>();
|
||||||
CONTROL_FILTERS.add(f);
|
CONTROL_FILTERS.add(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void addDataTypeUnchecked(IntentFilter filter, String type) {
|
private static void addDataTypeUnchecked(IntentFilter filter, String type) {
|
||||||
try {
|
try {
|
||||||
filter.addDataType(type);
|
filter.addDataType(type);
|
||||||
} catch (MalformedMimeTypeException ex) {
|
}
|
||||||
throw new RuntimeException(ex);
|
catch (MalformedMimeTypeException ex) {
|
||||||
}
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Provider(Context context) {
|
public Provider(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
|
|
||||||
MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
|
MediaRouteDescriptor routeDescriptor = new MediaRouteDescriptor.Builder(
|
||||||
ROUTE_ID, context.getResources().getString(R.string.local_device))
|
ROUTE_ID, context.getResources().getString(R.string.local_device))
|
||||||
.addControlFilters(CONTROL_FILTERS)
|
.addControlFilters(CONTROL_FILTERS)
|
||||||
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
|
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
|
||||||
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
|
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_VARIABLE)
|
||||||
.setVolume(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
|
.setVolume(mAudio.getStreamMaxVolume(AudioManager.STREAM_MUSIC))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
MediaRouteProviderDescriptor providerDescriptor =
|
MediaRouteProviderDescriptor providerDescriptor =
|
||||||
new MediaRouteProviderDescriptor.Builder()
|
new MediaRouteProviderDescriptor.Builder()
|
||||||
.addRoute(routeDescriptor)
|
.addRoute(routeDescriptor)
|
||||||
.build();
|
.build();
|
||||||
setDescriptor(providerDescriptor);
|
setDescriptor(providerDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RouteController onCreateRouteController(String routeId) {
|
public RouteController onCreateRouteController(String routeId) {
|
||||||
return new Controller(routeId, getContext());
|
return new Controller(routeId, getContext());
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,14 +4,14 @@ All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -36,8 +36,9 @@ public class ProviderService extends MediaRouteProviderService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaRouteProvider onCreateMediaRouteProvider() {
|
public MediaRouteProvider onCreateMediaRouteProvider() {
|
||||||
if (mProvider == null)
|
if (mProvider == null) {
|
||||||
mProvider = new Provider(this);
|
mProvider = new Provider(this);
|
||||||
|
}
|
||||||
return mProvider;
|
return mProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,17 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.mediarouter;
|
package com.github.nutomic.controldlna.mediarouter;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.teleal.cling.support.contentdirectory.DIDLParser;
|
|
||||||
import org.teleal.cling.support.model.DIDLContent;
|
|
||||||
import org.teleal.cling.support.model.DIDLObject;
|
|
||||||
import org.teleal.cling.support.model.item.Item;
|
|
||||||
import org.teleal.cling.support.model.item.MusicTrack;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
import android.app.Notification;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
|
@ -66,6 +55,17 @@ import com.github.nutomic.controldlna.gui.PreferencesActivity;
|
||||||
import com.github.nutomic.controldlna.gui.RouteFragment;
|
import com.github.nutomic.controldlna.gui.RouteFragment;
|
||||||
import com.github.nutomic.controldlna.utility.LoadImageTask;
|
import com.github.nutomic.controldlna.utility.LoadImageTask;
|
||||||
|
|
||||||
|
import org.teleal.cling.support.contentdirectory.DIDLParser;
|
||||||
|
import org.teleal.cling.support.model.DIDLContent;
|
||||||
|
import org.teleal.cling.support.model.DIDLObject;
|
||||||
|
import org.teleal.cling.support.model.item.Item;
|
||||||
|
import org.teleal.cling.support.model.item.MusicTrack;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Background service that handles media playback to a single UPNP media renderer.
|
* Background service that handles media playback to a single UPNP media renderer.
|
||||||
*
|
*
|
||||||
|
@ -120,22 +120,24 @@ public class MediaRouterPlayService extends Service {
|
||||||
new MediaRouter.Callback() {
|
new MediaRouter.Callback() {
|
||||||
@Override
|
@Override
|
||||||
public void onRouteRemoved(MediaRouter router, RouteInfo route) {
|
public void onRouteRemoved(MediaRouter router, RouteInfo route) {
|
||||||
if (route.equals(mCurrentRoute))
|
if (route.equals(mCurrentRoute)) {
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (!mBound && !mPollingStatus)
|
if (!mBound && !mPollingStatus) {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRouteAdded(MediaRouter router, RouteInfo route) {
|
public void onRouteAdded(MediaRouter router, RouteInfo route) {
|
||||||
if (route.getId().equals(mCurrentRoute.getId())) {
|
if (route.getId().equals(mCurrentRoute.getId())) {
|
||||||
selectRoute(route);
|
selectRoute(route);
|
||||||
new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack)
|
new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack)
|
||||||
.getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class));
|
.getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a notification after the icon bitmap is loaded.
|
* Creates a notification after the icon bitmap is loaded.
|
||||||
|
@ -150,15 +152,16 @@ public class MediaRouterPlayService extends Service {
|
||||||
title = mPlaylist.get(mCurrentTrack).getTitle();
|
title = mPlaylist.get(mCurrentTrack).getTitle();
|
||||||
if (mPlaylist.get(mCurrentTrack) instanceof MusicTrack) {
|
if (mPlaylist.get(mCurrentTrack) instanceof MusicTrack) {
|
||||||
MusicTrack track = (MusicTrack) mPlaylist.get(mCurrentTrack);
|
MusicTrack track = (MusicTrack) mPlaylist.get(mCurrentTrack);
|
||||||
if (track.getArtists().length > 0)
|
if (track.getArtists().length > 0) {
|
||||||
artist = track.getArtists()[0].getName();
|
artist = track.getArtists()[0].getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Intent intent = new Intent(MediaRouterPlayService.this, MainActivity.class);
|
Intent intent = new Intent(MediaRouterPlayService.this, MainActivity.class);
|
||||||
intent.setAction("showRouteFragment");
|
intent.setAction("showRouteFragment");
|
||||||
Notification notification = new NotificationCompat.Builder(MediaRouterPlayService.this)
|
Notification notification = new NotificationCompat.Builder(MediaRouterPlayService.this)
|
||||||
.setContentIntent(PendingIntent.getActivity(MediaRouterPlayService.this, 0,
|
.setContentIntent(PendingIntent.getActivity(MediaRouterPlayService.this, 0,
|
||||||
intent, 0))
|
intent, 0))
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setContentText(artist)
|
.setContentText(artist)
|
||||||
.setLargeIcon(result)
|
.setLargeIcon(result)
|
||||||
|
@ -170,35 +173,35 @@ public class MediaRouterPlayService extends Service {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listens for incoming phone calls and pauses playback then.
|
* Listens for incoming phone calls and pauses playback then.
|
||||||
*/
|
*/
|
||||||
private class PhoneCallListener extends PhoneStateListener {
|
private class PhoneCallListener extends PhoneStateListener {
|
||||||
|
|
||||||
private boolean mPausedForCall = false;
|
private boolean mPausedForCall = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCallStateChanged(int state, String incomingNumber) {
|
public void onCallStateChanged(int state, String incomingNumber) {
|
||||||
|
|
||||||
if (!PreferenceManager.getDefaultSharedPreferences(MediaRouterPlayService.this)
|
if (!PreferenceManager.getDefaultSharedPreferences(MediaRouterPlayService.this)
|
||||||
.getBoolean(PreferencesActivity.KEY_INCOMING_PHONE_CALL_PAUSE, true)) {
|
.getBoolean(PreferencesActivity.KEY_INCOMING_PHONE_CALL_PAUSE, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TelephonyManager.CALL_STATE_RINGING == state ||
|
if (TelephonyManager.CALL_STATE_RINGING == state ||
|
||||||
TelephonyManager.CALL_STATE_OFFHOOK == state) {
|
TelephonyManager.CALL_STATE_OFFHOOK == state) {
|
||||||
// phone ringing or call active
|
// phone ringing or call active
|
||||||
pause();
|
pause();
|
||||||
mPausedForCall = true;
|
mPausedForCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPausedForCall && TelephonyManager.CALL_STATE_IDLE == state) {
|
if (mPausedForCall && TelephonyManager.CALL_STATE_IDLE == state) {
|
||||||
// run when class initial and phone call ended
|
// run when class initial and phone call ended
|
||||||
resume();
|
resume();
|
||||||
mPausedForCall = false;
|
mPausedForCall = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
|
@ -206,11 +209,10 @@ public class MediaRouterPlayService extends Service {
|
||||||
mMediaRouter = MediaRouter.getInstance(this);
|
mMediaRouter = MediaRouter.getInstance(this);
|
||||||
pollStatus();
|
pollStatus();
|
||||||
|
|
||||||
PhoneCallListener phoneListener = new PhoneCallListener();
|
PhoneCallListener phoneListener = new PhoneCallListener();
|
||||||
TelephonyManager telephonyManager = (TelephonyManager) this
|
TelephonyManager telephonyManager =
|
||||||
.getSystemService(Context.TELEPHONY_SERVICE);
|
(TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
telephonyManager.listen(phoneListener,
|
telephonyManager.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
|
||||||
PhoneStateListener.LISTEN_CALL_STATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -225,8 +227,9 @@ public class MediaRouterPlayService extends Service {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean onUnbind(Intent intent) {
|
public boolean onUnbind(Intent intent) {
|
||||||
if (!mPollingStatus)
|
if (!mPollingStatus) {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
|
}
|
||||||
mBound = false;
|
mBound = false;
|
||||||
return super.onUnbind(intent);
|
return super.onUnbind(intent);
|
||||||
}
|
}
|
||||||
|
@ -239,8 +242,8 @@ public class MediaRouterPlayService extends Service {
|
||||||
mMediaRouter.removeCallback(mRouteRemovedCallback);
|
mMediaRouter.removeCallback(mRouteRemovedCallback);
|
||||||
mMediaRouter.selectRoute(route);
|
mMediaRouter.selectRoute(route);
|
||||||
MediaRouteSelector selector = new MediaRouteSelector.Builder()
|
MediaRouteSelector selector = new MediaRouteSelector.Builder()
|
||||||
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
|
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
mMediaRouter.addCallback(selector, mRouteRemovedCallback, 0);
|
mMediaRouter.addCallback(selector, mRouteRemovedCallback, 0);
|
||||||
mCurrentRoute = route;
|
mCurrentRoute = route;
|
||||||
|
@ -287,8 +290,9 @@ public class MediaRouterPlayService extends Service {
|
||||||
new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack)
|
new CreateNotificationTask().execute(mPlaylist.get(mCurrentTrack)
|
||||||
.getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class));
|
.getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class));
|
||||||
|
|
||||||
if (mRouterFragment.get() != null)
|
if (mRouterFragment.get() != null) {
|
||||||
mRouterFragment.get().scrollToCurrent();
|
mRouterFragment.get().scrollToCurrent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -347,8 +351,7 @@ public class MediaRouterPlayService extends Service {
|
||||||
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
|
intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
|
||||||
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
|
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mSessionId);
|
||||||
intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, mItemId);
|
intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, mItemId);
|
||||||
intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION,
|
intent.putExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, (long) seconds * 1000);
|
||||||
(long) seconds * 1000);
|
|
||||||
mMediaRouter.getSelectedRoute().sendControlRequest(intent, null);
|
mMediaRouter.getSelectedRoute().sendControlRequest(intent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,6 +361,9 @@ public class MediaRouterPlayService extends Service {
|
||||||
* @param playlist The media files in the playlist.
|
* @param playlist The media files in the playlist.
|
||||||
*/
|
*/
|
||||||
public void setPlaylist(List<Item> playlist) {
|
public void setPlaylist(List<Item> playlist) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mPlaylist = playlist;
|
mPlaylist = playlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,8 +395,9 @@ public class MediaRouterPlayService extends Service {
|
||||||
else {
|
else {
|
||||||
// Playlist over, stop playback.
|
// Playlist over, stop playback.
|
||||||
stop();
|
stop();
|
||||||
if (!mBound)
|
if (!mBound) {
|
||||||
stopSelf();
|
stopSelf();
|
||||||
|
}
|
||||||
mPollingStatus = false;
|
mPollingStatus = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -404,11 +411,13 @@ public class MediaRouterPlayService extends Service {
|
||||||
if (mCurrentTrack == -1)
|
if (mCurrentTrack == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mShuffle)
|
if (mShuffle) {
|
||||||
// Play random item.
|
// Play random item.
|
||||||
play(new Random().nextInt(mPlaylist.size()));
|
play(new Random().nextInt(mPlaylist.size()));
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
play(mCurrentTrack - 1);
|
play(mCurrentTrack - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -437,16 +446,19 @@ public class MediaRouterPlayService extends Service {
|
||||||
if (status == null)
|
if (status == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mRouterFragment.get() != null)
|
if (mRouterFragment.get() != null) {
|
||||||
mRouterFragment.get().receivePlaybackStatus(status);
|
mRouterFragment.get().receivePlaybackStatus(status);
|
||||||
|
}
|
||||||
if (status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PENDING &&
|
if (status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PENDING &&
|
||||||
status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_BUFFERING &&
|
status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_BUFFERING &&
|
||||||
status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PLAYING)
|
status.getPlaybackState() != MediaItemStatus.PLAYBACK_STATE_PLAYING) {
|
||||||
stopForeground(true);
|
stopForeground(true);
|
||||||
|
}
|
||||||
|
|
||||||
if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED ||
|
if (status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_FINISHED ||
|
||||||
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_CANCELED)
|
status.getPlaybackState() == MediaItemStatus.PLAYBACK_STATE_CANCELED) {
|
||||||
playNext();
|
playNext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
|
|
@ -4,14 +4,14 @@ All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,12 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.upnp;
|
package com.github.nutomic.controldlna.upnp;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
@ -54,10 +48,17 @@ import android.support.v7.media.MediaRouteProvider;
|
||||||
import android.support.v7.media.MediaRouteProviderDescriptor.Builder;
|
import android.support.v7.media.MediaRouteProviderDescriptor.Builder;
|
||||||
import android.support.v7.media.MediaRouter;
|
import android.support.v7.media.MediaRouter;
|
||||||
import android.support.v7.media.MediaRouter.ControlRequestCallback;
|
import android.support.v7.media.MediaRouter.ControlRequestCallback;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows playing to a DLNA renderer from a remote app.
|
* Allows playing to a DLNA renderer from a remote app.
|
||||||
*
|
*
|
||||||
|
@ -65,6 +66,8 @@ import android.widget.Toast;
|
||||||
*/
|
*/
|
||||||
final class Provider extends MediaRouteProvider {
|
final class Provider extends MediaRouteProvider {
|
||||||
|
|
||||||
|
private static final String TAG = "Provider";
|
||||||
|
|
||||||
// Device has been added.
|
// Device has been added.
|
||||||
// param: Device device
|
// param: Device device
|
||||||
public static final int MSG_RENDERER_ADDED = 1;
|
public static final int MSG_RENDERER_ADDED = 1;
|
||||||
|
@ -93,8 +96,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
public int volume;
|
public int volume;
|
||||||
public int volumeMax;
|
public int volumeMax;
|
||||||
|
|
||||||
public static final Parcelable.Creator<Device> CREATOR
|
public static final Parcelable.Creator<Device> CREATOR =
|
||||||
= new Parcelable.Creator<Device>() {
|
new Parcelable.Creator<Device>() {
|
||||||
public Device createFromParcel(Parcel in) {
|
public Device createFromParcel(Parcel in) {
|
||||||
return new Device(in);
|
return new Device(in);
|
||||||
}
|
}
|
||||||
|
@ -187,8 +190,9 @@ final class Provider extends MediaRouteProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
if (mService.get() != null)
|
if (mService.get() != null) {
|
||||||
mService.get().handleMessage(msg);
|
mService.get().handleMessage(msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,11 +200,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
|
|
||||||
public Provider(Context context) {
|
public Provider(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
context.bindService(
|
context.bindService(new Intent(context, RemotePlayService.class),
|
||||||
new Intent(context, RemotePlayService.class),
|
mConnection, Context.BIND_AUTO_CREATE);
|
||||||
mConnection,
|
|
||||||
Context.BIND_AUTO_CREATE
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close() {
|
public void close() {
|
||||||
|
@ -210,9 +211,11 @@ final class Provider extends MediaRouteProvider {
|
||||||
@Override
|
@Override
|
||||||
public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
|
public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
|
||||||
try {
|
try {
|
||||||
if (request != null && request.isActiveScan() && mIRemotePlayService != null)
|
if (request != null && request.isActiveScan() && mIRemotePlayService != null) {
|
||||||
mIRemotePlayService.startSearch(mListener);
|
mIRemotePlayService.startSearch(mListener);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
|
}
|
||||||
|
catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +262,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
public void onSelect() {
|
public void onSelect() {
|
||||||
try {
|
try {
|
||||||
mIRemotePlayService.selectRenderer(mRouteId);
|
mIRemotePlayService.selectRenderer(mRouteId);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
|
catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +272,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
public void onUnselect() {
|
public void onUnselect() {
|
||||||
try {
|
try {
|
||||||
mIRemotePlayService.unselectRenderer(mRouteId);
|
mIRemotePlayService.unselectRenderer(mRouteId);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
|
catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -280,7 +285,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mIRemotePlayService.setVolume(volume);
|
mIRemotePlayService.setVolume(volume);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
|
catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
mDevices.get(mRouteId).volume = volume;
|
mDevices.get(mRouteId).volume = volume;
|
||||||
|
@ -301,13 +307,13 @@ final class Provider extends MediaRouteProvider {
|
||||||
if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) {
|
if (intent.getAction().equals(MediaControlIntent.ACTION_PLAY)) {
|
||||||
String metadata = (intent.hasExtra(MediaControlIntent.EXTRA_ITEM_METADATA))
|
String metadata = (intent.hasExtra(MediaControlIntent.EXTRA_ITEM_METADATA))
|
||||||
? intent.getExtras().getString(MediaControlIntent.EXTRA_ITEM_METADATA)
|
? intent.getExtras().getString(MediaControlIntent.EXTRA_ITEM_METADATA)
|
||||||
: null;
|
: null;
|
||||||
mIRemotePlayService.play(intent.getDataString(), metadata);
|
mIRemotePlayService.play(intent.getDataString(), metadata);
|
||||||
// Store in intent extras for later.
|
// Store in intent extras for later.
|
||||||
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mRouteId);
|
intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mRouteId);
|
||||||
intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, intent.getDataString());
|
intent.putExtra(MediaControlIntent.EXTRA_ITEM_ID, intent.getDataString());
|
||||||
getItemStatus(intent, callback);
|
getItemStatus(intent, callback);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) {
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_PAUSE)) {
|
||||||
mIRemotePlayService.pause(mRouteId);
|
mIRemotePlayService.pause(mRouteId);
|
||||||
|
@ -323,10 +329,8 @@ final class Provider extends MediaRouteProvider {
|
||||||
}
|
}
|
||||||
else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) {
|
else if (intent.getAction().equals(MediaControlIntent.ACTION_SEEK)) {
|
||||||
mIRemotePlayService.seek(mRouteId,
|
mIRemotePlayService.seek(mRouteId,
|
||||||
intent.getStringExtra(
|
intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID),
|
||||||
MediaControlIntent.EXTRA_ITEM_ID),
|
intent.getLongExtra(MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0));
|
||||||
intent.getLongExtra(
|
|
||||||
MediaControlIntent.EXTRA_ITEM_CONTENT_POSITION, 0));
|
|
||||||
getItemStatus(intent, callback);
|
getItemStatus(intent, callback);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -334,8 +338,9 @@ final class Provider extends MediaRouteProvider {
|
||||||
getItemStatus(intent, callback);
|
getItemStatus(intent, callback);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
e.printStackTrace();
|
catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Failed to execute control request", e);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -357,8 +362,7 @@ final class Provider extends MediaRouteProvider {
|
||||||
mRequests.put(r, pair);
|
mRequests.put(r, pair);
|
||||||
mIRemotePlayService.getItemStatus(
|
mIRemotePlayService.getItemStatus(
|
||||||
intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID),
|
intent.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID),
|
||||||
intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID),
|
intent.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID), r);
|
||||||
r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -382,12 +386,14 @@ final class Provider extends MediaRouteProvider {
|
||||||
mRequests.get(data.getInt("hash"));
|
mRequests.get(data.getInt("hash"));
|
||||||
Bundle status = data.getBundle("media_item_status");
|
Bundle status = data.getBundle("media_item_status");
|
||||||
|
|
||||||
if (pair.first.hasExtra(MediaControlIntent.EXTRA_SESSION_ID))
|
if (pair.first.hasExtra(MediaControlIntent.EXTRA_SESSION_ID)) {
|
||||||
status.putString(MediaControlIntent.EXTRA_SESSION_ID,
|
status.putString(MediaControlIntent.EXTRA_SESSION_ID,
|
||||||
pair.first.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID));
|
pair.first.getStringExtra(MediaControlIntent.EXTRA_SESSION_ID));
|
||||||
if (pair.first.hasExtra(MediaControlIntent.EXTRA_ITEM_ID))
|
}
|
||||||
|
if (pair.first.hasExtra(MediaControlIntent.EXTRA_ITEM_ID)) {
|
||||||
status.putString(MediaControlIntent.EXTRA_ITEM_ID,
|
status.putString(MediaControlIntent.EXTRA_ITEM_ID,
|
||||||
pair.first.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID));
|
pair.first.getStringExtra(MediaControlIntent.EXTRA_ITEM_ID));
|
||||||
|
}
|
||||||
pair.second.onResult(status);
|
pair.second.onResult(status);
|
||||||
break;
|
break;
|
||||||
case MSG_ERROR:
|
case MSG_ERROR:
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -36,8 +36,9 @@ public class ProviderService extends MediaRouteProviderService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaRouteProvider onCreateMediaRouteProvider() {
|
public MediaRouteProvider onCreateMediaRouteProvider() {
|
||||||
if (mProvider == null)
|
if (mProvider == null) {
|
||||||
mProvider = new Provider(this);
|
mProvider = new Provider(this);
|
||||||
|
}
|
||||||
return mProvider;
|
return mProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -87,11 +87,14 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
mUpnpService = (AndroidUpnpService) service;
|
mUpnpService = (AndroidUpnpService) service;
|
||||||
mUpnpService.getRegistry().addListener(RemotePlayService.this);
|
mUpnpService.getRegistry().addListener(RemotePlayService.this);
|
||||||
for (Device<?, ?, ?> d : mUpnpService.getControlPoint().getRegistry().getDevices())
|
for (Device<?, ?, ?> d : mUpnpService.getControlPoint().getRegistry().getDevices()) {
|
||||||
if (d instanceof LocalDevice)
|
if (d instanceof LocalDevice) {
|
||||||
localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d);
|
localDeviceAdded(mUpnpService.getRegistry(), (LocalDevice) d);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d);
|
remoteDeviceAdded(mUpnpService.getRegistry(), (RemoteDevice) d);
|
||||||
|
}
|
||||||
|
}
|
||||||
mUpnpService.getControlPoint().search();
|
mUpnpService.getControlPoint().search();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,11 +122,8 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
bindService(
|
bindService(new Intent(this, AndroidUpnpServiceImpl.class),
|
||||||
new Intent(this, AndroidUpnpServiceImpl.class),
|
mUpnpServiceConnection, Context.BIND_AUTO_CREATE);
|
||||||
mUpnpServiceConnection,
|
|
||||||
Context.BIND_AUTO_CREATE
|
|
||||||
);
|
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter();
|
IntentFilter filter = new IntentFilter();
|
||||||
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||||
|
@ -144,7 +144,8 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
void sendMessage(Message msg) {
|
void sendMessage(Message msg) {
|
||||||
try {
|
try {
|
||||||
mListener.send(msg);
|
mListener.send(msg);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
|
catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,21 +174,28 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
|
|
||||||
if (wifi.isConnected()) {
|
if (wifi.isConnected()) {
|
||||||
if (mUpnpService != null) {
|
if (mUpnpService != null) {
|
||||||
for (Device<?, ?, ?> d : mUpnpService.getControlPoint().getRegistry().getDevices())
|
for (Device<?, ?, ?> d :
|
||||||
|
mUpnpService.getControlPoint().getRegistry().getDevices()) {
|
||||||
deviceAdded(d);
|
deviceAdded(d);
|
||||||
|
}
|
||||||
mUpnpService.getControlPoint().search();
|
mUpnpService.getControlPoint().search();
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
for (Entry<String, Device<?, ?, ?>> d : mDevices.entrySet())
|
else {
|
||||||
|
for (Entry<String, Device<?, ?, ?>> d : mDevices.entrySet()) {
|
||||||
if (mUpnpService.getControlPoint().getRegistry()
|
if (mUpnpService.getControlPoint().getRegistry()
|
||||||
.getDevice(new UDN(d.getKey()), false) == null) {
|
.getDevice(new UDN(d.getKey()), false) == null) {
|
||||||
deviceRemoved(d.getValue());
|
deviceRemoved(d.getValue());
|
||||||
for (RemotePlayServiceBinder b : mBinders.keySet())
|
for (RemotePlayServiceBinder b : mBinders.keySet()) {
|
||||||
if (b.mCurrentRenderer != null && b.mCurrentRenderer.equals(d.getValue())) {
|
if (b.mCurrentRenderer != null &&
|
||||||
|
b.mCurrentRenderer.equals(d.getValue())) {
|
||||||
b.mSubscriptionCallback.end();
|
b.mSubscriptionCallback.end();
|
||||||
b.mCurrentRenderer = null;
|
b.mCurrentRenderer = null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -196,8 +204,7 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
*/
|
*/
|
||||||
org.teleal.cling.model.meta.Service<?, ?> getService(
|
org.teleal.cling.model.meta.Service<?, ?> getService(
|
||||||
Device<?, ?, ?> device, String name) {
|
Device<?, ?, ?> device, String name) {
|
||||||
return device.findService(
|
return device.findService(new ServiceType("schemas-upnp-org", name));
|
||||||
new ServiceType("schemas-upnp-org", name));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -207,8 +214,7 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
if (mDevices.containsValue(device))
|
if (mDevices.containsValue(device))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
final org.teleal.cling.model.meta.Service<?, ?> rc =
|
final org.teleal.cling.model.meta.Service<?, ?> rc = getService(device, "RenderingControl");
|
||||||
getService(device, "RenderingControl");
|
|
||||||
if (rc == null || mListener == null)
|
if (rc == null || mListener == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -233,7 +239,8 @@ public class RemotePlayService extends Service implements RegistryListener {
|
||||||
int maxVolume = 100;
|
int maxVolume = 100;
|
||||||
if (rc.getStateVariable("Volume") != null) {
|
if (rc.getStateVariable("Volume") != null) {
|
||||||
StateVariableAllowedValueRange volumeRange =
|
StateVariableAllowedValueRange volumeRange =
|
||||||
rc.getStateVariable("Volume").getTypeDetails().getAllowedValueRange();
|
rc.getStateVariable("Volume")
|
||||||
|
.getTypeDetails().getAllowedValueRange();
|
||||||
maxVolume = (int) volumeRange.getMaximum();
|
maxVolume = (int) volumeRange.getMaximum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -83,26 +83,27 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
private RemotePlayService mRps;
|
private RemotePlayService mRps;
|
||||||
|
|
||||||
private boolean mStartingPlayback = false;
|
private boolean mStartingPlayback = false;
|
||||||
|
|
||||||
public RemotePlayServiceBinder(RemotePlayService rps) {
|
public RemotePlayServiceBinder(RemotePlayService rps) {
|
||||||
mRps = rps;
|
mRps = rps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startSearch(Messenger listener)
|
public void startSearch(Messenger listener) throws RemoteException {
|
||||||
throws RemoteException {
|
|
||||||
mRps.mListener = listener;
|
mRps.mListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selectRenderer(String id) throws RemoteException {
|
public void selectRenderer(String id) throws RemoteException {
|
||||||
mCurrentRenderer = mRps.mDevices.get(id);
|
mCurrentRenderer = mRps.mDevices.get(id);
|
||||||
for (RemotePlayServiceBinder b : mRps.mBinders.keySet())
|
for (RemotePlayServiceBinder b : mRps.mBinders.keySet()) {
|
||||||
if (b != this && mCurrentRenderer.equals(b.mCurrentRenderer))
|
if (b != this && mCurrentRenderer.equals(b.mCurrentRenderer)) {
|
||||||
b.unselectRenderer("");
|
b.unselectRenderer("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mSubscriptionCallback = new SubscriptionCallback(
|
mSubscriptionCallback = new SubscriptionCallback(mCurrentRenderer.findService(
|
||||||
mCurrentRenderer.findService(
|
new ServiceType("schemas-upnp-org", "AVTransport")), 600) {
|
||||||
new ServiceType("schemas-upnp-org", "AVTransport")), 600) {
|
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
|
@ -111,8 +112,7 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
protected void ended(GENASubscription sub, CancelReason reason,
|
protected void ended(GENASubscription sub, CancelReason reason, UpnpResponse response) {
|
||||||
UpnpResponse response) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
|
@ -121,16 +121,14 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, StateVariableValue> m = sub.getCurrentValues();
|
Map<String, StateVariableValue> m = sub.getCurrentValues();
|
||||||
try {
|
try {
|
||||||
LastChange lastChange = new LastChange(
|
LastChange lastChange = new LastChange(new AVTransportLastChangeParser(),
|
||||||
new AVTransportLastChangeParser(),
|
|
||||||
m.get("LastChange").toString());
|
m.get("LastChange").toString());
|
||||||
if (mStartingPlayback || lastChange.getEventedValue(0,
|
if (mStartingPlayback || lastChange.getEventedValue(0,
|
||||||
AVTransportVariable.TransportState.class) == null)
|
AVTransportVariable.TransportState.class) == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (lastChange.getEventedValue(0,
|
switch (lastChange.getEventedValue(0,
|
||||||
AVTransportVariable.TransportState.class)
|
AVTransportVariable.TransportState.class).getValue()) {
|
||||||
.getValue()) {
|
|
||||||
case PLAYING:
|
case PLAYING:
|
||||||
mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
||||||
break;
|
break;
|
||||||
|
@ -149,7 +147,8 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e) {
|
||||||
Log.w(TAG, "Failed to parse UPNP event", e);
|
Log.w(TAG, "Failed to parse UPNP event", e);
|
||||||
mRps.sendError("Failed to parse UPNP event");
|
mRps.sendError("Failed to parse UPNP event");
|
||||||
}
|
}
|
||||||
|
@ -157,8 +156,7 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
protected void eventsMissed(GENASubscription sub,
|
protected void eventsMissed(GENASubscription sub, int numberOfMissedEvents) {
|
||||||
int numberOfMissedEvents) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
|
@ -177,10 +175,12 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void unselectRenderer(String sessionId) throws RemoteException {
|
public void unselectRenderer(String sessionId) throws RemoteException {
|
||||||
if (mRps.mDevices.get(sessionId) != null)
|
if (mRps.mDevices.get(sessionId) != null) {
|
||||||
stop(sessionId);
|
stop(sessionId);
|
||||||
if (mSubscriptionCallback != null)
|
}
|
||||||
|
if (mSubscriptionCallback != null) {
|
||||||
mSubscriptionCallback.end();
|
mSubscriptionCallback.end();
|
||||||
|
}
|
||||||
mCurrentRenderer = null;
|
mCurrentRenderer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,19 +246,19 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
new Play(mRps.getService(mCurrentRenderer,
|
new Play(mRps.getService(mCurrentRenderer,
|
||||||
"AVTransport")) {
|
"AVTransport")) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void success(ActionInvocation invocation) {
|
public void success(ActionInvocation invocation) {
|
||||||
mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
mPlaybackState = MediaItemStatus.PLAYBACK_STATE_PLAYING;
|
||||||
mStartingPlayback = false;
|
mStartingPlayback = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void failure(ActionInvocation invocation,
|
public void failure(ActionInvocation invocation,
|
||||||
UpnpResponse operation, String defaultMessage) {
|
UpnpResponse operation, String defaultMessage) {
|
||||||
Log.w(TAG, "Play failed: " + defaultMessage);
|
Log.w(TAG, "Play failed: " + defaultMessage);
|
||||||
mRps.sendError("Play failed: " + defaultMessage);
|
mRps.sendError("Play failed: " + defaultMessage);
|
||||||
mStartingPlayback = false;
|
mStartingPlayback = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -284,8 +284,10 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
// Sometimes stop works even though pause does not.
|
// Sometimes stop works even though pause does not.
|
||||||
try {
|
try {
|
||||||
stop(sessionId);
|
stop(sessionId);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
e.printStackTrace();
|
catch (RemoteException e) {
|
||||||
|
Log.w(TAG, "Calling stop failed", e);
|
||||||
|
mRps.sendError("Calling stop failed: " + e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -372,6 +374,7 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
public void failure(ActionInvocation invocation,
|
public void failure(ActionInvocation invocation,
|
||||||
UpnpResponse operation, String defaultMessage) {
|
UpnpResponse operation, String defaultMessage) {
|
||||||
Log.w(TAG, "Get position failed: " + defaultMessage);
|
Log.w(TAG, "Get position failed: " + defaultMessage);
|
||||||
|
mRps.sendError("Get position failed: " + defaultMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
|
@ -381,17 +384,20 @@ public class RemotePlayServiceBinder extends IRemotePlayService.Stub {
|
||||||
Message msg = Message.obtain(null, Provider.MSG_STATUS_INFO, 0, 0);
|
Message msg = Message.obtain(null, Provider.MSG_STATUS_INFO, 0, 0);
|
||||||
Builder status = null;
|
Builder status = null;
|
||||||
|
|
||||||
status = new MediaItemStatus.Builder(mPlaybackState);
|
status = new MediaItemStatus.Builder(mPlaybackState);
|
||||||
if (positionInfo.getTrackURI() != null && positionInfo.getTrackURI().equals(itemId)) {
|
if (positionInfo.getTrackURI() != null &&
|
||||||
try {
|
positionInfo.getTrackURI().equals(itemId)) {
|
||||||
status.setContentPosition(positionInfo.getTrackElapsedSeconds() * 1000)
|
try {
|
||||||
.setContentDuration(positionInfo.getTrackDurationSeconds() * 1000)
|
status.setContentPosition(positionInfo.getTrackElapsedSeconds() * 1000)
|
||||||
.setTimestamp(positionInfo.getAbsCount());
|
.setContentDuration(positionInfo.getTrackDurationSeconds() * 1000)
|
||||||
}
|
.setTimestamp(positionInfo.getAbsCount());
|
||||||
catch (NumberFormatException e) {
|
}
|
||||||
Log.d(TAG, "Failed to read track position or duration", e);
|
catch (NumberFormatException e) {
|
||||||
}
|
Log.d(TAG, "Failed to read track position or duration", e);
|
||||||
}
|
mRps.sendError("Failed to read track position or duration: " +
|
||||||
|
e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
msg.getData().putBundle("media_item_status", status.build().asBundle());
|
msg.getData().putBundle("media_item_status", status.build().asBundle());
|
||||||
msg.getData().putInt("hash", requestHash);
|
msg.getData().putInt("hash", requestHash);
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -27,16 +27,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
package com.github.nutomic.controldlna.utility;
|
package com.github.nutomic.controldlna.utility;
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import org.teleal.cling.model.meta.Device;
|
|
||||||
import org.teleal.cling.model.meta.LocalDevice;
|
|
||||||
import org.teleal.cling.model.meta.RemoteDevice;
|
|
||||||
import org.teleal.cling.registry.Registry;
|
|
||||||
import org.teleal.cling.registry.RegistryListener;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -48,6 +38,16 @@ import android.widget.TextView;
|
||||||
|
|
||||||
import com.github.nutomic.controldlna.R;
|
import com.github.nutomic.controldlna.R;
|
||||||
|
|
||||||
|
import org.teleal.cling.model.meta.Device;
|
||||||
|
import org.teleal.cling.model.meta.LocalDevice;
|
||||||
|
import org.teleal.cling.model.meta.RemoteDevice;
|
||||||
|
import org.teleal.cling.registry.Registry;
|
||||||
|
import org.teleal.cling.registry.RegistryListener;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays the devices that are inserted through the RegistryListener (either
|
* Displays the devices that are inserted through the RegistryListener (either
|
||||||
* of type RENDERER or SERVER).
|
* of type RENDERER or SERVER).
|
||||||
|
@ -60,8 +60,6 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
|
||||||
|
|
||||||
private static final String TAG = "DeviceArrayAdapter";
|
private static final String TAG = "DeviceArrayAdapter";
|
||||||
|
|
||||||
public static final String RENDERER = "MediaRenderer";
|
|
||||||
|
|
||||||
public static final String SERVER = "MediaServer";
|
public static final String SERVER = "MediaServer";
|
||||||
|
|
||||||
private Activity mActivity;
|
private Activity mActivity;
|
||||||
|
@ -91,15 +89,16 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
|
||||||
|
|
||||||
if (getItem(position).hasIcons()) {
|
if (getItem(position).hasIcons()) {
|
||||||
URI uri = getItem(position).getIcons()[0].getUri();
|
URI uri = getItem(position).getIcons()[0].getUri();
|
||||||
if (getItem(position) instanceof RemoteDevice)
|
if (getItem(position) instanceof RemoteDevice) {
|
||||||
try {
|
try {
|
||||||
RemoteDevice device = (RemoteDevice) getItem(position);
|
RemoteDevice device = (RemoteDevice) getItem(position);
|
||||||
uri = device.normalizeURI(uri).toURI();
|
uri = device.normalizeURI(uri).toURI();
|
||||||
} catch (URISyntaxException e) {
|
}
|
||||||
|
catch (URISyntaxException e) {
|
||||||
Log.w(TAG, "Failed to get device icon URI", e);
|
Log.w(TAG, "Failed to get device icon URI", e);
|
||||||
}
|
}
|
||||||
RemoteImageView icon =
|
}
|
||||||
(RemoteImageView) convertView.findViewById(R.id.image);
|
RemoteImageView icon = (RemoteImageView) convertView.findViewById(R.id.image);
|
||||||
icon.setImageUri(uri);
|
icon.setImageUri(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,9 +109,11 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
|
||||||
* Adds a new device to the list if its type equals mDeviceType.
|
* Adds a new device to the list if its type equals mDeviceType.
|
||||||
*/
|
*/
|
||||||
public void deviceAdded(final Device<?, ?, ?> device) {
|
public void deviceAdded(final Device<?, ?, ?> device) {
|
||||||
for (int i = 0; i < getCount(); i++)
|
for (int i = 0; i < getCount(); i++) {
|
||||||
if (getItem(i).equals(device))
|
if (getItem(i).equals(device)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mActivity.runOnUiThread(new Runnable() {
|
mActivity.runOnUiThread(new Runnable() {
|
||||||
|
|
||||||
|
@ -141,8 +142,9 @@ public class DeviceArrayAdapter extends ArrayAdapter<Device<?, ?, ?>>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if (getPosition(device) != -1)
|
if (getPosition(device) != -1) {
|
||||||
remove(device);
|
remove(device);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -78,32 +78,38 @@ public class FileArrayAdapter extends ArrayAdapter<DIDLObject> {
|
||||||
MusicTrack track = (MusicTrack) item;
|
MusicTrack track = (MusicTrack) item;
|
||||||
String trackNumber = (track.getOriginalTrackNumber() != null)
|
String trackNumber = (track.getOriginalTrackNumber() != null)
|
||||||
? Integer.toString(track.getOriginalTrackNumber()) + ". "
|
? Integer.toString(track.getOriginalTrackNumber()) + ". "
|
||||||
: "";
|
: "";
|
||||||
title.setText(trackNumber + item.getTitle());
|
title.setText(trackNumber + item.getTitle());
|
||||||
if (track.getArtists().length > 0)
|
if (track.getArtists().length > 0) {
|
||||||
artist.setText(track.getArtists()[0].getName());
|
artist.setText(track.getArtists()[0].getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
title.setText(item.getTitle());
|
title.setText(item.getTitle());
|
||||||
|
}
|
||||||
|
|
||||||
RemoteImageView image = (RemoteImageView) convertView.findViewById(R.id.image);
|
RemoteImageView image = (RemoteImageView) convertView.findViewById(R.id.image);
|
||||||
URI icon = item.getFirstPropertyValue(
|
URI icon = item.getFirstPropertyValue(DIDLObject.Property.UPNP.ALBUM_ART_URI.class);
|
||||||
DIDLObject.Property.UPNP.ALBUM_ART_URI.class);
|
|
||||||
if (icon != null) {
|
if (icon != null) {
|
||||||
image.setImageUri(icon);
|
image.setImageUri(icon);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int resId;
|
int resId;
|
||||||
if (item instanceof AudioItem)
|
if (item instanceof AudioItem) {
|
||||||
resId = R.drawable.ic_doc_audio_am;
|
resId = R.drawable.ic_doc_audio_am;
|
||||||
else if (item instanceof VideoItem)
|
}
|
||||||
|
else if (item instanceof VideoItem) {
|
||||||
resId = R.drawable.ic_doc_video_am;
|
resId = R.drawable.ic_doc_video_am;
|
||||||
else if (item instanceof ImageItem)
|
}
|
||||||
|
else if (item instanceof ImageItem) {
|
||||||
resId = R.drawable.ic_doc_image;
|
resId = R.drawable.ic_doc_image;
|
||||||
else if (item instanceof PlaylistItem)
|
}
|
||||||
|
else if (item instanceof PlaylistItem) {
|
||||||
resId = R.drawable.ic_doc_album;
|
resId = R.drawable.ic_doc_album;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
resId = R.drawable.ic_root_folder_am;
|
resId = R.drawable.ic_root_folder_am;
|
||||||
|
}
|
||||||
image.setImageResource(resId);
|
image.setImageResource(resId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +120,9 @@ public class FileArrayAdapter extends ArrayAdapter<DIDLObject> {
|
||||||
* Replacement for addAll, which is not implemented on lower API levels.
|
* Replacement for addAll, which is not implemented on lower API levels.
|
||||||
*/
|
*/
|
||||||
public void add(List<Item> playlist) {
|
public void add(List<Item> playlist) {
|
||||||
for (DIDLObject d : playlist)
|
for (DIDLObject d : playlist) {
|
||||||
add(d);
|
add(d);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -40,7 +40,7 @@ import android.os.AsyncTask;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles background task of loading a bitmap by URI.
|
* Loads an image by URI in the background and returns it.
|
||||||
*
|
*
|
||||||
* @author Felix Ableitner
|
* @author Felix Ableitner
|
||||||
*
|
*
|
||||||
|
@ -56,15 +56,15 @@ public class LoadImageTask extends AsyncTask<URI, Void, Bitmap> {
|
||||||
|
|
||||||
Bitmap bm = null;
|
Bitmap bm = null;
|
||||||
try {
|
try {
|
||||||
URLConnection conn = new URL(uri[0].toString())
|
URLConnection conn = new URL(uri[0].toString()).openConnection();
|
||||||
.openConnection();
|
|
||||||
conn.connect();
|
conn.connect();
|
||||||
InputStream is = conn.getInputStream();
|
InputStream is = conn.getInputStream();
|
||||||
BufferedInputStream bis = new BufferedInputStream(is);
|
BufferedInputStream bis = new BufferedInputStream(is);
|
||||||
bm = BitmapFactory.decodeStream(bis);
|
bm = BitmapFactory.decodeStream(bis);
|
||||||
bis.close();
|
bis.close();
|
||||||
is.close();
|
is.close();
|
||||||
} catch (IOException e) {
|
}
|
||||||
|
catch (IOException e) {
|
||||||
Log.w(TAG, "Failed to load artwork image", e);
|
Log.w(TAG, "Failed to load artwork image", e);
|
||||||
}
|
}
|
||||||
return bm;
|
return bm;
|
||||||
|
|
|
@ -5,13 +5,13 @@ All rights reserved.
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
* Redistributions of source code must retain the above copyright
|
* Redistributions of source code must retain the above copyright
|
||||||
notice, this list of conditions and the following disclaimer.
|
notice, this list of conditions and the following disclaimer.
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in the
|
notice, this list of conditions and the following disclaimer in the
|
||||||
documentation and/or other materials provided with the distribution.
|
documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the <organization> nor the
|
* Neither the name of the <organization> nor the
|
||||||
names of its contributors may be used to endorse or promote products
|
names of its contributors may be used to endorse or promote products
|
||||||
derived from this software without specific prior written permission.
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
@ -52,8 +52,9 @@ public class RemoteImageView extends ImageView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPostExecute(Bitmap bm) {
|
protected void onPostExecute(Bitmap bm) {
|
||||||
if (bm != null)
|
if (bm != null) {
|
||||||
setImageBitmap(bm);
|
setImageBitmap(bm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,7 +41,7 @@ public class RouteAdapter extends ArrayAdapter<RouteInfo> {
|
||||||
public void add(List<RouteInfo> routes) {
|
public void add(List<RouteInfo> routes) {
|
||||||
for (RouteInfo r : routes) {
|
for (RouteInfo r : routes) {
|
||||||
add(r);
|
add(r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Reference in a new issue