diff options
author | Nikitas Stamatopoulos <nikitas.stamatopoulos@gmail.com> | 2013-02-17 15:28:48 -0500 |
---|---|---|
committer | Nikitas Stamatopoulos <nikitas.stamatopoulos@gmail.com> | 2013-02-17 20:08:58 -0500 |
commit | 004afab027fe500cb6ec91f63314e203cde02899 (patch) | |
tree | a3f83b0173cb404503bce5d7a33b666fe5ea5476 | |
parent | 91f6d4666d16d0a1c65e1eaafdb22da47eab1ee0 (diff) |
Added the AndroidRemote Extension
Added the Android App source code
46 files changed, 3998 insertions, 1 deletions
diff --git a/Extensions.sln b/Extensions.sln index 319fd61..d56b513 100644 --- a/Extensions.sln +++ b/Extensions.sln @@ -1,6 +1,8 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AndroidRemote", "src\AndroidRemote\AndroidRemote.csproj", "{ED1C6ABE-4BA3-4771-9419-CAA77D1BBFEF}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CueSheets", "src\CueSheets\CueSheets.csproj", "{}" EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DuplicateSongDetector", "src\DuplicateSongDetector\DuplicateSongDetector.csproj", "{1725FB8A-DF47-4CAF-A322-59EE97AAB5DE}"
@@ -90,6 +92,10 @@ Global Windows|Any CPU = Windows|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution + {ED1C6ABE-4BA3-4771-9419-CAA77D1BBFEF}.Debug|x86.ActiveCfg = Debug|Any CPU + {ED1C6ABE-4BA3-4771-9419-CAA77D1BBFEF}.Debug|x86.Build.0 = Debug|Any CPU + {ED1C6ABE-4BA3-4771-9419-CAA77D1BBFEF}.Release|x86.ActiveCfg = Release|Any CPU + {ED1C6ABE-4BA3-4771-9419-CAA77D1BBFEF}.Release|x86.Build.0 = Release|Any CPU {}.Debug|x86.ActiveCfg = Debug|Any CPU {}.Debug|x86.Build.0 = Debug|Any CPU {}.Release|x86.ActiveCfg = Release|Any CPU diff --git a/build/m4/extensions/androidremote.m4 b/build/m4/extensions/androidremote.m4 new file mode 100644 index 0000000..266d64d --- /dev/null +++ b/build/m4/extensions/androidremote.m4 @@ -0,0 +1,11 @@ +AC_DEFUN([BCE_ANDROIDREMOTE], +[ + BCE_ARG_DISABLE([AndroidRemote], [yes]) + + if test "x$enable_AndroidRemote" = "xyes"; then + AM_CONDITIONAL(ENABLE_ANDROIDREMOTE, true) + else + AM_CONDITIONAL(ENABLE_ANDROIDREMOTE, false) + fi +]) + diff --git a/configure.ac b/configure.ac index 2f5d99c..2282745 100644 --- a/configure.ac +++ b/configure.ac @@ -79,6 +79,7 @@ dnl Extensions BCE_ALARMCLOCK BCE_ALBUMARTWRITER BCE_AMPACHE +BCE_ANDROIDREMOTE BCE_APPINDICATOR BCE_AWN BCE_CLUTTERFLOW @@ -140,6 +141,7 @@ src/AssemblyInfo.cs src/AlarmClock/Makefile src/AlbumArtWriter/Makefile src/Ampache/Makefile +src/AndroidRemote/Makefile src/AppIndicator/Makefile src/Awn/Makefile src/ClutterFlow/Makefile @@ -207,6 +209,7 @@ ${PACKAGE}-${VERSION} Alarm Clock: ${enable_AlarmClock} AlbumArtWriter: ${enable_AlbumArtWriter} Ampache: ${enable_Ampache} + AndroidRemote: ${enable_AndroidRemote} AppIndicator: ${enable_AppIndicator} Awn: ${enable_Awn} ClutterFlow: ${enable_ClutterFlow} diff --git a/po/banshee-community-extensions.pot b/po/banshee-community-extensions.pot index aa716a0..e466fdf 100644 --- a/po/banshee-community-extensions.pot +++ b/po/banshee-community-extensions.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-01-13 10:20+0100\n" +"POT-Creation-Date: 2013-02-17 15:05-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" diff --git a/src/AndroidRemote/AndroidApp/.classpath b/src/AndroidRemote/AndroidApp/.classpath new file mode 100644 index 0000000..a4763d1 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> + <classpathentry kind="output" path="bin/classes"/> +</classpath> diff --git a/src/AndroidRemote/AndroidApp/.project b/src/AndroidRemote/AndroidApp/.project new file mode 100644 index 0000000..66744a5 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>BansheeRemote</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.ApkBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/src/AndroidRemote/AndroidApp/AndroidManifest.xml b/src/AndroidRemote/AndroidApp/AndroidManifest.xml new file mode 100644 index 0000000..43fc6a4 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/AndroidManifest.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.nstamato.bansheeremote" + android:versionCode="14" + android:versionName="4.2"> + <uses-sdk android:minSdkVersion="4" /> + <application android:icon="@drawable/banshee" android:label="Banshee Remote"> + <activity android:name=".BansheeRemote" android:label="Banshee Remote" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name=".Settings" android:label="Banshee Remote" android:configChanges="orientation|keyboardHidden"> + </activity> + <activity android:name=".ArtistBrowse" android:label="Artists" android:configChanges = "orientation|keyboardHidden" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + </activity> + <activity android:name=".AlbumBrowse" android:label="Artists" android:configChanges = "orientation|keyboardHidden" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + </activity> + <activity android:name=".SongBrowse" android:label="Artists" android:configChanges = "orientation|keyboardHidden" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + </activity> + <activity android:name=".Sync" android:label="Sync" android:configChanges = "orientation|keyboardHidden" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + </activity> + <activity android:name=".NewServer" android:label="Banshee Remote" android:configChanges="orientation|keyboardHidden"> + </activity> + <activity android:name=".main" android:label="Banshee Remote" android:launchMode="singleTask" android:theme="@android:style/Theme.NoTitleBar.Fullscreen"> + </activity> + </application> + + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> + + +<uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission> +</manifest>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/BansheeRemote.apk b/src/AndroidRemote/AndroidApp/BansheeRemote.apk Binary files differnew file mode 100644 index 0000000..e301c2b --- /dev/null +++ b/src/AndroidRemote/AndroidApp/BansheeRemote.apk diff --git a/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/BuildConfig.java b/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/BuildConfig.java new file mode 100644 index 0000000..75abf2f --- /dev/null +++ b/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/BuildConfig.java @@ -0,0 +1,6 @@ +/** Automatically generated file. DO NOT MODIFY */ +package org.nstamato.bansheeremote; + +public final class BuildConfig { + public final static boolean DEBUG = true; +}
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/R.java b/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/R.java new file mode 100644 index 0000000..ee844f6 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/gen/org/nstamato/bansheeremote/R.java @@ -0,0 +1,62 @@ +/* AUTO-GENERATED FILE. DO NOT MODIFY. + * + * This class was automatically generated by the + * aapt tool from the resource data it found. It + * should not be modified by hand. + */ + +package org.nstamato.bansheeremote; + +public final class R { + public static final class attr { + } + public static final class drawable { + public static final int album=0x7f020000; + public static final int artist=0x7f020001; + public static final int banshee=0x7f020002; + public static final int ic_menu_refresh=0x7f020003; + public static final int no_cover_art=0x7f020004; + public static final int seek_background=0x7f020005; + public static final int songs=0x7f020006; + } + public static final class id { + public static final int album=0x7f05000a; + public static final int albumArtist=0x7f050004; + public static final int albumBrowse=0x7f050002; + public static final int albumName=0x7f050003; + public static final int albums=0x7f05000d; + public static final int artist=0x7f050009; + public static final int artists=0x7f05000c; + public static final int cover=0x7f05000b; + public static final int icon=0x7f050000; + public static final int ip=0x7f050005; + public static final int next=0x7f050011; + public static final int playpause=0x7f050010; + public static final int port=0x7f050006; + public static final int prev=0x7f05000f; + public static final int seek_position=0x7f050013; + public static final int seek_total=0x7f050014; + public static final int seekbar=0x7f050012; + public static final int songArtist=0x7f050017; + public static final int songBrowse=0x7f050015; + public static final int songName=0x7f050016; + public static final int songs=0x7f05000e; + public static final int submit=0x7f050007; + public static final int title=0x7f050001; + public static final int track=0x7f050008; + } + public static final class layout { + public static final int album_browse=0x7f030000; + public static final int album_row_view=0x7f030001; + public static final int browse=0x7f030002; + public static final int init=0x7f030003; + public static final int list_item=0x7f030004; + public static final int main=0x7f030005; + public static final int song_browse=0x7f030006; + public static final int song_row_view=0x7f030007; + } + public static final class string { + public static final int app_name=0x7f040001; + public static final int hello=0x7f040000; + } +} diff --git a/src/AndroidRemote/AndroidApp/project.properties b/src/AndroidRemote/AndroidApp/project.properties new file mode 100644 index 0000000..2e98c5f --- /dev/null +++ b/src/AndroidRemote/AndroidApp/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system use, +# "ant.properties", and override values to adapt the script to your +# project structure. + +# Indicates whether an apk should be generated for each density. +split.density=false +# Project target. +target=android-10 +apk-configurations= diff --git a/src/AndroidRemote/AndroidApp/res/drawable/album.png b/src/AndroidRemote/AndroidApp/res/drawable/album.png Binary files differnew file mode 100644 index 0000000..647e059 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/album.png diff --git a/src/AndroidRemote/AndroidApp/res/drawable/artist.png b/src/AndroidRemote/AndroidApp/res/drawable/artist.png Binary files differnew file mode 100644 index 0000000..492247c --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/artist.png diff --git a/src/AndroidRemote/AndroidApp/res/drawable/banshee.png b/src/AndroidRemote/AndroidApp/res/drawable/banshee.png Binary files differnew file mode 100644 index 0000000..af4fbf4 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/banshee.png diff --git a/src/AndroidRemote/AndroidApp/res/drawable/ic_menu_refresh.png b/src/AndroidRemote/AndroidApp/res/drawable/ic_menu_refresh.png Binary files differnew file mode 100644 index 0000000..77d70dd --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/ic_menu_refresh.png diff --git a/src/AndroidRemote/AndroidApp/res/drawable/no_cover_art.jpg b/src/AndroidRemote/AndroidApp/res/drawable/no_cover_art.jpg Binary files differnew file mode 100644 index 0000000..4d2f2cd --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/no_cover_art.jpg diff --git a/src/AndroidRemote/AndroidApp/res/drawable/seek_background.xml b/src/AndroidRemote/AndroidApp/res/drawable/seek_background.xml new file mode 100644 index 0000000..3195f3f --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/seek_background.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:id="@android:id/background"> + <shape> + <corners android:radius="5dip" /> + <gradient + android:startColor="#ff9d9e9d" + android:centerColor="#ff5a5d5a" + android:centerY="0.75" + android:endColor="#ff747674" + android:angle="270" + /> + </shape> + </item> + + <item android:id="@android:id/secondaryProgress"> + <clip> + <shape> + <corners android:radius="5dip" /> + <gradient + android:startColor="#80ffd300" + android:centerColor="#80ffb600" + android:centerY="0.75" + android:endColor="#a0ffcb00" + android:angle="270" + /> + </shape> + </clip> + </item> + + <item android:id="@android:id/progress"> + <clip> + <shape android:shape="rectangle"> + <gradient android:startColor="#FFFFAA00" +android:endColor="#FFFF0000" + android:angle="0"/> + <stroke android:width="1dp" android:color="#AAFFFFFF" /> + <padding android:left="7dp" android:top="7dp" + android:right="7dp" android:bottom="7dp" /> + <corners android:radius="4dp" /> + </shape> + </clip> + </item> + +</layer-list>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/drawable/songs.png b/src/AndroidRemote/AndroidApp/res/drawable/songs.png Binary files differnew file mode 100644 index 0000000..c2c250b --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/drawable/songs.png diff --git a/src/AndroidRemote/AndroidApp/res/layout-land/main.xml b/src/AndroidRemote/AndroidApp/res/layout-land/main.xml new file mode 100644 index 0000000..208ef8f --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout-land/main.xml @@ -0,0 +1,219 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_horizontal" + > + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingLeft="0dip" + android:paddingTop="20px" + > + + +<ImageView + android:id="@+id/cover" + android:layout_width="200dip" + android:layout_height="200dip" + android:paddingRight="0dip" +/> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="vertical" + android:paddingLeft="0dip" + android:paddingTop="0px" + > + +<TextView + android:id="@+id/track" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Track name" + android:paddingTop="5dip" + android:paddingLeft="15dip" + android:textAppearance="?android:attr/textAppearanceLarge" + /> + +<TextView + android:id="@+id/artist" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Artist" + android:paddingLeft="15dip" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + + <TextView + android:id="@+id/album" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Album" + android:paddingLeft="15dip" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + + <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingRight="35dip" + android:paddingTop="20px" + > + + <ImageButton + android:id="@+id/next" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="18dip" android:paddingRight="10dip" + android:paddingTop="0dip" android:paddingBottom="0dip" + android:src="@android:drawable/ic_media_next" + android:layout_alignParentRight="true" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/playpause" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="18dip" android:paddingRight="18dip" + android:paddingTop="0dip" android:paddingBottom="0dip" + android:src="@android:drawable/ic_media_play" + android:layout_toLeftOf="@id/next" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/prev" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="0dip" android:paddingRight="18dip" + android:paddingTop="0dip" android:paddingBottom="0dip" + android:src="@android:drawable/ic_media_previous" + android:layout_toLeftOf="@id/playpause" + android:background="@null" + android:tint="#00000000" + /> + <!-- android:background="@null" --> + <ImageButton + android:id="@+id/songs" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="5dip" android:paddingRight="0dip" + android:paddingTop="20dip" android:paddingBottom="0dip" + android:src="@drawable/songs" + android:layout_alignParentRight="true" + android:layout_below="@id/next" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/albums" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="5dip" android:paddingRight="5dip" + android:paddingTop="20dip" android:paddingBottom="0dip" + android:src="@drawable/album" + android:layout_toLeftOf="@id/songs" + android:layout_below="@id/playpause" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/artists" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="0dip" android:paddingRight="5dip" + android:paddingTop="20dip" android:paddingBottom="0dip" + android:src="@drawable/artist" + android:layout_toLeftOf="@id/albums" + android:layout_below="@id/prev" + android:background="@null" + android:tint="#00000000" + /> + + +</RelativeLayout> +</LinearLayout> +</LinearLayout> + +<RelativeLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:padding="10dip" + > + + + + <SeekBar + android:id="@+id/seekbar" + android:max="100" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingBottom="5dip" + android:progressDrawable="@drawable/seek_background" + /> + + <TextView + android:id="@+id/seek_position" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="0:00" + android:layout_below="@id/seekbar" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + + <TextView + android:id="@+id/seek_total" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="0:00" + android:layout_below="@id/seekbar" + android:layout_alignParentRight="true" + android:textAppearance="?android:attr/textAppearanceSmall" + /> +</RelativeLayout> + +</LinearLayout> +</ScrollView> diff --git a/src/AndroidRemote/AndroidApp/res/layout/album_browse.xml b/src/AndroidRemote/AndroidApp/res/layout/album_browse.xml new file mode 100644 index 0000000..cdaf100 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/album_browse.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + +<ImageView +android:id="@+id/icon" +android:layout_height="wrap_content" +android:layout_width="wrap_content" +android:src="@drawable/album"/> + +<TextView +android:id="@+id/title" +android:paddingTop="15dip" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:textSize="26sp" +android:text="Albums"/> +/> + +</LinearLayout> + + <ListView android:id="@+id/albumBrowse" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + + </LinearLayout>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/layout/album_row_view.xml b/src/AndroidRemote/AndroidApp/res/layout/album_row_view.xml new file mode 100644 index 0000000..52515e3 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/album_row_view.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <TextView android:id="@+id/albumName" + android:textSize="14sp" + android:textStyle="bold" + android:textColor="#FFFFFF" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/albumArtist" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> +</LinearLayout>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/layout/browse.xml b/src/AndroidRemote/AndroidApp/res/layout/browse.xml new file mode 100644 index 0000000..0d2527a --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/browse.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + +<ImageView +android:id="@+id/icon" +android:layout_height="wrap_content" +android:layout_width="wrap_content" +android:src="@drawable/artist"/> + +<TextView +android:id="@+id/title" +android:paddingTop="15dip" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:textSize="26sp" +android:text="Artists"/> +/> + +</LinearLayout> + + <ListView android:id="@android:id/list" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + + </LinearLayout> diff --git a/src/AndroidRemote/AndroidApp/res/layout/init.xml b/src/AndroidRemote/AndroidApp/res/layout/init.xml new file mode 100644 index 0000000..b59330a --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/init.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingTop="15dip" + android:text="Banshee Server Settings" + /> + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingTop="25dip" + android:text="IP Address" + /> + <EditText + android:id="@+id/ip" + android:text="" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + /> + <TextView + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingTop="15dip" + android:text="Port" + /> + <EditText + android:id="@+id/port" + android:text="8484" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingBottom="15dip" + /> + <RelativeLayout + android:paddingTop="10dip" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + > + <Button + android:id="@+id/submit" + android:layout_width="70px" + android:layout_height="wrap_content" + android:layout_alignParentRight="true" + android:text="OK" + /> + </RelativeLayout> + <!-- <ListView + android:id="@+id/savedServers" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + />--> + </LinearLayout> +</ScrollView>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/layout/list_item.xml b/src/AndroidRemote/AndroidApp/res/layout/list_item.xml new file mode 100644 index 0000000..2cfa01d --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/list_item.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:padding="10dp" + android:textSize="16sp" + android:textColor="#FFFFFF" > +</TextView> diff --git a/src/AndroidRemote/AndroidApp/res/layout/main.xml b/src/AndroidRemote/AndroidApp/res/layout/main.xml new file mode 100644 index 0000000..09b8e57 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/main.xml @@ -0,0 +1,236 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + +<ScrollView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + > + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_horizontal" + > + + + +<LinearLayout + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="10dip" + > + + <TextView + android:id="@+id/track" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Track name" + android:paddingTop="5dip" + android:textAppearance="?android:attr/textAppearanceLarge" + /> + + <TextView + android:id="@+id/artist" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Artist" + android:layout_below="@id/track" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + + <TextView + android:id="@+id/album" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:text="Album" + android:layout_below="@id/artist" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + +</LinearLayout> + + +<RelativeLayout + android:layout_width="300dip" + android:layout_height="wrap_content" + android:paddingLeft="10dip" + android:paddingRight="10dip" + > + + + <ImageView + android:id="@+id/cover" + android:layout_width="200dip" + android:layout_height="200dip" + android:paddingRight="0dip" + /> + + <ImageButton + android:id="@+id/artists" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="0dip" android:paddingBottom="10dip" + android:src="@drawable/artist" + android:layout_alignParentRight="true" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/albums" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:src="@drawable/album" + android:paddingTop="10dip" android:paddingBottom="10dip" + android:layout_alignParentRight="true" + android:layout_below="@id/artists" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/songs" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="10dip" android:paddingBottom="0dip" + android:layout_alignParentRight="true" + android:layout_below="@id/albums" + android:src="@drawable/songs" + android:background="@null" + android:tint="#00000000" + /> + + + + <!-- + <ImageButton + android:id="@+id/mute" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="0dip" android:paddingRight="0dip" + android:paddingTop="0dip" android:paddingBottom="0dip" + android:src="@android:drawable/ic_lock_silent_mode" + android:layout_alignParentRight="true" + android:layout_below="@id/volumedown" + android:background="@null" + /> + --> + +</RelativeLayout> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="center_horizontal" + > + <LinearLayout + android:orientation="horizontal" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:padding="40dip" + > + + <ImageButton + android:id="@+id/prev" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="0dip" android:paddingRight="15dip" + android:src="@android:drawable/ic_media_previous" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/playpause" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="15dip" android:paddingRight="15dip" + android:src="@android:drawable/ic_media_play" + android:background="@null" + android:tint="#00000000" + /> + + <ImageButton + android:id="@+id/next" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingLeft="15dip" android:paddingRight="0dip" + android:src="@android:drawable/ic_media_next" + android:background="@null" + android:tint="#00000000" + /> + +</LinearLayout> + +<RelativeLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:padding="10dip" + > + + <SeekBar + android:id="@+id/seekbar" + android:max="100" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingBottom="5dip" + android:progressDrawable="@drawable/seek_background" + /> + + <TextView + android:id="@+id/seek_position" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="0:00" + android:layout_below="@id/seekbar" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + + <TextView + android:id="@+id/seek_total" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="0:00" + android:layout_below="@id/seekbar" + android:layout_alignParentRight="true" + android:textAppearance="?android:attr/textAppearanceSmall" + /> + +</RelativeLayout> + + +</LinearLayout> + + +</LinearLayout> +</ScrollView> diff --git a/src/AndroidRemote/AndroidApp/res/layout/song_browse.xml b/src/AndroidRemote/AndroidApp/res/layout/song_browse.xml new file mode 100644 index 0000000..475c384 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/song_browse.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> + + + <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + > + +<ImageView +android:id="@+id/icon" +android:layout_height="wrap_content" +android:layout_width="wrap_content" +android:src="@drawable/album"/> + +<TextView +android:id="@+id/title" +android:paddingTop="15dip" +android:layout_width="wrap_content" +android:layout_height="wrap_content" +android:textSize="26sp" +android:text="Songs"/> +/> + +</LinearLayout> + + <ListView android:id="@+id/songBrowse" + android:layout_width="fill_parent" + android:layout_height="wrap_content"/> + + + </LinearLayout>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/layout/song_row_view.xml b/src/AndroidRemote/AndroidApp/res/layout/song_row_view.xml new file mode 100644 index 0000000..655bb4f --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/layout/song_row_view.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + BansheeRemote + + Copyright (C) 2009 Nikitas Stamatopoulos + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + <TextView android:id="@+id/songName" + android:textSize="14sp" + android:textStyle="bold" + android:textColor="#FFFFFF" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + <TextView android:id="@+id/songArtist" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> +</LinearLayout>
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidApp/res/values/strings.xml b/src/AndroidRemote/AndroidApp/res/values/strings.xml new file mode 100644 index 0000000..33bcd04 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="hello">Hello World, BansheeRemote</string> + <string name="app_name">BansheeRemote</string> +</resources> diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBaseAdapter.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBaseAdapter.java new file mode 100644 index 0000000..fd43e51 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBaseAdapter.java @@ -0,0 +1,83 @@ +package org.nstamato.bansheeremote; +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +import java.util.ArrayList; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +public class AlbumBaseAdapter extends BaseAdapter { + private static ArrayList<AlbumListItem> albumList; + + private LayoutInflater mInflater; + + public AlbumBaseAdapter(Context context, ArrayList<AlbumListItem> albums) { + albumList = albums; + mInflater = LayoutInflater.from(context); + } + + public int getCount() { + return albumList.size(); + } + + public Object getItem(int position) { + return albumList.get(position); + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + + //Log.i("banshee","Entered getView method"); + if (convertView == null) { + //Log.i("banshee","convertView is null"); + convertView = mInflater.inflate(R.layout.album_row_view, null); + holder = new ViewHolder(); + holder.albumName = (TextView) convertView.findViewById(R.id.albumName); + holder.artist = (TextView) convertView.findViewById(R.id.albumArtist); + + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + holder.albumName.setText(albumList.get(position).getAlbumName()); + holder.artist.setText(albumList.get(position).getArtist()); + + return convertView; + } + + public class ViewHolder { + TextView albumName; + TextView artist; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBrowse.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBrowse.java new file mode 100644 index 0000000..544db4c --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumBrowse.java @@ -0,0 +1,232 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.File; +import java.util.ArrayList; + +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; + +public class AlbumBrowse extends Activity{ + ArrayList<AlbumListItem> albumList; + AlbumBaseAdapter albumListAdapter; + //ArrayAdapter<AlbumListItem> albumListAdapter; + final String filenameDB = "banshee.db"; + SQLiteDatabase bansheeDB; + public ImageView icon; + public TextView title; + public String titleText="Albums"; + public boolean addedNull=false; + //public ListView l; + + /*private OnItemClickListener clickListener = new OnItemClickListener(){ + public void onItemClick(AdapterView<?> a, View v, int position, long id) { + Object o = l.getItemAtPosition(position); + AlbumListItem album = (AlbumListItem)o; + Intent i = new Intent(AlbumBrowse.this,SongBrowse.class); + i.putExtra("Album",album.getAlbumName()); + i.putExtra("AlbumID",album.getAlbumId()); + startActivityForResult(i,2); + } + };*/ + + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + setResult(resultCode,data); + if(resultCode==RESULT_OK) + finish(); + } + + public void onCreate(Bundle savedInstanceState) { + //this.setFastScrollEnabled(true); + super.onCreate(savedInstanceState); + setContentView(R.layout.album_browse); + Intent i=getIntent(); + Bundle extras=null; + if(i!=null) + extras = i.getExtras(); + if(extras!=null) + this.titleText = extras.getString("Artist"); + this.icon = (ImageView)this.findViewById(R.id.icon); + this.title = (TextView)this.findViewById(R.id.title); + this.title.setText(titleText); + this.icon.setImageResource(R.drawable.album); + this.albumList = new ArrayList<AlbumListItem>(); + this.albumListAdapter = new AlbumBaseAdapter(this,albumList); + //this.albumListAdapter = new ArrayAdapter<AlbumListItem>(this,R.layout.album_row_view,albumList); + + //this.header = new ArrayList<String>(); + //this.header.add("title"); + //this.headerAdapter = new ArrayAdapter<String>(this,R.layout.list_item,header); + //setListAdapter(headerAdapter); + + //setListAdapter(albumListAdapter); + ListView l = (ListView) findViewById(R.id.albumBrowse); + l.setAdapter(albumListAdapter); + //ListView l = getListView(); + l.setTextFilterEnabled(true); + l.setFastScrollEnabled(true); + //l.setTextFilterEnabled(true); + //l.setFastScrollEnabled(true); + //l.setOnItemClickListener(clickListener); + File db = null; + try{ + //db = getFileStreamPath(filenameDB); + db = Environment.getExternalStorageDirectory(); + String path = db.getAbsolutePath()+'/'+filenameDB; + bansheeDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); + String query = "SELECT Title, TitleLowered, ArtistName, AlbumID FROM CoreAlbums"; + String[] params = null; + if(!titleText.equals("Albums")){ + query+=" WHERE ArtistName=?"; + params = new String[]{titleText}; + } + query+=" ORDER BY Title"; + + Cursor c = bansheeDB.rawQuery(query,params); + //int columnCount = c.getColumnCount(); + int name = c.getColumnIndex("Title"); + int lowered = c.getColumnIndex("TitleLowered"); + int artistColumnIndex = c.getColumnIndex("ArtistName"); + int albumIdColumnIndex = c.getColumnIndex("AlbumID"); + //int count = c.getCount(); + c.moveToFirst(); + while(c.isAfterLast()==false){ + AlbumListItem albumItem = new AlbumListItem(); + String label = c.getString(name); + String artist = c.getString(artistColumnIndex); + int albumID = c.getInt(albumIdColumnIndex); + if(label!=null){ + albumItem.setAlbumName(label); + albumItem.setAlbumId(albumID); + albumItem.setArtist(""); + if(artist!=null) + albumItem.setArtist(artist); + albumList.add(albumItem); + } + else if(!addedNull){ + albumItem.setAlbumName(c.getString(lowered)); + albumItem.setAlbumId(albumID); + albumItem.setArtist(("Unknown Artist")); + albumList.add(albumItem); + addedNull=true; + } + c.moveToNext(); + //artistList.add("hello"); + } + c.close(); + //artistList.add("hello"); + //Toast.makeText(this,result,Toast.LENGTH_SHORT).show(); + //String result = c.getString(name); + }catch(SQLiteException e){ + //Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + catch(Exception e){ + //Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + + //l.setOnItemClickListener(clickListener); + l.setOnItemClickListener(new OnItemClickListener(){ + public void onItemClick(AdapterView<?> a, View v, int position, long id) { + ListView l = (ListView) findViewById(R.id.albumBrowse); + Object o = l.getItemAtPosition(position); + AlbumListItem album = (AlbumListItem)o; + Intent i = new Intent(AlbumBrowse.this,SongBrowse.class); + i.putExtra("Album",album.getAlbumName()); + i.putExtra("AlbumID",album.getAlbumId()); + startActivityForResult(i,2); + } + }); + + + } + /*public void onListItemClick(ListView l, View v, int position, long id){ + super.onListItemClick(l, v, position, id); + Object o = l.getItemAtPosition(position); + AlbumListItem album = (AlbumListItem)o; + Intent i = new Intent(AlbumBrowse.this,SongBrowse.class); + i.putExtra("Album",album.getAlbumName()); + i.putExtra("AlbumID",album.getAlbumId()); + startActivityForResult(i,2); + }*/ + + /*public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + String selected = this.albumListAdapter.getItem(position); + String query=null; + String[] params=null; + if(!selected.equals("unknown album")){ + query = "SELECT AlbumID FROM CoreAlbums WHERE Title=?"; + params = new String[]{selected}; + if(!titleText.equals("Albums")){ + query+=" AND ArtistName=?"; + params = new String[]{selected,titleText}; + } + } + else{ + query = "SELECT AlbumID FROM CoreAlbums WHERE TitleLowered=?"; + params = new String[]{selected}; + if(!titleText.equals("Albums")){ + query+=" AND ArtistName=?"; + params = new String[]{selected,titleText}; + } + } + Cursor c = bansheeDB.rawQuery(query,params); + //int columnCount = c.getColumnCount(); + int albumIDColumn = c.getColumnIndex("AlbumID"); + //int count = c.getCount(); + c.moveToFirst(); + int albumID=0; + try{ + albumID = c.getInt(albumIDColumn); + } + catch(Exception e){ + + } + + //Toast.makeText(this,selected,Toast.LENGTH_SHORT).show(); + Intent i = new Intent(this,SongBrowse.class); + i.putExtra("Album",selected); + i.putExtra("AlbumID",albumID); + startActivityForResult(i,2); + }*/ + +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumListItem.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumListItem.java new file mode 100644 index 0000000..2293811 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/AlbumListItem.java @@ -0,0 +1,55 @@ +package org.nstamato.bansheeremote; +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +public class AlbumListItem { + private String albumName = ""; + private String artist = ""; + private int albumId=0; + + public void setAlbumName(String name) { + this.albumName = name; + } + + public String getAlbumName() { + return albumName; + } + + + public void setArtist(String artist) { + this.artist = artist; + } + + public String getArtist() { + return artist; + } + + public void setAlbumId(int albumId){ + this.albumId = albumId; + } + + public int getAlbumId(){ + return albumId; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/ArtistBrowse.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/ArtistBrowse.java new file mode 100644 index 0000000..19e7ca5 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/ArtistBrowse.java @@ -0,0 +1,122 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.File; +import java.util.ArrayList; + + +import android.app.ListActivity; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.os.Bundle; +import android.os.Environment; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +public class ArtistBrowse extends ListActivity{ + ArrayList<String> artistList; + ArrayAdapter<String> artistListAdapter; + final String filenameDB = "banshee.db"; + SQLiteDatabase bansheeDB; + public ImageView icon; + public TextView title; + + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + setResult(resultCode,data); + if(resultCode==RESULT_OK) + finish(); + } + + public void onCreate(Bundle savedInstanceState) { + //this.setFastScrollEnabled(true); + //Log.i("test","test"); + super.onCreate(savedInstanceState); + setContentView(R.layout.browse); + this.icon = (ImageView)this.findViewById(R.id.icon); + this.title = (TextView)this.findViewById(R.id.title); + this.title.setText("Artists"); + this.icon.setImageResource(R.drawable.artist); + this.artistList = new ArrayList<String>(); + this.artistListAdapter = new ArrayAdapter<String>(this,R.layout.list_item,artistList); + //this.header = new ArrayList<String>(); + //this.header.add("title"); + //this.headerAdapter = new ArrayAdapter<String>(this,R.layout.list_item,header); + //setListAdapter(headerAdapter);n + setListAdapter(artistListAdapter); + File db = null; + try{ + //db = getFileStreamPath(filenameDB); + db = Environment.getExternalStorageDirectory(); + String path = db.getAbsolutePath()+'/'+filenameDB; + bansheeDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); + String query = "SELECT Name FROM CoreArtists ORDER BY Name"; + Cursor c = bansheeDB.rawQuery(query,null); + //int columnCount = c.getColumnCount(); + int name = c.getColumnIndex("Name"); + //int count = c.getCount(); + c.moveToFirst(); + while(c.isAfterLast()==false){ + String artist = c.getString(name); + if(artist!=null) + artistList.add(c.getString(name)); + c.moveToNext(); + //artistList.add("hello"); + } + c.close(); + //artistList.add("hello"); + //Toast.makeText(this,result,Toast.LENGTH_SHORT).show(); + //String result = c.getString(name); + }catch(SQLiteException e){ + //Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + catch(Exception e){ + //Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + ListView l = getListView(); + l.setTextFilterEnabled(true); + l.setFastScrollEnabled(true); + } + + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + String selected = this.artistListAdapter.getItem(position); + //Toast.makeText(this,selected,Toast.LENGTH_SHORT).show(); + Intent i = new Intent(this,AlbumBrowse.class); + i.putExtra("Artist",selected); + startActivityForResult(i,2); + } + +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeInstance.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeInstance.java new file mode 100644 index 0000000..85518f3 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeInstance.java @@ -0,0 +1,50 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import android.graphics.Bitmap; + +public class BansheeInstance { + public String status; + public Bitmap cover; + public String track, artist, album; + public int iseekposition, iseektotal; + public boolean isCover; + public String ip; + public int port; + + public BansheeInstance(String status, Bitmap cover, String track, String artist, String album, int position, int total, boolean isCover, String ip, int port){ + this.status=status; + this.cover = cover; + this.track=track; + this.artist=artist; + this.album=album; + this.iseekposition=position; + this.iseektotal=total; + this.ip=ip; + this.port=port; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeRemote.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeRemote.java new file mode 100644 index 0000000..385557b --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/BansheeRemote.java @@ -0,0 +1,159 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.util.ArrayList; +import android.app.ListActivity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.Toast; + + +public class BansheeRemote extends ListActivity { + String serverData = null; + String savedServers[]; + boolean serversExist=false; + ArrayList<String> savedServersListArray; + ArrayAdapter<String> savedServersListAdapter; + final String filename = "bansheeServers.dat"; + + + public String readSettings(Context context, String filename){ + FileInputStream fIn = null; + InputStreamReader isr = null; + + char[] inputBuffer = new char[255]; + String data = null; + + try{ + fIn = openFileInput(filename); + isr = new InputStreamReader(fIn); + isr.read(inputBuffer); + data = new String(inputBuffer); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + try { + isr.close(); + fIn.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + return data; + } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + finish(); + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setup(); + } + public void setup(){ + this.savedServersListArray = new ArrayList<String>(); + this.savedServersListAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,savedServersListArray); + setListAdapter(savedServersListAdapter); + serverData = readSettings(BansheeRemote.this,filename); + if(serverData!=null){ + serversExist=true; + savedServers = serverData.split(";"); + for(int i=savedServers.length-2;i>=0;i--){ + savedServersListArray.add(savedServers[i]); + } + } + savedServersListArray.add("Add new Server"); + //File root = Environment.getDataDirectory(); + //Toast.makeText(BansheeRemote.this,root.getAbsolutePath(),Toast.LENGTH_LONG).show(); + } + + public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + String selected = this.savedServersListAdapter.getItem(position); + if(selected.equals("Add new Server")){ + Intent response = new Intent(BansheeRemote.this,NewServer.class); + startActivityForResult(response,1); + } + else{ + boolean canConnect = false; + boolean isReachable=false; + String server[] = selected.split(":"); + String ip = server[0]; + int port = Integer.parseInt(server[1]); + String command = "test/"; + Socket s; + OutputStream os; + try{ + InetAddress address = InetAddress.getByName(ip); + isReachable = address.isReachable(3000); + if(isReachable){ + try { + s = new Socket(ip,port); + os = s.getOutputStream(); + os.write(command.getBytes(), 0, command.length()); + s.close(); + os.close(); + canConnect = true; + } catch(Exception e) { + canConnect = false; + Toast.makeText(BansheeRemote.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + } + else{ + Toast.makeText(BansheeRemote.this,"Unreachable host.",Toast.LENGTH_SHORT).show(); + + } + }catch(Exception e){ + Toast.makeText(BansheeRemote.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + + } + + if(canConnect){ + Intent response = new Intent(BansheeRemote.this,main.class); + response.putExtra("ip",ip); + response.putExtra("port", port); + startActivityForResult(response,1); + } + } + //Toast.makeText(BansheeRemote.this, selected,Toast.LENGTH_SHORT).show(); + } + +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/NewServer.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/NewServer.java new file mode 100644 index 0000000..3044881 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/NewServer.java @@ -0,0 +1,198 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.net.InetAddress; +import java.net.Socket; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + + +public class NewServer extends Activity { + String serverData = null; + String savedServers[]; + boolean serversExist=false; + final String filename = "bansheeServers.dat"; + + public void writeSettings(Context context, String filename, String data){ + FileOutputStream fOut = null; + OutputStreamWriter osw = null; + + try{ + fOut = context.openFileOutput(filename,Context.MODE_APPEND); + osw = new OutputStreamWriter(fOut); + osw.write(data+';'); + osw.flush(); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + try { + osw.close(); + fOut.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + public String readSettings(Context context, String filename){ + FileInputStream fIn = null; + InputStreamReader isr = null; + + char[] inputBuffer = new char[255]; + String data = null; + + try{ + fIn = openFileInput(filename); + isr = new InputStreamReader(fIn); + isr.read(inputBuffer); + data = new String(inputBuffer); + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + try { + isr.close(); + fIn.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + return data; + } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + finish(); + } + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setup(); + } + public void setup(){ + setContentView(R.layout.init); + Button data = (Button) findViewById(R.id.submit); + serverData = readSettings(NewServer.this,filename); + if(serverData!=null){ + serversExist=true; + savedServers = serverData.split(";"); + } + data.setOnClickListener(new OnClickListener(){ + public void onClick(View v) { + EditText iptext = (EditText)findViewById(R.id.ip); + EditText porttext = (EditText)findViewById(R.id.port); + String ip = iptext.getText().toString(); + Socket s; + OutputStream os; + String command = "test/"; + boolean canConnect = false; + boolean isReachable = false; + int port=0; + + try{ + port=Integer.parseInt(porttext.getText().toString()); + InetAddress address = InetAddress.getByName(ip); + isReachable = address.isReachable(3000); + if(isReachable){ + try { + s = new Socket(ip,port); + os = s.getOutputStream(); + os.write(command.getBytes(), 0, command.length()); + s.close(); + os.close(); + canConnect = true; + } catch(Exception e) { + canConnect = false; + Toast.makeText(NewServer.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + } + else{ + Toast.makeText(NewServer.this,"Unreachable host.",Toast.LENGTH_SHORT).show(); + + } + }catch(Exception e){ + Toast.makeText(NewServer.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + + } + + if(canConnect){ + Intent response = new Intent(NewServer.this,main.class); + response.putExtra("ip",ip); + response.putExtra("port", port); + String newServer = ip+':'+porttext.getText().toString(); + boolean exists = false; + if(serversExist){ + for(int i=0;i<savedServers.length-1;i++){ + if(newServer.equals(savedServers[i])){ + exists = true; + + } + } + + if(!exists){ + int numberServersSaved = savedServers.length-1; + if(numberServersSaved<5) + writeSettings(NewServer.this,filename,newServer); + else{ + deleteFile(filename); + for(int i=1;i<numberServersSaved;i++){ + writeSettings(NewServer.this,filename,savedServers[i]); + } + writeSettings(NewServer.this,filename,newServer); + } + } + } + else{ + writeSettings(NewServer.this,filename,newServer); + } + startActivityForResult(response,1); + //setResult(RESULT_OK,response); + //finish(); + } + } + + }); + } + +} + diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Settings.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Settings.java new file mode 100644 index 0000000..8047f5c --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Settings.java @@ -0,0 +1,107 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + + +public class Settings extends Activity { + + //public void onConfigurationChanged(Configuration newConfig){ + //setup(); + //} + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setup(); + } + public void setup(){ + setContentView(R.layout.init); + Button data = (Button) findViewById(R.id.submit); + + data.setOnClickListener(new OnClickListener(){ + + public void onClick(View v) { + EditText iptext = (EditText)findViewById(R.id.ip); + EditText porttext = (EditText)findViewById(R.id.port); + String ip = iptext.getText().toString(); + Socket s; + OutputStream os; + String command = "test/"; + boolean canConnect = false; + boolean isReachable = false; + int port=Integer.parseInt(porttext.getText().toString()); + + try{ + InetAddress address = InetAddress.getByName(ip); + isReachable = address.isReachable(3000); + if(isReachable){ + try { + s = new Socket(ip,port); + os = s.getOutputStream(); + os.write(command.getBytes(), 0, command.length()); + s.close(); + os.close(); + canConnect = true; + } catch(Exception e) { + canConnect = false; + Toast.makeText(Settings.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + } + else{ + Toast.makeText(Settings.this,"Unreachable host.",Toast.LENGTH_SHORT).show(); + + } + }catch(Exception e){ + Toast.makeText(Settings.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + + } + + if(canConnect){ + Intent response = new Intent(); + response.putExtra("ip",ip); + response.putExtra("port", port); + setResult(RESULT_OK,response); + finish(); + } + } + + }); + } + +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBaseAdapter.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBaseAdapter.java new file mode 100644 index 0000000..0ca75dd --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBaseAdapter.java @@ -0,0 +1,83 @@ +package org.nstamato.bansheeremote; +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +import java.util.ArrayList; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +public class SongBaseAdapter extends BaseAdapter { + private static ArrayList<SongListItem> songList; + + private LayoutInflater mInflater; + + public SongBaseAdapter(Context context, ArrayList<SongListItem> songs) { + songList = songs; + mInflater = LayoutInflater.from(context); + } + + public int getCount() { + return songList.size(); + } + + public Object getItem(int position) { + return songList.get(position); + } + + public long getItemId(int position) { + return position; + } + + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + + //Log.i("banshee","Entered getView method"); + if (convertView == null) { + //Log.i("banshee","convertView is null"); + convertView = mInflater.inflate(R.layout.song_row_view, null); + holder = new ViewHolder(); + holder.songName = (TextView) convertView.findViewById(R.id.songName); + holder.artist = (TextView) convertView.findViewById(R.id.songArtist); + + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + + holder.songName.setText(songList.get(position).getSongName()); + holder.artist.setText(songList.get(position).getArtist()); + + return convertView; + } + + public class ViewHolder { + TextView songName; + TextView artist; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBrowse.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBrowse.java new file mode 100644 index 0000000..ffde3cf --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongBrowse.java @@ -0,0 +1,216 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.File; +import java.util.ArrayList; + +import android.app.Activity; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteException; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.AdapterView.OnItemClickListener; + +public class SongBrowse extends Activity{ + ArrayList<SongListItem> songList; + //ArrayList<String> trackIdList; + SongBaseAdapter songListAdapter; + final String filenameDB = "banshee.db"; + SQLiteDatabase bansheeDB; + public int albumID; + public ImageView icon; + public TextView title; + public Cursor c; + public String[] params = null; + public String query; + + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + finish(); + } + + public void onCreate(Bundle savedInstanceState) { + //this.setFastScrollEnabled(true); + super.onCreate(savedInstanceState); + setContentView(R.layout.song_browse); + Bundle extras = getIntent().getExtras(); + String titleText = extras.getString("Album"); + this.albumID = extras.getInt("AlbumID"); + this.icon = (ImageView)this.findViewById(R.id.icon); + this.title = (TextView)this.findViewById(R.id.title); + this.title.setText(titleText); + this.icon.setImageResource(R.drawable.songs); + this.songList = new ArrayList<SongListItem>(); + this.songListAdapter = new SongBaseAdapter(this,songList); + //this.trackIdList = new ArrayList<Integer>(); + //this.songListAdapter = new ArrayAdapter<String>(this,R.layout.list_item,songList); + //this.header = new ArrayList<String>(); + //this.header.add("title"); + //this.headerAdapter = new ArrayAdapter<String>(this,R.layout.list_item,header); + //setListAdapter(headerAdapter); + //setListAdapter(songListAdapter); + final ListView l = (ListView) findViewById(R.id.songBrowse); + l.setAdapter(songListAdapter); + l.setTextFilterEnabled(true); + l.setFastScrollEnabled(true); + File db = null; + try{ + //db = getFileStreamPath(filenameDB); + db = Environment.getExternalStorageDirectory(); + String path = db.getAbsolutePath()+'/'+filenameDB; + bansheeDB = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS); + query = "SELECT CoreTracks.Title AS trackTitle, CoreTracks.Uri, CoreArtists.Name, CoreAlbums.Title FROM CoreTracks,CoreAlbums,CoreArtists WHERE CoreTracks.AlbumID==CoreAlbums.AlbumID AND CoreTracks.ArtistID==CoreArtists.ArtistID"; + + if(albumID>=0){ + query+=" AND CoreTracks.AlbumID=?"; + params = new String[]{String.valueOf(albumID)}; + query+=" ORDER BY CoreTracks.TrackNumber"; + } + else{ + query+=" ORDER BY CoreTracks.Title"; + } + //Thread queryDB = new Thread(new Runnable(){ + //public void run(){ + c = bansheeDB.rawQuery(query,params); + int name = c.getColumnIndex("trackTitle"); + int artist = c.getColumnIndex("CoreArtists.Name"); + int albumColumnIndex = c.getColumnIndex("CoreAlbums.Title"); + int uriColumnIndex = c.getColumnIndex("CoreTracks.Uri"); + Log.i("banshee","coretrack title index "+name+" corealbum title index "+albumColumnIndex+" number of columns "+c.getColumnCount()); + for(int i=0;i<c.getColumnCount();i++){ + Log.i("banshee",c.getColumnName(i)); + } + //int albumColumnIndex = c.getColumnIndex("CoreAlbums.Title"); + //int trackIdColumn = c.getColumnIndex("TrackID"); + //int count = c.getCount(); + c.moveToFirst(); + while(c.isAfterLast()==false){ + SongListItem songItem = new SongListItem(); + String songName = c.getString(name); + String artistName = c.getString(artist); + String albumName = c.getString(albumColumnIndex); + String uri = c.getString(uriColumnIndex); + String combination = ""; + songItem.setSongName(songName); + if(artistName!=null){ + combination+=artistName; + if(albumName!=null) + combination+='/'+albumName; + } + else{ + combination+="Unknown Artist"; + if(albumName!=null) + combination+='/'+albumName; + } + songItem.setUri(uri); + songItem.setArtist(combination); + //String trackID = c.getString(trackIdColumn); + if(songName!=null){ + songList.add(songItem); + //trackIdList.add(c.getString(trackIdColumn)); + } + c.moveToNext(); + //artistList.add("hello"); + } + c.close(); + //} + //}); + //queryDB.start(); + //int columnCount = c.getColumnCount(); + + //artistList.add("hello"); + //Toast.makeText(this,result,Toast.LENGTH_SHORT).show(); + //String result = c.getString(name); + }catch(SQLiteException e){ + Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + //Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + catch(Exception e){ + Toast.makeText(this,e.getMessage(),Toast.LENGTH_SHORT).show(); + //Toast.makeText(this,"Something went wrong. Make sure the banshee database file is on your sd-card.",Toast.LENGTH_LONG).show(); + } + + l.setOnItemClickListener(new OnItemClickListener(){ + public void onItemClick(AdapterView<?> a, View v, int position, long id) { + Object o = l.getItemAtPosition(position); + SongListItem song = (SongListItem)o; + Intent response = new Intent(); + response.putExtra("Uri",song.getUri()); + setResult(RESULT_OK,response); + finish(); + } + }); + } + /*public boolean onKeyDown(int keyCode, KeyEvent event) { + if ((keyCode == KeyEvent.KEYCODE_BACK)) { + //Log.d(this.getClass().getName(), "back button pressed"); + Intent response = new Intent(); + setResult(RESULT_OK+1,response); + finish(); + } + return super.onKeyDown(keyCode, event); + }*/ + + /*public void onListItemClick(ListView l, View v, int position, long id) { + super.onListItemClick(l, v, position, id); + String selected = this.songListAdapter.getItem(position); + //String trackID = this.trackIdList.get(position); + //Toast.makeText(this,selected,Toast.LENGTH_SHORT).show(); + query = "SELECT Uri FROM CoreTracks WHERE Title=?"; + params = new String[]{selected}; + if(albumID>=0){ + query+=" AND AlbumID=?"; + params = new String[]{selected, String.valueOf(albumID)}; + query+=" ORDER BY TrackNumber"; + } + else{ + query+=" ORDER BY Title"; + } + this.c = bansheeDB.rawQuery(query,params); + //int columnCount = c.getColumnCount(); + int uriColumn = c.getColumnIndex("Uri"); + //int count = c.getCount(); + c.moveToFirst(); + String Uri = c.getString(uriColumn); + //Toast.makeText(this,Uri,Toast.LENGTH_SHORT).show(); + Intent response = new Intent(); + response.putExtra("Uri",Uri); + setResult(RESULT_OK,response); + finish(); + //startActivityForResult(i,0); + }*/ + +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongListItem.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongListItem.java new file mode 100644 index 0000000..f52613e --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/SongListItem.java @@ -0,0 +1,64 @@ +package org.nstamato.bansheeremote; +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +public class SongListItem { + private String songName = ""; + private String artist = ""; + private int albumId=0; + private String uri=""; + + public void setSongName(String name) { + this.songName = name; + } + + public String getSongName() { + return songName; + } + + + public void setArtist(String artist) { + this.artist = artist; + } + + public String getArtist() { + return artist; + } + + public void setAlbumId(int albumId){ + this.albumId = albumId; + } + + public int getAlbumId(){ + return albumId; + } + + public void setUri(String uri){ + this.uri = uri; + } + + public String getUri(){ + return uri; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Sync.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Sync.java new file mode 100644 index 0000000..4b59acd --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/Sync.java @@ -0,0 +1,222 @@ +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Intent; +import android.content.res.Configuration; +import android.database.sqlite.SQLiteException; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +public class Sync extends Activity{ +public ProgressDialog pd; +String server; +int port; +public final String filenameDB = "banshee.db"; +public static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +public static byte[] byteBuff = new byte[1024]; + +private Handler dbHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + //int progress = msg.arg1; + //pd.setProgress(progress); + //if(progress>=100) + pd.dismiss(); + //tv.setText(pi_string); + + } +}; + + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Bundle extras = getIntent().getExtras(); + server = extras.getString("ip"); + port = extras.getInt("port"); + sync(); + } + + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + sync(); + } + + + public void sync(){ + pd = new ProgressDialog(this); + pd.setCancelable(true); + //pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + pd.setTitle("Syncing with Banshee..."); + pd.setMessage("This might take some time, depending on your internet connection and your phone."); + pd.show(); + + Thread getDB = new Thread(new Runnable (){ + //String command="sync/"; + public void run(){ + try { + //String dbCount = getInfo("syncCount",null); + //int totalReceived = 0; + //int remainingBytes = getInfoInt("syncCount",null); + int chunksize=8000;//remainingBytes; + //int offset = 0; + //Log.i("banshee","bytes "+remainingBytes); + //Toast.makeText(main.this,"Bytes "+dbCount,Toast.LENGTH_SHORT).show(); + byte[] dbbytes = null; + File root = Environment.getExternalStorageDirectory(); + //Log.i("banshee","external directory "+root.getAbsolutePath()); + FileOutputStream fstream = new FileOutputStream(new File(root,filenameDB)); + //FileOutputStream fstream = openFileOutput(filenameDB,Context.MODE_PRIVATE); + dbbytes = new byte[chunksize]; + Socket s = new Socket(server,port); + OutputStream os = s.getOutputStream(); + InputStream is = s.getInputStream(); + String command = "sync/"; + os.write(command.getBytes(), 0, command.length()); + //Log.i("banshee","sent command"); + int len=0; + while ( (len = is.read(dbbytes)) > 0 ) { + //Log.i("banshee","inside loop"); + //is.read(dbbytes,0,chunksize); + fstream.write(dbbytes,0,len); + //totalReceived+=len; + //int progress=totalReceived/remainingBytes*100; + //Message progressMessage = new Message(); + //progressMessage.arg1=progress; + //dbHandler.sendMessage(progressMessage); + } + + /*while(remainingBytes>0){ + Socket s = new Socket(server,port); + OutputStream os = s.getOutputStream(); + InputStream is = s.getInputStream(); + String offsetT = Integer.toString(offset); + String command = "sync/"+offsetT; + //String command = "sync/"; + os.write(command.getBytes(), 0, command.length()); + //if(remainingBytes>=chunksize){ + //dbbytes = new byte[chunksize]; + is.read(dbbytes,0,chunksize); + //if(rep==0){ + //hash = Base64.encodeToString(dbbytes, 0, chunksize, Base64.DEFAULT); + //os.write(hash.getBytes(),0,chunksize); + //} + remainingBytes-=chunksize; + offset+=chunksize; + //} + //else{ + //dbbytes = new byte[remainingBytes]; + //is.read(dbbytes,0,remainingBytes); + //remainingBytes=0; + //} + //Toast.makeText(main.this,"hello "+dbCount,Toast.LENGTH_SHORT).show(); + fstream.write(dbbytes); + s.close(); + //rep++; + }*/ + fstream.close(); + dbHandler.sendEmptyMessage(0); + Intent response = new Intent(); + //response.putExtra("ip",ip); + //response.putExtra("port", port); + setResult(RESULT_OK,response); + finish(); + //continueserver=true; + //bansheeDB = SQLiteDatabase.openDatabase(filenameDB, null, SQLiteDatabase.OPEN_READONLY); + } + catch (java.lang.OutOfMemoryError e) { + Log.i("banshee","ran out of memory"); + dbHandler.sendEmptyMessage(0); + Intent response = new Intent(); + setResult(RESULT_OK+2,response); + finish(); + //Toast.makeText(Sync.this,"Memory Error.",Toast.LENGTH_SHORT).show(); + + } + catch(SQLiteException e){ + dbHandler.sendEmptyMessage(0); + Intent response = new Intent(); + setResult(RESULT_OK+1,response); + finish(); + //Toast.makeText(main.this,"Can't create database",Toast.LENGTH_LONG).show(); + } + + catch (Exception e) { + dbHandler.sendEmptyMessage(0); + Intent response = new Intent(); + setResult(RESULT_OK+1,response); + finish(); + //Toast.makeText(Sync.this,"Can't write to database file.",Toast.LENGTH_SHORT).show(); + } + } + }); + getDB.start(); + + } + public String getInfo(String action, String params) throws Exception{ + String data=null; + String formattedAction = action+'/'+params; + Socket s = new Socket(server,port); + OutputStream os = s.getOutputStream(); + InputStream is = s.getInputStream(); + os.write(formattedAction.getBytes(), 0, formattedAction.length()); + int byteCount = -1; + byteArrayOutputStream.reset(); + while ((byteCount = is.read(byteBuff, 0, byteBuff.length)) != -1) { + byteArrayOutputStream.write(byteBuff, 0, byteCount); + } + data = byteArrayOutputStream.toString(); + return data; + } + public int getInfoInt(String action,String params){ + int n=-1; + boolean done=false; + while(!done){ + try{ + n = Integer.parseInt(getInfo(action,params)); + done=true; + } + catch(NumberFormatException e){ + done=false; + } + catch(Exception e){ + + } + } + return n; + } +} diff --git a/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/main.java b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/main.java new file mode 100644 index 0000000..f5f95c7 --- /dev/null +++ b/src/AndroidRemote/AndroidApp/src/org/nstamato/bansheeremote/main.java @@ -0,0 +1,727 @@ + +package org.nstamato.bansheeremote; + +/* +BansheeRemote + +Copyright (C) 2011 Nikitas Stamatopoulos + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +import java.io.*; +import java.net.*; + +import android.app.Activity; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.database.sqlite.SQLiteDatabase; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.SeekBar; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.SeekBar.OnSeekBarChangeListener; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; + +public class main extends Activity{ + + public ImageButton prev, playpause, next, mute, artists, albums, songs; + public PhoneStateListener phoneListener; + public TelephonyManager tm; + public TextView track, artist, album, seekposition, seektotal; + public SeekBar seekbar; + public ImageView cover; + + + public static String server=""; + public static int port=-1; + public static int interval = 1; + + public final static int PARTIAL_UPDATE = 1, FULL_UPDATE = 2; + public final String filenameDB = "banshee.db"; + + public String strack, sartist, salbum; + public int iseekposition, iseektotal; + public String istatus; + public Bitmap bcover = null; + public Socket s; + public OutputStream os; + public InputStream is; + public String command; + public boolean isCover; + public Bitmap no_cover;//=BitmapFactory.decodeResource(getResources(),R.drawable.no_cover_art); + //public boolean connected; + public ProgressDialog pd; + public Thread getDB; + public SQLiteDatabase bansheeDB = null; + public boolean serverThreadDone = false; + public final Handler update = new Handler() { + @Override + public void handleMessage(Message msg) { + + if(msg.what == FULL_UPDATE) { + playpause.setImageResource((istatus.contains("playing")) ? android.R.drawable.ic_media_pause : android.R.drawable.ic_media_play); + track.setText(strack); + artist.setText(sartist); + album.setText(salbum); + + seektotal.setText(formatTime(iseektotal)); + seekbar.setMax(iseektotal); + cover.setImageBitmap(bcover); + } + + seekbar.setProgress(iseekposition); + seekposition.setText(formatTime(iseekposition)); + + + } + }; + + public static String formatTime(int seconds) { + String leading = (seconds % 60 < 10) ? "0" : ""; + if(seconds >= 60) + return (seconds / 60) + ":" + leading + (seconds % 60); + else + return "0:" + leading + seconds; + } + + + public boolean continueserver = true; + + public Thread serverpoke = new Thread(new Runnable() { + public void run() { + while(true){ + while(continueserver) { + serverThreadDone = false; + if(!istatus.equals("idle")){ + try { + int oldseektotal = iseektotal; + String oldstatus = istatus; + getAllInfo(); + if(isCover && (bcover==null)){ + bcover = getCover(server,port); + } + if(!istatus.equals(oldstatus)){ + update.sendEmptyMessage(FULL_UPDATE); + } + if(iseektotal != oldseektotal) { + bcover=no_cover; + if(isCover) + bcover = getCover(server,port); + update.sendEmptyMessage(FULL_UPDATE); + } + else { + update.sendEmptyMessage(PARTIAL_UPDATE); + } + + }catch(Exception e) { + } + } + else{ + try { + istatus = getInfo("status",null); + } catch (Exception e) { + + e.printStackTrace(); + } + } + + // then sleep until next round + try { + Thread.sleep(1000 * interval); + } catch (Exception e) { + e.printStackTrace(); + } + + serverThreadDone=true; + } + try{ + Thread.sleep(1000 * interval); + }catch(Exception e){ + + } + } + + } + }); + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + MenuItem item1 = menu.add(0,0,0,"Settings"); + item1.setIcon(android.R.drawable.ic_menu_edit); + MenuItem item5 = menu.add(0,4,4,"Sync"); + item5.setIcon(R.drawable.ic_menu_refresh); + MenuItem item2 = menu.add(0,1,1,"Shuffle"); + item2.setIcon(android.R.drawable.ic_menu_directions); + MenuItem item3 = menu.add(0,2,2,"Repeat"); + item3.setIcon(android.R.drawable.ic_menu_revert); + MenuItem item4 = menu.add(0,3,3,"Exit"); + item4.setIcon(android.R.drawable.ic_menu_close_clear_cancel); + + return true; + } + @Override + public boolean onOptionsItemSelected(MenuItem item){ + if(item.getItemId()==3){ + Intent response = new Intent(); + setResult(RESULT_OK,response); + finish(); + } + else if(item.getItemId()==0){ + displaySettings(); + } + + else if(item.getItemId()==4){ + //File dir = Environment.getExternalStorageDirectory(); + //Toast.makeText(main.this,"Shuffle mode by "+dir.getAbsolutePath(),Toast.LENGTH_SHORT).show(); + + continueserver=false; + while(true){ + if(serverThreadDone){ + syncLibrary(); + break; + } + } + + + } + + else if(item.getItemId()==1){ + try{ + String shuffleText = getInfo("shuffle",null); + if(shuffleText.equals("off")) + Toast.makeText(main.this,"Shuffle mode off",Toast.LENGTH_SHORT).show(); + else if(shuffleText.equals("song") || shuffleText.equals("Artist") || shuffleText.equals("Album") || shuffleText.equals("Score") || shuffleText.equals("Rating")) + Toast.makeText(main.this,"Shuffle mode by "+shuffleText,Toast.LENGTH_SHORT).show(); + + }catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + serverpoke.interrupt(); + } + else if(item.getItemId()==2){ + try{ + String repeatText = getInfo("repeat",null); + if(repeatText.equals("off")||repeatText.equals("single")||repeatText.equals("all")){ + Toast.makeText(main.this,"Repeat mode "+repeatText,Toast.LENGTH_SHORT).show(); + } + }catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + serverpoke.interrupt(); + } + + return true; + } + + public void sendCommand(String action, String params) throws Exception{ + String formattedAction = action+'/'+params; + + this.s = new Socket(server,port); + this.os = this.s.getOutputStream(); + this.os.write(formattedAction.getBytes(), 0, formattedAction.length()); + + } + + public String getInfo(String action, String params) throws Exception{ + String data=null; + String formattedAction = action+'/'+params; + this.s = new Socket(server,port); + this.os = this.s.getOutputStream(); + this.is = this.s.getInputStream(); + this.os.write(formattedAction.getBytes(), 0, formattedAction.length()); + int byteCount = -1; + byteArrayOutputStream.reset(); + while ((byteCount = this.is.read(byteBuff, 0, byteBuff.length)) != -1) { + byteArrayOutputStream.write(byteBuff, 0, byteCount); + } + data = byteArrayOutputStream.toString(); + return data; + } + public static Bitmap getCover(String server, int port){ + Bitmap decoded = null; + String command="coverImage/"; + try { + Socket s = new Socket(server,port); + OutputStream os = s.getOutputStream(); + InputStream is = s.getInputStream(); + os.write(command.getBytes(), 0, command.length()); + decoded = BitmapFactory.decodeStream(is); + } catch (IOException e) { + } + return decoded; + } + + + +public void syncLibrary(){ + Intent i = new Intent(main.this, Sync.class); + i.putExtra("ip", server); + i.putExtra("port",port); + startActivityForResult(i,1); +} + + + + + public boolean coverExists() throws Exception{ + String data=null; + String action="coverExists/"; + boolean done=false; + while(!done){ + this.s = new Socket(server,port); + this.os = this.s.getOutputStream(); + this.is = this.s.getInputStream(); + this.os.write(action.getBytes(), 0, action.length()); + int byteCount = -1; + byteArrayOutputStream.reset(); + while ((byteCount = this.is.read(byteBuff, 0, byteBuff.length)) != -1) { + byteArrayOutputStream.write(byteBuff, 0, byteCount); + } + data = byteArrayOutputStream.toString(); + if(data.equals("true")||data.equals("false")){ + done=true; + } + } + return Boolean.parseBoolean(data); + } + + public int getInfoInt(String action,String params){ + int n=-1; + boolean done=false; + while(!done){ + try{ + n = Integer.parseInt(getInfo(action,params)); + done=true; + } + catch(NumberFormatException e){ + done=false; + } + catch(Exception e){ + + } + } + return n; + } + public void getAllInfo() throws Exception{ + //Toast.makeText(main.this,"Inside",Toast.LENGTH_SHORT).show(); + String everything = getInfo("all",null); + boolean done=false; + while(!done){ + if(everything!=null){ + String resultArray[] = new String[7]; + resultArray = everything.split("/"); + istatus = resultArray[0]; + salbum = resultArray[1]; + sartist = resultArray[2]; + strack = resultArray[3]; + try { + iseekposition = Integer.parseInt(resultArray[4]); + iseektotal = Integer.parseInt(resultArray[5]); + isCover = Boolean.parseBoolean(resultArray[6]); + if(resultArray[6].equals("false") || resultArray[6].equals("true")){ + done=true; + } + } + catch(NumberFormatException e){ + done=false; + } + catch(Exception e) { + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + + } + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + continueserver = false; + this.serverpoke.interrupt(); + //if(this.getDB.isAlive()) + //this.getDB.interrupt(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + super.onActivityResult(requestCode, resultCode, data); + if(requestCode==0){ + if(resultCode==RESULT_OK){ + Bundle extras = data.getExtras(); + server = extras.getString("ip"); + port = extras.getInt("port"); + } + try { + istatus = getInfo("status",null); + } catch (Exception e) { + } + + if(!istatus.contains("idle")){ + try{ + getAllInfo(); + }catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + bcover=no_cover; + if(isCover) + bcover = getCover(server,port); + update.sendEmptyMessage(FULL_UPDATE); + } + } + else if(requestCode==1){ + if(resultCode==RESULT_OK+1){ + Toast.makeText(main.this,"Something went wrong, please try resynching.",Toast.LENGTH_LONG).show(); + } + else if(resultCode==RESULT_OK+2){ + Toast.makeText(main.this,"Out of device memory. Please copy the banshee.db file manually.",Toast.LENGTH_LONG).show(); + } + } + else if(requestCode==2){ + if(resultCode==RESULT_OK){ + Bundle extras = data.getExtras(); + String Uri = extras.getString("Uri"); + String safeUri = Uri.replace('/','*'); + try { + sendCommand("play",safeUri); + } catch (Exception e) { + Toast.makeText(main.this,"Something went wrong enqueuing.",Toast.LENGTH_LONG).show(); + + } + } + } + + continueserver = true; + //connected = true; + if(!this.serverpoke.isAlive()) + this.serverpoke.start(); + + } + public void displaySettings(){ + Intent i = new Intent(main.this,Settings.class); + //Intent i = new Intent(main.this,Browse.class); + startActivityForResult(i,0); + } + + + + @Override + public Object onRetainNonConfigurationInstance(){ + BansheeInstance data = new BansheeInstance(istatus, bcover, strack, sartist, salbum, iseekposition, iseektotal, isCover, server, port); + return data; + } + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + int action = event.getAction(); + int keyCode = event.getKeyCode(); + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + if (action == KeyEvent.ACTION_UP) { + try{ + sendCommand("volumeUp",null); + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + + } + } + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + if (action == KeyEvent.ACTION_UP) { + try{ + sendCommand("volumeDown",null); + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + + } + } + return true; + default: + return super.dispatchKeyEvent(event); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setup(R.layout.main); + Bundle extras = getIntent().getExtras(); + BansheeInstance data = (BansheeInstance)getLastNonConfigurationInstance(); + if(data==null){ + server = extras.getString("ip"); + port = extras.getInt("port"); + + try { + istatus = getInfo("status",null); + } catch (Exception e) { + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + if(istatus!=null){ + if(!istatus.contains("idle")){ + try{ + getAllInfo(); + }catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + bcover=no_cover; + if(isCover) + bcover = getCover(server,port); + } + } + } + else{ + server = data.ip; + port = data.port; + istatus=data.status; + bcover = data.cover; + strack=data.track; + sartist=data.artist; + salbum=data.album; + iseekposition=data.iseekposition; + iseektotal=data.iseektotal; + } + update.sendEmptyMessage(FULL_UPDATE); + continueserver = true; + if(!this.serverpoke.isAlive()) + this.serverpoke.start(); + } + private void setup(int content){ + setContentView(content); + this.prev = (ImageButton)this.findViewById(R.id.prev); + this.playpause = (ImageButton)this.findViewById(R.id.playpause); + this.next = (ImageButton)this.findViewById(R.id.next); + //this.mute = (ImageButton)this.findViewById(R.id.mute); + this.track = (TextView)this.findViewById(R.id.track); + this.artist = (TextView)this.findViewById(R.id.artist); + this.album = (TextView)this.findViewById(R.id.album); + this.seekposition = (TextView)this.findViewById(R.id.seek_position); + this.seektotal = (TextView)this.findViewById(R.id.seek_total); + this.artists = (ImageButton)this.findViewById(R.id.artists); + this.albums = (ImageButton)this.findViewById(R.id.albums); + this.songs = (ImageButton)this.findViewById(R.id.songs); + this.seekbar = (SeekBar)this.findViewById(R.id.seekbar); + this.cover = (ImageView)this.findViewById(R.id.cover); + this.tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE); + this.no_cover=BitmapFactory.decodeResource(getResources(),R.drawable.no_cover_art); + //this.tm.listen(this.phoneListener,PhoneStateListener.LISTEN_CALL_STATE); + this.phoneListener = new PhoneStateListener(){ + public void onCallStateChanged(int state, String incomingNumber){ + if(state==TelephonyManager.CALL_STATE_RINGING){ + if(istatus.equals("playing")){ + try{ + sendCommand("playPause",null); + }catch(Exception e){ + Toast.makeText(main.this,"Could not pause for incoming call",Toast.LENGTH_SHORT).show(); + + } + } + } + } + }; + this.tm.listen(this.phoneListener,PhoneStateListener.LISTEN_CALL_STATE); + this.prev.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v,MotionEvent me) { + try{ + if (me.getAction() == MotionEvent.ACTION_DOWN) { + prev.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + prev.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + sendCommand("prev",null); + //update.sendEmptyMessage(FULL_UPDATE); + return true; + } + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return false; + } + }); + + + + + + this.playpause.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View arg0, MotionEvent me) { + if (me.getAction() == MotionEvent.ACTION_DOWN) { + playpause.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + playpause.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + try{ + sendCommand("playPause",null); + update.sendEmptyMessage(FULL_UPDATE); + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return true; + } + return false; + } + + }); + + this.next.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v,MotionEvent me) { + try{ + if (me.getAction() == MotionEvent.ACTION_DOWN) { + next.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + next.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + sendCommand("next",null); + update.sendEmptyMessage(FULL_UPDATE); + return true; + } + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return false; + //sendCommand("prev",null); + /* + getAllInfo(); + bcover=null; + if(isCover){ + bcover = getCover(server,port); + } + update.sendEmptyMessage(FULL_UPDATE); + serverpoke.interrupt(); + */ + } + }); + + + this.artists.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v,MotionEvent me) { + try{ + if (me.getAction() == MotionEvent.ACTION_DOWN) { + artists.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + artists.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + Intent i = new Intent(main.this,ArtistBrowse.class); + startActivityForResult(i,2); + return true; + } + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return false; + } + }); + + this.albums.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v,MotionEvent me) { + try{ + if (me.getAction() == MotionEvent.ACTION_DOWN) { + albums.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + albums.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + Intent i = new Intent(main.this,AlbumBrowse.class); + i.putExtra("Artist", "Albums"); + startActivityForResult(i,2); + return true; + } + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return false; + } + }); + + this.songs.setOnTouchListener(new OnTouchListener() { + public boolean onTouch(View v,MotionEvent me) { + try{ + if (me.getAction() == MotionEvent.ACTION_DOWN) { + songs.setColorFilter(Color.CYAN, PorterDuff.Mode.SRC_ATOP); + return false; + } else if (me.getAction() == MotionEvent.ACTION_UP) { + songs.setColorFilter(Color.parseColor("#00000000"), PorterDuff.Mode.SRC_ATOP); + Intent i = new Intent(main.this,SongBrowse.class); + i.putExtra("Album", "Songs"); + i.putExtra("AlbumID", -1); + startActivityForResult(i,2); + return true; + } + } + catch(Exception e){ + Toast.makeText(main.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + return false; + } + }); + + + + this.seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) { + if(fromTouch){ + try{ + sendCommand("seek",Integer.toString(progress)); + iseekposition=progress; + update.sendEmptyMessage(PARTIAL_UPDATE); + }catch(Exception e){ + //Toast.makeText(BansheeRemote.this,"Can't connect to Server. Check your settings.",Toast.LENGTH_SHORT).show(); + } + } + } + + + + public void onStartTrackingTouch(SeekBar seekBar) { + } + + public void onStopTrackingTouch(SeekBar seekBar) { + } + }); + + } + + public static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + public static byte[] byteBuff = new byte[1024]; + + +}
\ No newline at end of file diff --git a/src/AndroidRemote/AndroidRemote.addin.xml b/src/AndroidRemote/AndroidRemote.addin.xml new file mode 100644 index 0000000..3167df7 --- /dev/null +++ b/src/AndroidRemote/AndroidRemote.addin.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<Addin + id="Banshee.AndroidRemote" + version="1.0" + compatVersion="1.0" + copyright="Copyright © 2013 Nikitas Stamatopoulos. Licensed under the MIT X11 license." + name="Android Remote" + category="Community Extensions" + description="Control Banshee from an Android device over the internet." + author="Nikitas Stamatopoulos/Kristopher Dick" + url="http://gitorious.org/banshee-community-extension/" + defaultEnabled="false"> + + <Localizer type="Gettext" catalog="banshee-community-extensions" location="../../../share/locale"/> + + <Dependencies> + <Addin id="Banshee.Services" version="1.0"/> + <Addin id="Banshee.ThickClient" version="1.0"/> + </Dependencies> + + + + <Extension path="/Banshee/ServiceManager/Service"> + <Service class="Banshee.AndroidRemote.AndroidRemoteService"/> + </Extension> + +</Addin> diff --git a/src/AndroidRemote/AndroidRemote.csproj b/src/AndroidRemote/AndroidRemote.csproj new file mode 100644 index 0000000..2b75e88 --- /dev/null +++ b/src/AndroidRemote/AndroidRemote.csproj @@ -0,0 +1,103 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>8.0.50727</ProductVersion> + <ProjectGuid>{696EF9D2-3F3E-4FF9-9D8C-E26C74DD8563}</ProjectGuid> + <OutputType>Library</OutputType> + <UseParentDirectoryAsNamespace>true</UseParentDirectoryAsNamespace> + <AssemblyName>Banshee.AndroidRemote</AssemblyName> + <SchemaVersion>2.0</SchemaVersion> + <TargetFrameworkVersion>v3.5</TargetFrameworkVersion> + <Optimize>true</Optimize> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow> + <RootNamespace>Foo</RootNamespace> + <AssemblyOriginatorKeyFile>.</AssemblyOriginatorKeyFile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <OutputPath>..\..\..\bin</OutputPath> + <CustomCommands> + <CustomCommands> + <Command type="Execute" command="make run" workingdir="${SolutionDir}" /> + </CustomCommands> + </CustomCommands> + <WarningLevel>4</WarningLevel> + <Optimize>false</Optimize> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Windows|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <OutputPath>..\..\..\bin</OutputPath> + <PlatformTarget>x86</PlatformTarget> + <WarningLevel>4</WarningLevel> + <Optimize>false</Optimize> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> + <Package>gtk-sharp-2.0</Package> + </Reference> + <Reference Include="Mono.Posix" /> + <Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"> + <Package>gtk-sharp-2.0</Package> + </Reference> + <Reference Include="Mono.Cairo"> + <SpecificVersion>False</SpecificVersion> + </Reference> + <Reference Include="Mono.Addins"> + <SpecificVersion>False</SpecificVersion> + <Package>mono-addins</Package> + </Reference> + <Reference Include="Banshee.Core, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-core</Package> + </Reference> + <Reference Include="Banshee.Services, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-services</Package> + </Reference> + <Reference Include="Banshee.ThickClient, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-thickclient</Package> + </Reference> + <Reference Include="Banshee.Widgets, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-thickclient</Package> + </Reference> + <Reference Include="Hyena, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-hyena</Package> + </Reference> + <Reference Include="Hyena.Data.Sqlite, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-hyena-data-sqlite</Package> + </Reference> + <Reference Include="Hyena.Gui, Version=1.7.0.0, Culture=neutral"> + <Package>banshee-hyena-gui</Package> + </Reference> + <Reference Include="System.Core" /> + </ItemGroup> + <ItemGroup> + <EmbeddedResource Include="AndroidRemote.addin.xml"> + <LogicalName>AndroidRemote.addin.xml</LogicalName> + </EmbeddedResource> + </ItemGroup> + <ItemGroup> + <Compile Include="Banshee.AndroidRemote\AndroidRemoteSource.cs" /> + </ItemGroup> + <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> + <ProjectExtensions> + <MonoDevelop> + <Properties> + <MonoDevelop.Autotools.MakefileInfo IntegrationEnabled="true" RelativeMakefileName="Makefile.am"> + <BuildFilesVar Sync="true" Name="SOURCES" /> + <DeployFilesVar /> + <ResourcesVar Sync="true" Name="RESOURCES" /> + <OthersVar /> + <GacRefVar /> + <AsmRefVar /> + <ProjectRefVar /> + </MonoDevelop.Autotools.MakefileInfo> + </Properties> + </MonoDevelop> + </ProjectExtensions> +</Project> diff --git a/src/AndroidRemote/Banshee.AndroidRemote/AndroidRemoteSource.cs b/src/AndroidRemote/Banshee.AndroidRemote/AndroidRemoteSource.cs new file mode 100644 index 0000000..06eace6 --- /dev/null +++ b/src/AndroidRemote/Banshee.AndroidRemote/AndroidRemoteSource.cs @@ -0,0 +1,422 @@ +// +// AndroidRemoteSource.cs +// +// Authors: +// Nikitas Stamatopoulos / Kristopher Dick +// +// Copyright (C) 2013 Nikitas Stamatopoulos +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.IO; + +using Mono.Unix; +using Mono.Addins; + +using Banshee.Collection; +using Banshee.Sources; +using Banshee.PlaybackController; +using Banshee.ServiceStack; +using Banshee.Preferences; +using Banshee.Configuration; + +using Hyena; + +namespace Banshee.AndroidRemote +{ + + public class AndroidRemoteService : IExtensionService, IDisposable + { + Socket bansheeServerConn; + ushort volume = ServiceManager.PlayerEngine.Volume; + byte[] socketBuffer = new byte[5000]; + + private PreferenceBase port_pref; + PreferenceService bansheePrefs; + int port; + + string IService.ServiceName + { + get { return "AndroidRemote"; } + } + + void IExtensionService.Initialize() + { + InstallPreferences(); + Console.WriteLine("AndroidRemote: Preferences installed"); + + bansheePrefs["RemoteControl"]["AndroidRemote"]["remote_control_port"].ValueChanged += delegate { + listen(); + }; + + listen(); + } + + void IDisposable.Dispose() + { + UninstallPreferences(); + bansheeServerConn.Close(); + } + + public void listen () + { + if (bansheeServerConn != null) + { + bansheeServerConn.Disconnect(false); + } + + port = (int) bansheePrefs["RemoteControl"]["AndroidRemote"]["remote_control_port"].BoxedValue; + Console.WriteLine("AndroidRemote will listen on port " + port.ToString()); + IPEndPoint bansheeServer_ep = new IPEndPoint (IPAddress.Any, port); + + bansheeServerConn = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + bansheeServerConn.Bind(bansheeServer_ep); + bansheeServerConn.Listen(1); + bansheeServerConn.BeginAccept(new AsyncCallback(OnIncomingConnection), bansheeServerConn); + } + + void OnIncomingConnection (IAsyncResult ar) + { + try + { + Socket client = ((Socket)ar.AsyncState).EndAccept(ar); + client.BeginReceive(socketBuffer, 0, socketBuffer.Length, SocketFlags.None, OnSocketReceive,client); + bansheeServerConn.BeginAccept(new AsyncCallback(OnIncomingConnection), bansheeServerConn); + } + catch (Exception) + { + } + } + + void OnSocketReceive (IAsyncResult ar) { + Socket client = null; + int bytes = 0; + try + { + client = (Socket) ar.AsyncState; + bytes = client.EndReceive(ar); + + client.BeginReceive(socketBuffer, 0, socketBuffer.Length, SocketFlags.None, OnSocketReceive, client); + + + string text = Encoding.UTF8.GetString(socketBuffer,0,bytes); + string sep = "/"; + string[] remoteMessage = text.Split('/'); + string action = remoteMessage[0]; + string variable = remoteMessage[1]; + if (action.Equals("play")) + { + variable = variable.Replace('*','/'); + } + + Banshee.Collection.TrackInfo currTrack = ServiceManager.PlayerEngine.CurrentTrack; + string replyText = ""; + ushort currVol; + ushort volStep = 10; + bool replyReq = false; + string home = Environment.GetEnvironmentVariable("HOME"); + string coverPath=""; + string dbPath = home + "/.config/banshee-1/banshee.db"; + if(currTrack != null && currTrack.ArtworkId != null){ + coverPath = home + "/.cache/media-art/" + currTrack.ArtworkId.ToString() +".jpg"; + } + + switch (action) + { + case "coverImage": + byte[] coverImage = File.ReadAllBytes(coverPath); + client.Send(coverImage); + replyReq = true; + break; + + case "syncCount": + int count = System.IO.File.ReadAllBytes(dbPath).Length; + client.Send(System.Text.Encoding.UTF8.GetBytes(count.ToString())); + replyReq=true; + break; + + case "sync": + byte[] db = File.ReadAllBytes(dbPath); + client.Send(db); + replyReq = true; + break; + + case "coverExists": + replyText = coverExists(coverPath); + replyReq = true; + break; + + case "playPause": + ServiceManager.PlayerEngine.TogglePlaying(); + replyReq = true; + break; + + case "next": + ServiceManager.PlaybackController.Next(); + replyReq = true; + break; + + case "prev": + ServiceManager.PlaybackController.Previous(); + replyReq = true; + break; + + case "play": + var source = ServiceManager.SourceManager.MusicLibrary as DatabaseSource; + source.FilterQuery=""; + if(source!=null) + { + var countSongs = source.Count; + + UnknownTrackInfo track = new UnknownTrackInfo(new SafeUri(variable)); + TrackInfo trackTemp = null; + for(int i=0; i<countSongs; i++) + { + trackTemp = source.TrackModel [i]; + if(trackTemp.TrackEqual(track)) + { + break; + } + } + if(trackTemp != null) + ServiceManager.PlayerEngine.OpenPlay (trackTemp); + } + replyReq = true; + break; + + case "volumeDown": + currVol = ServiceManager.PlayerEngine.Volume; + if (currVol < 10) + { + ServiceManager.PlayerEngine.Volume = 0; + } + else + { + ServiceManager.PlayerEngine.Volume = (ushort) (currVol - volStep); + } + replyReq = true; + break; + + case "volumeUp": + currVol = ServiceManager.PlayerEngine.Volume; + if (currVol > 90) + { + ServiceManager.PlayerEngine.Volume = 100; + } + else + { + ServiceManager.PlayerEngine.Volume = (ushort) (currVol + volStep); + } + replyReq = true; + break; + + case "mute": + currVol = ServiceManager.PlayerEngine.Volume; + if (currVol > 0) + { + volume = currVol; + ServiceManager.PlayerEngine.Volume = 0; + } + else + { + ServiceManager.PlayerEngine.Volume = volume; + } + replyReq = true; + break; + case "status": + replyText = ServiceManager.PlayerEngine.CurrentState.ToString().ToLower(); + replyReq = true; + break; + + case "album": + replyText = currTrack.DisplayAlbumTitle; + replyReq = true; + break; + + case "artist": + replyText = currTrack.DisplayArtistName; + replyReq = true; + break; + + case "title": + replyText = currTrack.DisplayTrackTitle; + replyReq = true; + break; + case "trackCurrentTime": + replyText = (ServiceManager.PlayerEngine.Position/1000).ToString(); + replyReq = true; + break; + + case "trackTotalTime": + replyText = currTrack.Duration.ToString(); + replyReq = true; + break; + + case "seek": + ServiceManager.PlayerEngine.Position = UInt32.Parse(variable)*1000; + replyReq = true; + break; + + case "shuffle": + if (ServiceManager.PlaybackController.ShuffleMode.ToString() == "off") + { + ServiceManager.PlaybackController.ShuffleMode = "song"; + replyText = "song"; + } + else if(ServiceManager.PlaybackController.ShuffleMode.ToString() == "song") + { + ServiceManager.PlaybackController.ShuffleMode = "artist"; + replyText = "Artist"; + } + else if(ServiceManager.PlaybackController.ShuffleMode.ToString() == "artist") + { + ServiceManager.PlaybackController.ShuffleMode = "album"; + replyText = "Album"; + } + else if(ServiceManager.PlaybackController.ShuffleMode.ToString() == "album") + { + ServiceManager.PlaybackController.ShuffleMode = "rating"; + replyText = "Rating"; + } + else if(ServiceManager.PlaybackController.ShuffleMode.ToString() == "rating") + { + ServiceManager.PlaybackController.ShuffleMode = "score"; + replyText = "Score"; + } + else + { + ServiceManager.PlaybackController.ShuffleMode = "off"; + replyText = "off"; + } + replyReq = true; + break; + + case "repeat": + if (ServiceManager.PlaybackController.RepeatMode == PlaybackRepeatMode.None) + { + ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.RepeatAll; + replyText = "all"; + } + else if (ServiceManager.PlaybackController.RepeatMode == PlaybackRepeatMode.RepeatAll) + { + ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.RepeatSingle; + replyText = "single"; + } + else + { + ServiceManager.PlaybackController.RepeatMode = PlaybackRepeatMode.None; + replyText = "off"; + } + replyReq = true; + break; + + case "all": + replyText = ServiceManager.PlayerEngine.CurrentState.ToString().ToLower() + sep; + replyText += currTrack.DisplayAlbumTitle.Replace('/','\\') + sep; + replyText += currTrack.DisplayArtistName.Replace('/','\\') + sep; + replyText += currTrack.DisplayTrackTitle.Replace('/','\\') + sep; + replyText += ((uint) (ServiceManager.PlayerEngine.Position/1000)).ToString() + sep; + replyText += ((uint) (currTrack.Duration.TotalSeconds)).ToString() + sep; + replyText += coverExists(coverPath); + replyReq = true; + break; + + case "test": + replyText = ""; + replyReq = true; + break; + + default: + replyText = ""; + replyReq = false; + break; + } + + byte[] messageByte = System.Text.Encoding.UTF8.GetBytes(replyText); + + if (replyReq) + { + reply(client, messageByte); + } + client.Close(); + } + catch(Exception) + { + } + } + + void reply (Socket remoteClient, byte[] reply) + { + remoteClient.Send(reply); + } + + string coverExists(string coverPath) + { + string retVal = "false"; + if (System.IO.File.Exists(coverPath)) + { + if (System.IO.File.ReadAllBytes(coverPath).Length < 110000) + { + retVal = "true"; + } + } + return retVal; + } + + private void InstallPreferences() + { + bansheePrefs = ServiceManager.Get<PreferenceService>(); + + if (bansheePrefs == null) + { + return; + } + Page remoteControlPage = new Page("RemoteControl", "Remote Control", 3); + bansheePrefs.FindOrAdd(remoteControlPage); + + Section BansheeRemotePrefs = remoteControlPage.FindOrAdd(new Section("AndroidRemote", "Android Remote", 0)); + + port_pref = BansheeRemotePrefs.Add (new SchemaPreference<int>( + RemotePortSchema, + Catalog.GetString("Android Remote port"), + Catalog.GetString("Banshee will listen for the Android Banshee Remote app on this port"))); + } + + private void UninstallPreferences() + { + Console.WriteLine("AndroidRemote: UninstallPreferences() called"); + bansheePrefs["RemoteControl"]["AndroidRemote"].Remove(port_pref); + bansheePrefs["RemoteControl"].Remove(bansheePrefs["RemoteControl"].FindById("AndroidRemote")); + bansheePrefs.Remove(bansheePrefs.FindById("RemoteControl")); + } + + public static readonly SchemaEntry<int> RemotePortSchema = new SchemaEntry<int> ( + "remote_control", "remote_control_port", + 8484,1024,49151, + "Android Remote Port", + "Android Remote will listen for the Android Banshee Remote app on this port" + ); + } +} diff --git a/src/AndroidRemote/Makefile.am b/src/AndroidRemote/Makefile.am new file mode 100644 index 0000000..2faedaf --- /dev/null +++ b/src/AndroidRemote/Makefile.am @@ -0,0 +1,8 @@ +ASSEMBLY = Banshee.AndroidRemote +LINK = $(BANSHEE_LIBS) + +SOURCES = Banshee.AndroidRemote/AndroidRemoteSource.cs + +RESOURCES = AndroidRemote.addin.xml + +include $(top_srcdir)/build/build.mk diff --git a/src/Makefile.am b/src/Makefile.am index e80fff0..d18e853 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,6 +2,7 @@ SUBDIRS = \ AlarmClock \ AlbumArtWriter \ Ampache \ + AndroidRemote \ AppIndicator \ Awn \ ClutterFlow \ |