summaryrefslogtreecommitdiff
path: root/androvdr
diff options
context:
space:
mode:
Diffstat (limited to 'androvdr')
-rw-r--r--androvdr/.classpath7
-rw-r--r--androvdr/.project33
-rw-r--r--androvdr/.settings/org.eclipse.jdt.core.prefs12
-rw-r--r--androvdr/AndroidManifest.xml29
-rw-r--r--androvdr/default.properties11
-rw-r--r--androvdr/res/drawable-hdpi/icon.pngbin0 -> 4147 bytes
-rw-r--r--androvdr/res/drawable-ldpi/icon.pngbin0 -> 1723 bytes
-rw-r--r--androvdr/res/drawable-mdpi/icon.pngbin0 -> 2574 bytes
-rw-r--r--androvdr/res/drawable/channels.gifbin0 -> 106 bytes
-rw-r--r--androvdr/res/drawable/settings.gifbin0 -> 104 bytes
-rw-r--r--androvdr/res/drawable/timer_active.pngbin0 -> 202 bytes
-rw-r--r--androvdr/res/drawable/timer_inactive.pngbin0 -> 232 bytes
-rw-r--r--androvdr/res/drawable/timer_none.pngbin0 -> 102 bytes
-rw-r--r--androvdr/res/drawable/timer_recording.pngbin0 -> 248 bytes
-rw-r--r--androvdr/res/drawable/timers.gifbin0 -> 86 bytes
-rw-r--r--androvdr/res/drawable/vdr_logo.jpgbin0 -> 12240 bytes
-rw-r--r--androvdr/res/drawable/whatson.gifbin0 -> 107 bytes
-rw-r--r--androvdr/res/layout/channel_item.xml21
-rw-r--r--androvdr/res/layout/channel_list.xml10
-rw-r--r--androvdr/res/layout/epg_detail.xml84
-rw-r--r--androvdr/res/layout/epg_list.xml50
-rw-r--r--androvdr/res/layout/epg_search.xml32
-rw-r--r--androvdr/res/layout/epg_search_times_item.xml8
-rw-r--r--androvdr/res/layout/epg_search_times_list.xml25
-rw-r--r--androvdr/res/layout/event_item.xml40
-rw-r--r--androvdr/res/layout/main.xml21
-rw-r--r--androvdr/res/layout/timer_detail.xml99
-rw-r--r--androvdr/res/layout/timer_list.xml11
-rw-r--r--androvdr/res/layout/vdrmanager.xml28
-rw-r--r--androvdr/res/layout/vdrmanager_menu_item.xml21
-rw-r--r--androvdr/res/layout/video.xml27
-rw-r--r--androvdr/res/menu/channel_list_item_menu.xml11
-rw-r--r--androvdr/res/menu/epg_list_item_menu.xml17
-rw-r--r--androvdr/res/menu/epg_list_menu.xml11
-rw-r--r--androvdr/res/menu/epg_search_time_item_menu.xml8
-rw-r--r--androvdr/res/menu/main_menu.xml14
-rw-r--r--androvdr/res/values/action_menu.xml10
-rw-r--r--androvdr/res/values/application.xml4
-rw-r--r--androvdr/res/values/channel_list_menu.xml7
-rw-r--r--androvdr/res/values/common.xml6
-rw-r--r--androvdr/res/values/epg.xml18
-rw-r--r--androvdr/res/values/epg_list_menu.xml13
-rw-r--r--androvdr/res/values/epg_search_times.xml6
-rw-r--r--androvdr/res/values/errors.xml6
-rw-r--r--androvdr/res/values/main_menu.xml8
-rw-r--r--androvdr/res/values/preferences.xml49
-rw-r--r--androvdr/res/values/preferences_keys.xml29
-rw-r--r--androvdr/res/values/progress.xml20
-rw-r--r--androvdr/res/values/strings.xml5
-rw-r--r--androvdr/res/values/timers.xml13
-rw-r--r--androvdr/res/xml/preferences.xml103
-rw-r--r--androvdr/src/de/bjusystems/androvdr/app/AndroVdrApp.java134
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/AliveState.java36
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/Channel.java41
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/Epg.java65
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/EpgSearchParams.java43
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValue.java49
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValues.java62
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/Event.java21
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/EventFormatter.java43
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/EventListItem.java100
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/MenuActionHandler.java16
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/Preferences.java312
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/Timer.java186
-rw-r--r--androvdr/src/de/bjusystems/androvdr/data/WakeupState.java36
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/AndroVdrActivity.java228
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/ChannelAdapter.java75
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/ChannelHolder.java9
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/ChannelListActivity.java187
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EpgDetailsActivity.java91
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EpgListActivity.java408
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EpgSearchActivity.java63
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EpgSearchTimesListActivity.java130
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EventAdapter.java171
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/EventListItemHolder.java12
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/PreferencesActivity.java34
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/SvdrpProgressDialog.java72
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/TimerDetailsActivity.java232
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/TimerListActivity.java238
-rw-r--r--androvdr/src/de/bjusystems/androvdr/gui/VideoActivity.java67
-rw-r--r--androvdr/src/de/bjusystems/androvdr/tasks/AsyncProgressTask.java55
-rw-r--r--androvdr/src/de/bjusystems/androvdr/tasks/DeleteTimerTask.java18
-rw-r--r--androvdr/src/de/bjusystems/androvdr/tasks/ToggleTimerTask.java25
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/date/DateFormatter.java43
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/http/HttpHelper.java263
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/AliveClient.java49
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/ChannelClient.java44
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/EpgClient.java91
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SetTimerClient.java59
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncListener.java7
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncTask.java61
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpClient.java275
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpEvent.java17
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpException.java22
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpListener.java7
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/TimerClient.java50
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/svdrp/WakeupClient.java51
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/wakeup/AsyncWakeupTask.java94
-rw-r--r--androvdr/src/de/bjusystems/androvdr/utils/wakeup/WakeupProgress.java8
99 files changed, 5327 insertions, 0 deletions
diff --git a/androvdr/.classpath b/androvdr/.classpath
new file mode 100644
index 0000000..79a8481
--- /dev/null
+++ b/androvdr/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/androvdr/.project b/androvdr/.project
new file mode 100644
index 0000000..0ebf06a
--- /dev/null
+++ b/androvdr/.project
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>AndroVdr</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/androvdr/.settings/org.eclipse.jdt.core.prefs b/androvdr/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..b95f163
--- /dev/null
+++ b/androvdr/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Fri Mar 04 00:03:01 CET 2011
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/androvdr/AndroidManifest.xml b/androvdr/AndroidManifest.xml
new file mode 100644
index 0000000..fd2376c
--- /dev/null
+++ b/androvdr/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="de.bjusystems.androvdr"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <application
+ android:icon="@drawable/icon"
+ android:label="@string/app_name" android:debuggable="true" android:name=".app.AndroVdrApp">
+ <activity android:label="@string/app_name" android:name=".gui.AndroVdrActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+<activity android:name=".gui.EpgListActivity"></activity>
+<activity android:name=".gui.TimerListActivity"></activity>
+<activity android:name=".gui.PreferencesActivity"></activity>
+<activity android:name=".gui.ChannelListActivity"></activity>
+<activity android:name=".gui.EpgDetailsActivity"></activity>
+<activity android:name=".gui.TimerDetailsActivity"></activity>
+<activity android:name=".gui.EpgSearchActivity"></activity>
+<activity android:name=".gui.EpgSearchTimesListActivity"></activity>
+<activity android:name=".gui.VideoActivity"></activity>
+</application>
+
+
+<uses-permission android:name="android.permission.INTERNET"></uses-permission>
+</manifest> \ No newline at end of file
diff --git a/androvdr/default.properties b/androvdr/default.properties
new file mode 100644
index 0000000..9d135cb
--- /dev/null
+++ b/androvdr/default.properties
@@ -0,0 +1,11 @@
+# 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,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
diff --git a/androvdr/res/drawable-hdpi/icon.png b/androvdr/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/androvdr/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/androvdr/res/drawable-ldpi/icon.png b/androvdr/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/androvdr/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/androvdr/res/drawable-mdpi/icon.png b/androvdr/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/androvdr/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/androvdr/res/drawable/channels.gif b/androvdr/res/drawable/channels.gif
new file mode 100644
index 0000000..f9874ff
--- /dev/null
+++ b/androvdr/res/drawable/channels.gif
Binary files differ
diff --git a/androvdr/res/drawable/settings.gif b/androvdr/res/drawable/settings.gif
new file mode 100644
index 0000000..5d36e7c
--- /dev/null
+++ b/androvdr/res/drawable/settings.gif
Binary files differ
diff --git a/androvdr/res/drawable/timer_active.png b/androvdr/res/drawable/timer_active.png
new file mode 100644
index 0000000..7b67f94
--- /dev/null
+++ b/androvdr/res/drawable/timer_active.png
Binary files differ
diff --git a/androvdr/res/drawable/timer_inactive.png b/androvdr/res/drawable/timer_inactive.png
new file mode 100644
index 0000000..c7a75c4
--- /dev/null
+++ b/androvdr/res/drawable/timer_inactive.png
Binary files differ
diff --git a/androvdr/res/drawable/timer_none.png b/androvdr/res/drawable/timer_none.png
new file mode 100644
index 0000000..dbf17ad
--- /dev/null
+++ b/androvdr/res/drawable/timer_none.png
Binary files differ
diff --git a/androvdr/res/drawable/timer_recording.png b/androvdr/res/drawable/timer_recording.png
new file mode 100644
index 0000000..2031530
--- /dev/null
+++ b/androvdr/res/drawable/timer_recording.png
Binary files differ
diff --git a/androvdr/res/drawable/timers.gif b/androvdr/res/drawable/timers.gif
new file mode 100644
index 0000000..3577dab
--- /dev/null
+++ b/androvdr/res/drawable/timers.gif
Binary files differ
diff --git a/androvdr/res/drawable/vdr_logo.jpg b/androvdr/res/drawable/vdr_logo.jpg
new file mode 100644
index 0000000..bba3a1f
--- /dev/null
+++ b/androvdr/res/drawable/vdr_logo.jpg
Binary files differ
diff --git a/androvdr/res/drawable/whatson.gif b/androvdr/res/drawable/whatson.gif
new file mode 100644
index 0000000..5a35904
--- /dev/null
+++ b/androvdr/res/drawable/whatson.gif
Binary files differ
diff --git a/androvdr/res/layout/channel_item.xml b/androvdr/res/layout/channel_item.xml
new file mode 100644
index 0000000..dd09400
--- /dev/null
+++ b/androvdr/res/layout/channel_item.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/channel_item"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="5dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+ <ImageView
+ android:id="@+id/channel_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/androvdr/res/layout/channel_list.xml b/androvdr/res/layout/channel_list.xml
new file mode 100644
index 0000000..dd6ec31
--- /dev/null
+++ b/androvdr/res/layout/channel_list.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+ <ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/channel_list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:cacheColorHint="?android:attr/colorBackground"/>
diff --git a/androvdr/res/layout/epg_detail.xml b/androvdr/res/layout/epg_detail.xml
new file mode 100644
index 0000000..7752819
--- /dev/null
+++ b/androvdr/res/layout/epg_detail.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/epg_detail_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
+
+ <LinearLayout
+ android:id="@+id/epg_detail_time_channel"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/epg_detail_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="left"
+ android:layout_weight="1"/>
+
+ <TextView
+ android:id="@+id/epg_detail_channel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="right"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/epg_detail_date"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="left"
+ android:layout_below="@id/epg_detail_time"/>
+
+ <TextView
+ android:id="@+id/epg_detail_separator_0"
+ android:layout_width="fill_parent"
+ android:layout_height="2sp"/>
+
+ <TextView
+ android:id="@+id/epg_detail_separator_1"
+ android:layout_width="fill_parent"
+ android:layout_height="1sp"/>
+
+ <ScrollView
+ android:id="@+id/epg_detail_description_scroll"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+
+ <TextView
+ android:id="@+id/epg_detail_description"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ </TextView>
+
+ </ScrollView>
+
+ <TextView
+ android:id="@+id/epg_detail_separator_2"
+ android:layout_width="fill_parent"
+ android:layout_height="1sp"/>
+
+ <TextView
+ android:id="@+id/epg_detail_separator_3"
+ android:layout_width="fill_parent"
+ android:layout_height="4sp"/>
+
+ <Button
+ android:id="@+id/epg_event_create_timer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_centerHorizontal="true"
+ android:text="@string/epg_event_create_timer_text"/>
+
+</LinearLayout>
diff --git a/androvdr/res/layout/epg_list.xml b/androvdr/res/layout/epg_list.xml
new file mode 100644
index 0000000..dd44a8b
--- /dev/null
+++ b/androvdr/res/layout/epg_list.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/whatson_time"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/epg_list_time_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/epg_list_time_label"/>
+
+ <Spinner
+ android:id="@+id/epg_list_time_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/epg_list_time_label"/>
+
+ </LinearLayout>
+
+ <Spinner
+ android:id="@+id/epg_list_channel_spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:prompt="@string/epg_list_channel_spinner"/>
+
+ <ListView
+ android:id="@+id/whatson_list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_below="@id/epg_list_time_spinner"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:cacheColorHint="?android:attr/colorBackground"/>
+
+ <TextView
+ android:id="@+id/epg_list_search_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/epg_list_search_label"/>
+
+</LinearLayout>
diff --git a/androvdr/res/layout/epg_search.xml b/androvdr/res/layout/epg_search.xml
new file mode 100644
index 0000000..4153451
--- /dev/null
+++ b/androvdr/res/layout/epg_search.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/epg_search_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
+
+ <EditText
+ android:id="@+id/epg_search_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/epg_detail_time"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <Button
+ android:id="@+id/epg_search_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:text="@string/epg_search_button"/>
+
+</LinearLayout>
+
diff --git a/androvdr/res/layout/epg_search_times_item.xml b/androvdr/res/layout/epg_search_times_item.xml
new file mode 100644
index 0000000..93aa44b
--- /dev/null
+++ b/androvdr/res/layout/epg_search_times_item.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:paddingLeft="5dp"
+ android:paddingRight="5dp"
+ android:gravity= "center_vertical"
+ android:lines="2"/>
diff --git a/androvdr/res/layout/epg_search_times_list.xml b/androvdr/res/layout/epg_search_times_list.xml
new file mode 100644
index 0000000..f2ab650
--- /dev/null
+++ b/androvdr/res/layout/epg_search_times_list.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <ListView
+ android:id="@+id/epg_search_times_list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:cacheColorHint="?android:attr/colorBackground"/>
+
+ <Button
+ android:id="@+id/epg_search_times_add"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/epg_search_times_add"
+ android:layout_alignParentBottom="true"
+ android:layout_centerHorizontal="true"
+ android:text="@string/epg_search_times_add"/>
+
+
+</RelativeLayout>
diff --git a/androvdr/res/layout/event_item.xml b/androvdr/res/layout/event_item.xml
new file mode 100644
index 0000000..aab354a
--- /dev/null
+++ b/androvdr/res/layout/event_item.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/timer_item"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="5dp">
+
+ <ImageView
+ android:id="@+id/timer_item_state"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_alignParentLeft="true"
+ android:layout_centerVertical="true"/>
+
+ <TextView
+ android:id="@+id/timer_item_time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_toRightOf="@id/timer_item_state"
+ android:gravity="left"/>
+
+ <TextView
+ android:id="@+id/timer_item_channel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_toRightOf="@id/timer_item_time"
+ android:gravity="right"/>
+
+ <TextView
+ android:id="@+id/timer_item_title"
+ android:ellipsize="end"
+ android:gravity="left"
+ android:layout_toRightOf="@id/timer_item_state"
+ android:layout_below="@id/timer_item_time"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+</RelativeLayout> \ No newline at end of file
diff --git a/androvdr/res/layout/main.xml b/androvdr/res/layout/main.xml
new file mode 100644
index 0000000..1d0e21b
--- /dev/null
+++ b/androvdr/res/layout/main.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/tabhost"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="5dp">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="5dp" />
+ </LinearLayout>
+</TabHost> \ No newline at end of file
diff --git a/androvdr/res/layout/timer_detail.xml b/androvdr/res/layout/timer_detail.xml
new file mode 100644
index 0000000..0aa5da7
--- /dev/null
+++ b/androvdr/res/layout/timer_detail.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <ScrollView
+ android:id="@+id/timer_detail_scroll"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.5">
+
+ <LinearLayout
+ android:id="@+id/timer_detail_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/timer_detail_channel_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/timer_detail_channel_title"/>
+
+ <EditText
+ android:id="@+id/timer_detail_channel"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:editable="false"/>
+
+ <TextView
+ android:id="@+id/timer_detail_title_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"
+ android:text="@string/timer_detail_title_title"/>
+
+ <EditText
+ android:id="@+id/timer_detail_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <TextView
+ android:id="@+id/timer_detail_start_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timer_detail_start_title"/>
+
+ <LinearLayout
+ android:id="@+id/timer_detail_start_daytime"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/timer_detail_start"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:editable="false"/>
+
+ <EditText
+ android:id="@+id/timer_detail_day"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:editable="false"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/timer_detail_end_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/timer_detail_end_title"/>
+
+ <EditText
+ android:id="@+id/timer_detail_end"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:editable="false"/>
+
+ <TextView
+ android:id="@+id/timer_detail_fill"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="0.5"/>
+
+ </LinearLayout>
+
+ </ScrollView>
+
+ <Button
+ android:id="@+id/timer_details_save"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:text="@string/timer_details_create_title"/>
+
+</LinearLayout>
diff --git a/androvdr/res/layout/timer_list.xml b/androvdr/res/layout/timer_list.xml
new file mode 100644
index 0000000..13cff32
--- /dev/null
+++ b/androvdr/res/layout/timer_list.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ListView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/timer_list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_alignWithParentIfMissing="true"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:cacheColorHint="?android:attr/colorBackground"
+/>
diff --git a/androvdr/res/layout/vdrmanager.xml b/androvdr/res/layout/vdrmanager.xml
new file mode 100644
index 0000000..d4ca7db
--- /dev/null
+++ b/androvdr/res/layout/vdrmanager.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/main_logo"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:src="@drawable/vdr_logo"/>
+
+<!--
+ <ListView
+ android:id="@+id/vdrmanager_menu"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/main_logo"/>
+-->
+
+ <GridView
+ android:id="@+id/vdrmanager_menu"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_below="@id/main_logo"/>
+
+</RelativeLayout>
diff --git a/androvdr/res/layout/vdrmanager_menu_item.xml b/androvdr/res/layout/vdrmanager_menu_item.xml
new file mode 100644
index 0000000..1c793d8
--- /dev/null
+++ b/androvdr/res/layout/vdrmanager_menu_item.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/vdrmanager_menu_item"
+ android:lines="2"
+ android:gravity="center_vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:paddingLeft="15dp"
+ android:paddingRight="15dp"
+ android:paddingTop="10dp"
+ android:paddingBottom="10dp"/>
+
+<!--
+<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/vdrmanager_menu_item"
+ android:lines="2"
+ android:gravity="center_vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+--> \ No newline at end of file
diff --git a/androvdr/res/layout/video.xml b/androvdr/res/layout/video.xml
new file mode 100644
index 0000000..595e02a
--- /dev/null
+++ b/androvdr/res/layout/video.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/epg_search_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:textStyle="bold"/>
+
+ <VideoView
+ android:id="@+id/video_video"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <Button
+ android:id="@+id/video_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:text="Start"/>
+
+</LinearLayout>
+
diff --git a/androvdr/res/menu/channel_list_item_menu.xml b/androvdr/res/menu/channel_list_item_menu.xml
new file mode 100644
index 0000000..7e4915c
--- /dev/null
+++ b/androvdr/res/menu/channel_list_item_menu.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/channel_item_menu_epg"
+ android:title="@string/channel_item_menu_epg"/>
+ <item
+ android:id="@+id/channel_item_menu_stream"
+ android:title="@string/channel_item_menu_stream"/>
+
+</menu> \ No newline at end of file
diff --git a/androvdr/res/menu/epg_list_item_menu.xml b/androvdr/res/menu/epg_list_item_menu.xml
new file mode 100644
index 0000000..6a38f26
--- /dev/null
+++ b/androvdr/res/menu/epg_list_item_menu.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/epg_item_menu_timer_toggle"
+ android:title="@string/epg_item_menu_timer_enable"/>
+ <item
+ android:id="@+id/epg_item_menu_timer_add"
+ android:title="@string/epg_item_menu_timer_add"/>
+ <item
+ android:id="@+id/epg_item_menu_timer_delete"
+ android:title="@string/epg_item_menu_timer_delete"/>
+ <item
+ android:id="@+id/epg_item_menu_timer_modify"
+ android:title="@string/epg_item_menu_timer_modify"/>
+
+</menu> \ No newline at end of file
diff --git a/androvdr/res/menu/epg_list_menu.xml b/androvdr/res/menu/epg_list_menu.xml
new file mode 100644
index 0000000..cb5e4cf
--- /dev/null
+++ b/androvdr/res/menu/epg_list_menu.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/epg_menu_search"
+ android:title="@string/epg_menu_search"/>
+ <item
+ android:id="@+id/epg_menu_times"
+ android:title="@string/epg_menu_times"/>
+
+</menu> \ No newline at end of file
diff --git a/androvdr/res/menu/epg_search_time_item_menu.xml b/androvdr/res/menu/epg_search_time_item_menu.xml
new file mode 100644
index 0000000..a54abf0
--- /dev/null
+++ b/androvdr/res/menu/epg_search_time_item_menu.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/epg_search_time_delete"
+ android:title="@string/common_delete"/>
+
+</menu> \ No newline at end of file
diff --git a/androvdr/res/menu/main_menu.xml b/androvdr/res/menu/main_menu.xml
new file mode 100644
index 0000000..daf4e3e
--- /dev/null
+++ b/androvdr/res/menu/main_menu.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item
+ android:id="@+id/main_menu_preferences"
+ android:title="@string/main_menu_preferences"/>
+ <item
+ android:id="@+id/main_menu_info"
+ android:title="@string/main_menu_info"/>
+ <item
+ android:id="@+id/main_menu_exit"
+ android:title="@string/main_menu_exit"/>
+
+</menu> \ No newline at end of file
diff --git a/androvdr/res/values/action_menu.xml b/androvdr/res/values/action_menu.xml
new file mode 100644
index 0000000..68d11a3
--- /dev/null
+++ b/androvdr/res/values/action_menu.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="action_menu_channels">Channels</string>
+ <string name="action_menu_timers">Timers</string>
+ <string name="action_menu_epg">EPG list</string>
+ <string name="action_menu_search">EPG search</string>
+ <string name="action_menu_wakeup">Wakeup</string>
+
+</resources>
diff --git a/androvdr/res/values/application.xml b/androvdr/res/values/application.xml
new file mode 100644
index 0000000..8e4a192
--- /dev/null
+++ b/androvdr/res/values/application.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Andro-VDR</string>
+</resources>
diff --git a/androvdr/res/values/channel_list_menu.xml b/androvdr/res/values/channel_list_menu.xml
new file mode 100644
index 0000000..7d88621
--- /dev/null
+++ b/androvdr/res/values/channel_list_menu.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="channel_item_menu_epg">Show EPG</string>
+ <string name="channel_item_menu_stream">Show live stream</string>
+
+</resources>
diff --git a/androvdr/res/values/common.xml b/androvdr/res/values/common.xml
new file mode 100644
index 0000000..9e0daec
--- /dev/null
+++ b/androvdr/res/values/common.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="common_delete">Delete</string>
+
+</resources>
diff --git a/androvdr/res/values/epg.xml b/androvdr/res/values/epg.xml
new file mode 100644
index 0000000..a1fd152
--- /dev/null
+++ b/androvdr/res/values/epg.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- What's on display -->
+ <string name="epg_list_time_label">What\'s on at</string>
+ <string name="epg_list_time_now">Now</string>
+ <string name="epg_list_time_next">Next</string>
+ <string name="epg_list_channel_spinner">Channel</string>
+ <string name="epg_list_search_label">Search results</string>
+
+ <!-- create timer -->
+ <string name="epg_event_create_timer_text">Add timer</string>
+ <string name="epg_event_modify_timer_text">Modify timer</string>
+
+ <!-- search -->
+ <string name="epg_search_button">Search</string>
+
+</resources>
diff --git a/androvdr/res/values/epg_list_menu.xml b/androvdr/res/values/epg_list_menu.xml
new file mode 100644
index 0000000..bde8085
--- /dev/null
+++ b/androvdr/res/values/epg_list_menu.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="epg_menu_search">Search EPG</string>
+ <string name="epg_menu_times">Search times</string>
+
+ <string name="epg_item_menu_timer_add">Create timer</string>
+ <string name="epg_item_menu_timer_delete">Delete timer</string>
+ <string name="epg_item_menu_timer_modify">Modify timer</string>
+ <string name="epg_item_menu_timer_enable">Enable timer</string>
+ <string name="epg_item_menu_timer_disable">Disable timer</string>
+
+</resources>
diff --git a/androvdr/res/values/epg_search_times.xml b/androvdr/res/values/epg_search_times.xml
new file mode 100644
index 0000000..851935c
--- /dev/null
+++ b/androvdr/res/values/epg_search_times.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="epg_search_times_add">Add time</string>
+
+</resources>
diff --git a/androvdr/res/values/errors.xml b/androvdr/res/values/errors.xml
new file mode 100644
index 0000000..e954a26
--- /dev/null
+++ b/androvdr/res/values/errors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="vdr_error_text">The communication with VDR has caused some error.</string>
+
+</resources>
diff --git a/androvdr/res/values/main_menu.xml b/androvdr/res/values/main_menu.xml
new file mode 100644
index 0000000..8656f0c
--- /dev/null
+++ b/androvdr/res/values/main_menu.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="main_menu_preferences">Preferences</string>
+ <string name="main_menu_info">Info</string>
+ <string name="main_menu_exit">Exit</string>
+
+</resources>
diff --git a/androvdr/res/values/preferences.xml b/androvdr/res/values/preferences.xml
new file mode 100644
index 0000000..a354345
--- /dev/null
+++ b/androvdr/res/values/preferences.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- VDR plugin preferences -->
+ <string name="vdr_preferences">Network settings</string>
+ <string name="vdr_host_title">VDR host</string>
+ <string name="vdr_host_summary">Host running VDR</string>
+ <string name="vdr_port_title">VDR plugin port </string>
+ <string name="vdr_port_summary">Port for connections to VDR plugin</string>
+ <string name="vdr_port_default">6420</string>
+ <string name="vdr_password_title">VDR plugin password</string>
+ <string name="vdr_password_summary">Password for the VDR plugin</string>
+ <string name="vdr_ssl_title">Secure connect</string>
+ <string name="vdr_ssl_summary">Use SSL for connections</string>
+
+ <!-- channel filter preferences -->
+ <string name="channel_filter_preferences">Limit channels</string>
+ <string name="channel_filter_filter_title">Limit channels</string>
+ <string name="channel_filter_filter_summary">Use only given channels</string>
+ <string name="channel_filter_last_title">Channels</string>
+ <string name="channel_filter_last_summary">Channels to use</string>
+
+ <!-- wakeup -->
+ <string name="wakeup_preferences">Remote VDR host wakeup</string>
+ <string name="wakeup_enabled_title">Can remote wakeup VDR</string>
+ <string name="wakeup_enabled_summary">Enables to remote wakeup the VDR host</string>
+ <string name="wakeup_svdrphelper_title">Use HTTP request for wakeup</string>
+ <string name="wakeup_svdrphelper_summary">Wakeup by HTTP request and not using SvdrpHelper</string>
+ <string name="wakeup_url_title">URL for remote wakeup</string>
+ <string name="wakeup_url_summary">URL for a request doing the wakeup</string>
+ <string name="wakeup_user_title">Wakeup user</string>
+ <string name="wakeup_user_summary">User for remote wakeup</string>
+ <string name="wakeup_password_title">Wakeup password</string>
+ <string name="wakeup_password_summary">Password for remote wakeup</string>
+
+ <!-- timer -->
+ <string name="timer_preferences">Timer defaults</string>
+ <string name="timer_pre_start_buffer_title">Margin at start</string>
+ <string name="timer_pre_start_buffer_summary">Minutes recording starts before the beginning of the broadcast</string>
+ <string name="timer_post_end_buffer_title">Margin at stop</string>
+ <string name="timer_post_end_buffer_summary">Minutes recording stops after the end of the broadcast</string>
+ <string name="timer_default_priority_title">Default priority</string>
+ <string name="timer_default_priority_summary">Default priority</string>
+ <string name="timer_default_primary_limit_title">Default primary limit</string>
+ <string name="timer_default_primary_limit_summary">Default primary limit</string>
+ <string name="timer_default_lifetime_title">Default lifetime</string>
+ <string name="timer_default_lifetime_summary">Default lifetime</string>
+
+</resources>
diff --git a/androvdr/res/values/preferences_keys.xml b/androvdr/res/values/preferences_keys.xml
new file mode 100644
index 0000000..d60b323
--- /dev/null
+++ b/androvdr/res/values/preferences_keys.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="vdr_host_key">svdrp_host</string>
+ <string name="vdr_port_key">svdrp_port </string>
+ <string name="vdr_password_key">svdrp_password</string>
+ <string name="vdr_ssl_key">svdrp_ssl</string>
+
+ <string name="alive_check_enabled_key">alive_check_enabled</string>
+ <string name="alive_check_interval_key">alive_check_interval</string>
+
+ <string name="channel_filter_filter_key">limit_channels</string>
+ <string name="channel_filter_last_key">last_channel</string>
+
+ <string name="wakeup_enabled_key">wakeup_enabled</string>
+ <string name="wakeup_svdrphelper_key">wakeup_http</string>
+ <string name="wakeup_url_key">wakeup_url</string>
+ <string name="wakeup_user_key">wakeup_user</string>
+ <string name="wakeup_password_key">wakeup_password</string>
+
+ <string name="timer_pre_start_buffer_key">timer_pre_start_buffer</string>
+ <string name="timer_post_end_buffer_key">timer_post_end_buffer</string>
+ <string name="timer_default_priority_key">timer_default_priority</string>
+ <string name="timer_default_primary_limit_key">timer_default_primary_limit</string>
+ <string name="timer_default_lifetime_key">timer_default_lifetime</string>
+
+ <string name="epg_search_times_key">epg_search_times</string>
+
+</resources>
diff --git a/androvdr/res/values/progress.xml b/androvdr/res/values/progress.xml
new file mode 100644
index 0000000..0995eae
--- /dev/null
+++ b/androvdr/res/values/progress.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <!-- progress -->
+ <string name="progress_connect">Connecting ...</string>
+ <string name="progress_login">Login ...</string>
+ <string name="progress_login_error">Login failed</string>
+ <string name="progress_whatson_loading">Loading EPG ...</string>
+ <string name="progress_timers_loading">Loading timers ...</string>
+ <string name="progress_channels_loading">Loading channels ...</string>
+ <string name="progress_disconnect">Disconnecting ...</string>
+ <string name="progress_wakeup_sending">Initiating wakeup request ...</string>
+ <string name="progress_wakeup_sent">Wakeup request sent</string>
+ <string name="progress_wakeup_error">Error sending wakeup request</string>
+ <string name="progress_timer_save">Saving timer ...</string>
+ <string name="progress_timer_delete">Deleting timer ...</string>
+ <string name="progress_timer_enable">Enabling timer ...</string>
+ <string name="progress_timer_disable">Disabling timer ...</string>
+
+</resources>
diff --git a/androvdr/res/values/strings.xml b/androvdr/res/values/strings.xml
new file mode 100644
index 0000000..1fcd07e
--- /dev/null
+++ b/androvdr/res/values/strings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+
+</resources>
diff --git a/androvdr/res/values/timers.xml b/androvdr/res/values/timers.xml
new file mode 100644
index 0000000..b391c72
--- /dev/null
+++ b/androvdr/res/values/timers.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="timer_detail_title_title">Title:</string>
+ <string name="timer_detail_channel_title">Channel:</string>
+ <string name="timer_detail_start_title">Start:</string>
+ <string name="timer_detail_end_title">End:</string>
+
+ <string name="timer_details_create_title">Create timer</string>
+ <string name="timer_details_save_title">Save changes</string>
+ <string name="timer_details_delete_title">Delete timer</string>
+
+</resources>
diff --git a/androvdr/res/xml/preferences.xml b/androvdr/res/xml/preferences.xml
new file mode 100644
index 0000000..6d69051
--- /dev/null
+++ b/androvdr/res/xml/preferences.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceCategory android:title="@string/vdr_preferences" android:key="vdr_preferences">
+
+ <EditTextPreference
+ android:key="@string/vdr_host_key"
+ android:title="@string/vdr_host_title"
+ android:summary="@string/vdr_host_summary"/>
+
+ <EditTextPreference
+ android:key="@string/vdr_port_key"
+ android:title="@string/vdr_port_title"
+ android:summary="@string/vdr_port_summary"
+ android:defaultValue="@string/vdr_port_default"/>
+
+ <EditTextPreference
+ android:key="@string/vdr_password_key"
+ android:title="@string/vdr_password_title"
+ android:summary="@string/vdr_password_summary"
+ android:password="true"/>
+
+ <CheckBoxPreference
+ android:key="@string/vdr_ssl_key"
+ android:title="@string/vdr_ssl_title"
+ android:summary="@string/vdr_ssl_summary"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/channel_filter_preferences" android:key="filter_preferences">
+
+ <CheckBoxPreference
+ android:key="@string/channel_filter_filter_key"
+ android:title="@string/channel_filter_filter_title"
+ android:summary="@string/channel_filter_filter_summary"/>
+
+ <EditTextPreference
+ android:key="@string/channel_filter_last_key"
+ android:title="@string/channel_filter_last_title"
+ android:summary="@string/channel_filter_last_summary"
+ android:defaultValue="1"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/wakeup_preferences" android:key="wakeup_preferences">
+
+ <CheckBoxPreference
+ android:key="@string/wakeup_enabled_key"
+ android:title="@string/wakeup_enabled_title"
+ android:summary="@string/wakeup_enabled_summary"/>
+
+ <CheckBoxPreference
+ android:key="@string/wakeup_svdrphelper_key"
+ android:title="@string/wakeup_svdrphelper_title"
+ android:summary="@string/wakeup_svdrphelper_summary"/>
+
+ <EditTextPreference
+ android:key="@string/wakeup_url_key"
+ android:title="@string/wakeup_url_title"
+ android:summary="@string/wakeup_url_summary"/>
+
+ <EditTextPreference
+ android:key="@string/wakeup_user_key"
+ android:title="@string/wakeup_user_title"
+ android:summary="@string/wakeup_user_summary"/>
+
+ <EditTextPreference
+ android:key="@string/wakeup_password_key"
+ android:title="@string/wakeup_password_title"
+ android:summary="@string/wakeup_password_summary"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory android:title="@string/timer_preferences" android:key="timer_preferences">
+
+ <EditTextPreference
+ android:key="@string/timer_pre_start_buffer_key"
+ android:title="@string/timer_pre_start_buffer_title"
+ android:summary="@string/timer_pre_start_buffer_summary"
+ android:defaultValue="5"/>
+
+ <EditTextPreference
+ android:key="@string/timer_post_end_buffer_key"
+ android:title="@string/timer_post_end_buffer_title"
+ android:summary="@string/timer_post_end_buffer_summary"
+ android:defaultValue="30"/>
+
+ <EditTextPreference
+ android:key="@string/timer_default_lifetime_key"
+ android:title="@string/timer_default_lifetime_title"
+ android:summary="@string/timer_default_lifetime_summary"
+ android:defaultValue="99"/>
+
+ <EditTextPreference
+ android:key="@string/timer_default_priority_key"
+ android:title="@string/timer_default_priority_title"
+ android:summary="@string/timer_default_priority_summary"
+ android:defaultValue="50"/>
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
diff --git a/androvdr/src/de/bjusystems/androvdr/app/AndroVdrApp.java b/androvdr/src/de/bjusystems/androvdr/app/AndroVdrApp.java
new file mode 100644
index 0000000..8608cef
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/app/AndroVdrApp.java
@@ -0,0 +1,134 @@
+package de.bjusystems.androvdr.app;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.app.Application;
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Epg;
+import de.bjusystems.androvdr.data.EpgSearchParams;
+import de.bjusystems.androvdr.data.Timer;
+
+public class AndroVdrApp extends Application {
+
+ public enum EpgListState {
+ EPG_TIME,
+ EPG_CHANNEL,
+ EPG_SEARCH
+ }
+
+ private EpgListState epgListState;
+ private Epg currentEvent;
+ private Timer currentTimer;
+ private Channel currentChannel;
+ private List<Channel> channels;
+ private EpgSearchParams currentSearch;
+ private Class<? extends Activity> nextActivity;
+ private final List<Activity> activitiesToFinish = new ArrayList<Activity>();
+ private boolean reload;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ }
+
+ public void clear() {
+ this.currentEvent = null;
+ this.currentTimer = null;
+ this.currentChannel = null;
+ this.currentSearch = null;
+
+ this.epgListState = EpgListState.EPG_TIME;
+ }
+
+ public Epg getCurrentEvent() {
+ return currentEvent;
+ }
+
+ public void setCurrentEvent(final Epg currentEvent) {
+ clear();
+ this.currentEvent = currentEvent;
+ if (currentEvent.getTimer() != null) {
+ this.currentTimer = currentEvent.getTimer();
+ } else {
+ this.currentTimer = new Timer(currentEvent);
+ }
+ }
+
+ public Timer getCurrentTimer() {
+ return currentTimer;
+ }
+
+ public void setCurrentTimer(final Timer currentTimer) {
+ clear();
+ this.currentTimer = currentTimer;
+ }
+
+ public Channel getCurrentChannel() {
+ return currentChannel;
+ }
+
+ public void setCurrentChannel(final Channel currentChannel) {
+ clear();
+ this.currentChannel = currentChannel;
+ this.epgListState = EpgListState.EPG_CHANNEL;
+ }
+
+ public List<Channel> getChannels() {
+ return channels;
+ }
+
+ public void setChannels(final List<Channel> channels) {
+ this.channels = channels;
+ }
+
+ public EpgSearchParams getCurrentSearch() {
+ return currentSearch;
+ }
+
+ public void setCurrentSearch(final EpgSearchParams currentSearch) {
+ clear();
+ this.currentSearch = currentSearch;
+ this.epgListState = EpgListState.EPG_SEARCH;
+ }
+
+ public EpgListState getEpgListState() {
+ return epgListState;
+ }
+
+ public Class<? extends Activity> getNextActivity() {
+ return nextActivity;
+ }
+
+ public void setNextActivity(final Class<? extends Activity> nextActivity) {
+ this.nextActivity = nextActivity;
+ }
+
+ public List<Activity> getActivitiesToFinish() {
+ return activitiesToFinish;
+ }
+
+ public void clearActivitiesToFinish() {
+ activitiesToFinish.clear();
+ }
+
+ public void addActivityToFinish(final Activity activityToFinish) {
+ activitiesToFinish.add(activityToFinish);
+ }
+
+ public void finishActivities() {
+ for(final Activity activity : activitiesToFinish) {
+ activity.finish();
+ }
+ activitiesToFinish.clear();
+ }
+
+ public boolean isReload() {
+ return reload;
+ }
+
+ public void setReload(final boolean reload) {
+ this.reload = reload;
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/AliveState.java b/androvdr/src/de/bjusystems/androvdr/data/AliveState.java
new file mode 100644
index 0000000..c558ee7
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/AliveState.java
@@ -0,0 +1,36 @@
+package de.bjusystems.androvdr.data;
+
+public class AliveState {
+
+ public static AliveState ALIVE = new AliveState(0);
+ public static AliveState DEAD = new AliveState(1);
+ public static AliveState UNKNOWN = new AliveState(2);
+
+ private final int value;
+ private static AliveState state;
+
+ private AliveState(final int value) {
+ this.value = value;
+ }
+
+ public static AliveState getState() {
+ return state;
+ }
+
+ public static void setState(final AliveState state) {
+ AliveState.state = state;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (!(o instanceof AliveState)) {
+ return false;
+ }
+ return this.value == ((AliveState)o).value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Integer.valueOf(value).hashCode();
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/Channel.java b/androvdr/src/de/bjusystems/androvdr/data/Channel.java
new file mode 100644
index 0000000..d3753e6
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/Channel.java
@@ -0,0 +1,41 @@
+package de.bjusystems.androvdr.data;
+
+
+public class Channel {
+
+ private final int number;
+ private final String name;
+
+ public Channel(final String channelData) {
+
+ final String[] words = channelData.split(":");
+ this.number = Integer.valueOf(words[0].substring(1));
+ this.name = words[1];
+ }
+
+ public Channel() {
+ this.number = 0;
+ this.name = "Unknown";
+ }
+
+ public boolean isGroupSeparator() {
+ return number == 0;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder text = new StringBuilder();
+ text.append(number);
+ text.append(" - ");
+ text.append(name);
+ return text.toString();
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/Epg.java b/androvdr/src/de/bjusystems/androvdr/data/Epg.java
new file mode 100644
index 0000000..0960ad4
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/Epg.java
@@ -0,0 +1,65 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Date;
+
+/**
+ * Class for EPG events
+ * @author bju
+ */
+public class Epg implements Event {
+
+ private final String channelNumber;
+ private final String channelName;
+ private final String title;
+ private final String description;
+ private final Date start;
+ private final Date stop;
+ private Timer timer;
+
+ public Epg(final String line) {
+
+ final String[] words = line.split(":");
+
+ channelNumber = words[0].substring(1);
+ channelName = words[1];
+ start = new Date(Long.parseLong(words[2])*1000);
+ stop = new Date(Long.parseLong(words[3])*1000);
+ title = words[4];
+ description = words.length > 5 ? words[5] : "";
+ }
+
+ public String getChannelNumber() {
+ return channelNumber;
+ }
+ public String getChannelName() {
+ return channelName;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public String getDescription() {
+ return description;
+ }
+ public Date getStart() {
+ return start;
+ }
+ public Date getStop() {
+ return stop;
+ }
+
+ public Timer getTimer() {
+ return timer;
+ }
+
+ public void setTimer(final Timer timer) {
+ this.timer = timer;
+ }
+
+ public TimerState getTimerState() {
+ if (timer == null) {
+ return TimerState.None;
+ } else {
+ return timer.getTimerState();
+ }
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/EpgSearchParams.java b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchParams.java
new file mode 100644
index 0000000..3efc650
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchParams.java
@@ -0,0 +1,43 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Date;
+
+/**
+ * Class for EPG events
+ * @author bju
+ */
+public class EpgSearchParams {
+
+ private String channelNumber;
+ private String title;
+ private Date start;
+ private Date end;
+
+ public String getChannelNumber() {
+ return channelNumber;
+ }
+ public void setChannelNumber(final String channelNumber) {
+ this.channelNumber = channelNumber;
+ }
+ public String getTitle() {
+ return title;
+ }
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+ public Date getStart() {
+ return start;
+ }
+ public void setStart(final Date start) {
+ this.start = start;
+ }
+ public Date getEnd() {
+ return end;
+ }
+ public void setEnd(final Date end) {
+ this.end = end;
+ }
+ public String toCommandLine() {
+ return title;
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValue.java b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValue.java
new file mode 100644
index 0000000..a58c188
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValue.java
@@ -0,0 +1,49 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+public class EpgSearchTimeValue {
+
+ private final int index;
+ private final String text;
+
+ public EpgSearchTimeValue(final int index, final String text) {
+ this.index = index;
+ this.text = text;
+ }
+
+ public EpgSearchTimeValue() {
+ this.index = 0;
+ this.text = "";
+ }
+
+ public String getValue() {
+ switch (index) {
+ case 0:
+ return "now";
+ case 1:
+ return "next";
+ default:
+ final String[] values = text.split(":");
+ final Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(values[0]));
+ cal.set(Calendar.MINUTE, Integer.parseInt(values[1]));
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ // next day?
+ final Calendar now = new GregorianCalendar();
+ if (now.after(cal)) {
+ cal.add(Calendar.DAY_OF_MONTH, 1);
+ }
+
+ return String.format("%d", cal.getTimeInMillis() / 1000);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValues.java b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValues.java
new file mode 100644
index 0000000..7300e8e
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/EpgSearchTimeValues.java
@@ -0,0 +1,62 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import android.content.Context;
+import de.bjusystems.androvdr.R;
+
+public class EpgSearchTimeValues {
+
+ private final List<EpgSearchTimeValue> values = new ArrayList<EpgSearchTimeValue>();
+ private final Context context;
+
+ public EpgSearchTimeValues(final Context context) {
+
+ this.context = context;
+ }
+
+ public List<EpgSearchTimeValue> getValues() {
+
+ final Preferences prefs = Preferences.getPreferences();
+
+ // fixed values for now and next
+ values.add(new EpgSearchTimeValue(0, context.getString(R.string.epg_list_time_now)));
+ values.add(new EpgSearchTimeValue(1, context.getString(R.string.epg_list_time_next)));
+
+ // get user defined values
+ final String userValueString = prefs.getEpgSearchTimes();
+
+ final String[] userValues = userValueString.split(",");
+
+ Arrays.sort(userValues);
+
+ for(final String userValue : userValues) {
+ if (userValue.contains(":")) {
+ values.add(new EpgSearchTimeValue(values.size(), userValue));
+ }
+ }
+
+ return values;
+ }
+
+ public void saveValues(final List<EpgSearchTimeValue> values) {
+
+ // get old values
+ final Preferences prefs = Preferences.getPreferences();
+
+ // add value
+ String newValues = "";
+ for(int i = 2; i < values.size(); i++) {
+ final EpgSearchTimeValue value = values.get(i);
+ if (newValues.length() > 0) {
+ newValues += ",";
+ }
+ newValues += value.toString();
+ }
+
+ // save new values
+ prefs.setEpgSearchTimes(context, newValues);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/Event.java b/androvdr/src/de/bjusystems/androvdr/data/Event.java
new file mode 100644
index 0000000..1990316
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/Event.java
@@ -0,0 +1,21 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Date;
+
+public interface Event {
+
+ public enum TimerState {
+ None,
+ Active,
+ Inactive,
+ Recording
+ }
+
+ String getChannelNumber();
+ String getChannelName();
+ String getTitle();
+ String getDescription();
+ Date getStart();
+ Date getStop();
+ TimerState getTimerState();
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/EventFormatter.java b/androvdr/src/de/bjusystems/androvdr/data/EventFormatter.java
new file mode 100644
index 0000000..44f8c14
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/EventFormatter.java
@@ -0,0 +1,43 @@
+package de.bjusystems.androvdr.data;
+
+import de.bjusystems.androvdr.utils.date.DateFormatter;
+
+public class EventFormatter {
+
+ private String time;
+ private final String date;
+ private final String longDate;
+ private final String title;
+ private final String description;
+
+ public EventFormatter(final Event event) {
+ DateFormatter formatter = new DateFormatter(event.getStart());
+ this.date = formatter.getDateString();
+ this.longDate = formatter.getDailyHeader();
+ this.time = formatter.getTimeString();
+ formatter = new DateFormatter(event.getStop());
+ this.time += " - " + formatter.getTimeString();
+ this.title = event.getTitle().replace("|##", ":").replace("||#", "\n");
+ this.description = event.getDescription().replace("|##", ":").replace("||#", "\n");
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public String getLongDate() {
+ return longDate;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/EventListItem.java b/androvdr/src/de/bjusystems/androvdr/data/EventListItem.java
new file mode 100644
index 0000000..4e9e1f5
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/EventListItem.java
@@ -0,0 +1,100 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Date;
+
+
+public class EventListItem implements Event {
+
+ private final Timer timer;
+ private final Epg epg;
+ private final String header;
+ private final Event event;
+
+ public EventListItem(final Timer timer) {
+ this.header = null;
+ this.timer = timer;
+ this.epg = null;
+ this.event = timer;
+ }
+
+ public EventListItem(final Epg epg) {
+ this.header = null;
+ this.timer = null;
+ this.epg = epg;
+ this.event = epg;
+ }
+
+ public EventListItem(final String header) {
+ this.header = header;
+ this.timer = null;
+ this.epg = null;
+ this.event = null;
+ }
+
+ public boolean isHeader() {
+ return header != null;
+ }
+
+ public boolean isTimer() {
+ return timer != null;
+ }
+
+ public Date getStart() {
+ return event != null ? event.getStart() : null;
+ }
+
+ public Date getStop() {
+ return event != null ? event.getStop() : null;
+ }
+
+ public String getChannelNumber() {
+ return event != null ? event.getChannelNumber() : null;
+ }
+
+ public String getChannelName() {
+ return event != null ? event.getChannelName() : null;
+ }
+
+ public String getTitle() {
+ return event != null ? event.getTitle() : null;
+ }
+
+ public String getDescription() {
+ return event != null ? event.getDescription() : null;
+ }
+
+ public String getHeader() {
+ return header;
+ }
+
+ public TimerState getTimerState() {
+ return event != null ? event.getTimerState() : TimerState.None;
+ }
+
+ public Timer getTimer() {
+ return timer;
+ }
+
+ public Epg getEpg() {
+ return epg;
+ }
+
+ public Event getEvent() {
+ return event;
+ }
+
+ @Override
+ public String toString() {
+ if (isHeader()) {
+ return "Header: " + header;
+ }
+
+ final EventFormatter formatter = new EventFormatter(event);
+ final StringBuilder text = new StringBuilder();
+ text.append(isTimer() ? "Timer: " : "Event: ");
+ text.append("Channel: ").append(event.getChannelNumber());
+ text.append(" (").append(event.getChannelName()).append("), ");
+ text.append("Zeit: ").append(formatter.getDate()).append(" ").append(formatter.getTime());
+ return text.toString();
+ }
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/data/MenuActionHandler.java b/androvdr/src/de/bjusystems/androvdr/data/MenuActionHandler.java
new file mode 100644
index 0000000..271f3f4
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/MenuActionHandler.java
@@ -0,0 +1,16 @@
+package de.bjusystems.androvdr.data;
+
+import android.content.Context;
+
+
+/**
+ * Handler for menu actions
+ * @author bju
+ */
+public interface MenuActionHandler {
+
+ /**
+ * Execute the action
+ */
+ void executeAction(Context context);
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/Preferences.java b/androvdr/src/de/bjusystems/androvdr/data/Preferences.java
new file mode 100644
index 0000000..2caaf32
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/Preferences.java
@@ -0,0 +1,312 @@
+package de.bjusystems.androvdr.data;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * Class for all preferences
+ * @author bju
+ */
+public class Preferences {
+
+ private boolean ssl;
+ /** SVDRP host name or ip */
+ private String svdrpHost;
+ /** SVDRP port */
+ private int svdrpPort;
+ /** Password */
+ private String password;
+ /** should channels be filtered? */
+ private boolean filterChannels;
+ /** last channel to retrieve */
+ private String channels;
+ /** Enable remote wakeup */
+ private boolean wakeupEnabled;
+ /** Wakeup by HTTP request */
+ private boolean wakeupHttp;
+ /** URL of the wakeup script */
+ private String wakeupUrl;
+ /** User for wakeup */
+ private String wakeupUser;
+ /** Password for wakeup */
+ private String wakeupPassword;
+ /** Check for running VDR is enabled */
+ private boolean aliveCheckEnabled;
+ /** Intervall for alive test */
+ private int aliveCheckInterval;
+ /** Buffer before event */
+ private int timerPreMargin;
+ /** Buffer after event */
+ private int timerPostMargin;
+ /** Default priority */
+ private int timerDefaultPriority;
+ /** Default lifetime */
+ private int timerDefaultLifetime;
+ /** user defined epg search times */
+ private String epgSearchTimes;
+
+ /** Properties singleton */
+ private static Preferences thePrefs;
+
+ /**
+ * Checks for connect using SSL
+ * @return true, if use SSL connections
+ */
+ public boolean isSSL() {
+ return ssl;
+ }
+
+ /**
+ * Retrieves the channel filtering mode
+ * @return true, if channels will be filtered
+ */
+ public boolean isFilterChannels() {
+ return filterChannels;
+ }
+
+ /**
+ * Last channel to receive
+ * @return channel number
+ */
+ public String getChannels() {
+ return filterChannels ? channels : "";
+ }
+
+ /**
+ * Gets the SVDRP host or IP address
+ * @return SVDRP host
+ */
+ public String getSvdrpHost() {
+ return svdrpHost;
+ }
+
+ /**
+ * Gets the SVDRP port
+ * @return SVDRP port
+ */
+ public int getSvdrpPort() {
+ return svdrpPort;
+ }
+
+ /**
+ * Gets the SVDRP password
+ * @return SVDRO password
+ */
+ public String getPassword() {
+ return password;
+ }
+
+ /**
+ * Checks for enables remote wakeup
+ * @return true, if remote wakeup is enabled
+ */
+ public boolean isWakeupEnabled() {
+ return wakeupEnabled;
+ }
+
+ /**
+ * Gets the wakeup method
+ * @return true, wenn wakeup by http request
+ */
+ public boolean isWakeupHttp() {
+ return wakeupHttp;
+ }
+
+ /**
+ * Gets the URL for the wakeup request
+ * @return wakeup url
+ */
+ public String getWakeupUrl() {
+ return wakeupUrl;
+ }
+
+ /**
+ * Gets the user for the wakeup url
+ * @return user name
+ */
+ public String getWakeupUser() {
+ return wakeupUser;
+ }
+
+ /**
+ * Gets the password for the wakeup url
+ * @return password
+ */
+ public String getWakeupPassword() {
+ return wakeupPassword;
+ }
+
+ /**
+ * Checks for enabled alive check
+ * @return true, if enabled
+ */
+ public boolean isAliveCheckEnabled() {
+ return aliveCheckEnabled;
+ }
+
+ /**
+ * Gets the time between alive checks
+ * @return time in seconds
+ */
+ public int getAliveCheckInterval() {
+ return aliveCheckInterval;
+ }
+
+ /**
+ * Gets the buffer before the event start
+ * @return pre event buffer
+ */
+ public int getTimerPreMargin() {
+ return timerPreMargin;
+ }
+
+ /**
+ * Gets the buffer after the event stop
+ * @return post event buffer
+ */
+ public int getTimerPostMargin() {
+ return timerPostMargin;
+ }
+
+ /**
+ * Gets the default priority
+ * @return default priority
+ */
+ public int getTimerDefaultPriority() {
+ return timerDefaultPriority;
+ }
+
+ /**
+ * Gets the default lifetime
+ * @return default lifetime
+ */
+ public int getTimerDefaultLifetime() {
+ return timerDefaultLifetime;
+ }
+
+ /**
+ * Gets the time values for the epg search
+ * @return
+ */
+ public String getEpgSearchTimes() {
+ return epgSearchTimes;
+ }
+
+ /**
+ * Sets the time values for the epg search
+ * @param epgSearchTimes new time values
+ */
+ public void setEpgSearchTimes(final Context context, final String epgSearchTimes) {
+
+ final SharedPreferences prefs = getSharedPreferences(context);
+ final SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(context.getString(R.string.epg_search_times_key), epgSearchTimes);
+ editor.commit();
+
+ // reload
+ loadPreferences(context);
+ }
+
+ /**
+ * Gets the name for the file which preferences will be saved into
+ * @param context Context
+ * @return filename
+ */
+ public static String getPreferenceFile(final Context context) {
+ return context.getString(R.string.app_name);
+ }
+
+ /**
+ * Gets the previous loaded preferences
+ * @return preferences
+ */
+ public static Preferences getPreferences() {
+ return thePrefs;
+ }
+
+ /**
+ * Loads all preferences
+ * @param context Context
+ * @return Preferences
+ */
+ public static void loadPreferences(final Context context) {
+
+ final SharedPreferences sharedPrefs = getSharedPreferences(context);
+
+ final Preferences prefs = new Preferences();
+
+ prefs.svdrpHost = getString(context, sharedPrefs, R.string.vdr_host_key, "10.0.2.2");
+ prefs.svdrpPort = getInt(context, sharedPrefs, R.string.vdr_port_key, 6419);
+ prefs.password = getString(context, sharedPrefs, R.string.vdr_password_key, "");
+ prefs.ssl = getBoolean(context, sharedPrefs, R.string.vdr_ssl_key, false);
+
+ prefs.aliveCheckEnabled = getBoolean(context, sharedPrefs, R.string.alive_check_enabled_key, false);
+ prefs.aliveCheckInterval = getInt(context, sharedPrefs, R.string.alive_check_interval_key, 60);
+
+ prefs.channels = getString(context, sharedPrefs, R.string.channel_filter_last_key, "").replace(" ", "");
+ prefs.filterChannels = getBoolean(context, sharedPrefs, R.string.channel_filter_filter_key, false);
+
+ prefs.wakeupEnabled = getBoolean(context, sharedPrefs, R.string.wakeup_enabled_key, false);
+ prefs.wakeupHttp = getBoolean(context, sharedPrefs, R.string.wakeup_svdrphelper_key, false);
+ prefs.wakeupUrl = getString(context, sharedPrefs, R.string.wakeup_url_key, "");
+ prefs.wakeupUser = getString(context, sharedPrefs, R.string.wakeup_user_key, "");
+ prefs.wakeupPassword = getString(context, sharedPrefs, R.string.wakeup_password_key, "");
+
+ prefs.timerPreMargin = getInt(context, sharedPrefs, R.string.timer_pre_start_buffer_key, 5);
+ prefs.timerPostMargin = getInt(context, sharedPrefs, R.string.timer_post_end_buffer_key, 30);
+ prefs.timerDefaultPriority = getInt(context, sharedPrefs, R.string.timer_default_priority_key, 99);
+ prefs.timerDefaultLifetime = getInt(context, sharedPrefs, R.string.timer_default_lifetime_key, 99);
+
+ prefs.epgSearchTimes = getString(context, sharedPrefs, R.string.epg_search_times_key, "");
+
+ thePrefs = prefs;
+ }
+
+ /**
+ * Gets the persistent preferences
+ * @param context Context
+ * @return preferences
+ */
+ private static SharedPreferences getSharedPreferences(final Context context) {
+
+ return context.getSharedPreferences(getPreferenceFile(context), Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Helper for retrieving integer values from preferences
+ * @param context Context
+ * @param sharedPrefs Object for the preference file
+ * @param resId ressource id of the preferences name
+ * @param defValue default value
+ * @return value or the default value if not defined
+ */
+ private static int getInt(final Context context, final SharedPreferences sharedPrefs, final int resId, final int defValue) {
+ final String value = getString(context, sharedPrefs, resId, String.valueOf(defValue));
+ return Integer.parseInt(value);
+ }
+
+ /**
+ * Helper for retrieving boolean values from preferences
+ * @param context Context
+ * @param sharedPrefs Object for the preference file
+ * @param resId ressource id of the preferences name
+ * @param defValue default value
+ * @return value or the default value if not defined
+ */
+ private static boolean getBoolean(final Context context, final SharedPreferences sharedPrefs, final int resId, final boolean defValue) {
+ return sharedPrefs.getBoolean(context.getString(resId), defValue);
+ }
+
+ /**
+ * Helper for retrieving string values from preferences
+ * @param context Context
+ * @param sharedPrefs Object for the preference file
+ * @param resId ressource id of the preferences name
+ * @param defValue default value
+ * @return value or the default value if not defined
+ */
+ private static String getString(final Context context, final SharedPreferences sharedPrefs, final int resId, final String defValue) {
+ return sharedPrefs.getString(context.getString(resId), defValue);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/Timer.java b/androvdr/src/de/bjusystems/androvdr/data/Timer.java
new file mode 100644
index 0000000..975ae7e
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/Timer.java
@@ -0,0 +1,186 @@
+package de.bjusystems.androvdr.data;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+/**
+ * Class for timer data
+ * @author bju
+ */
+public class Timer implements Event {
+
+ private static final int ENABLED = 1;
+ private static final int INSTANT = 2;
+ private static final int VPS = 4;
+ private static final int RECORDING = 8;
+
+ private final int number;
+ private int flags;
+ private String title;
+ private String description;
+ private Date start;
+ private Date stop;
+ private final String channelNumber;
+ private final String channelName;
+ private final int priority;
+ private final int lifetime;
+
+
+ /**
+ * Constructs a timer from SvdrpHelper result line
+ * @param timerData result line
+ * @param channels list of channels
+ */
+ public Timer(final String timerData) {
+
+ final String[] values = timerData.split(":");
+
+ // number
+ this.number = Integer.valueOf(values[0].substring(1));
+
+ // flags, channel number and channel name
+ this.flags = Integer.valueOf(values[1]);
+ this.channelNumber = values[2];
+ this.channelName = values[3];
+
+ // get start and stop
+ this.start = new Date(Long.parseLong(values[4]) * 1000);
+ this.stop = new Date(Long.parseLong(values[5]) * 1000);
+
+ // priority and lifetime
+ this.priority = Integer.valueOf(values[6]);
+ this.lifetime = Integer.valueOf(values[7]);
+
+ // title and description
+ this.title = values[8];
+ this.description = values.length > 9 ? values[9] : "";
+ }
+
+ public Timer(final Epg event) {
+
+ final Preferences prefs = Preferences.getPreferences();
+
+ this.number = 0;
+ this.flags = ENABLED;
+ this.channelNumber = event.getChannelNumber();
+ this.channelName = event.getChannelName();
+ this.priority = prefs.getTimerDefaultPriority();
+ this.lifetime = prefs.getTimerDefaultLifetime();
+
+ this.start = new Date(event.getStart().getTime() - prefs.getTimerPreMargin() * 60000);
+ this.stop = new Date(event.getStop().getTime() + prefs.getTimerPostMargin() * 60000);
+
+ this.title = event.getTitle();
+ this.description = event.getDescription();
+ }
+
+ public String toCommandLine() {
+
+ final StringBuilder line = new StringBuilder();
+
+ line.append(number).append(":");
+ line.append(flags).append(":");
+ line.append(channelNumber).append(":");
+
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(start);
+ line.append(String.format("%04d-%02d-%02d:", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)));
+ line.append(String.format("%02d%02d:", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)));
+
+ cal.setTime(stop);
+ line.append(String.format("%02d%02d:", cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)));
+
+ line.append(priority).append(":");
+ line.append(lifetime).append(":");
+ line.append(title).append(":");
+ line.append(description);
+
+ return line.toString();
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public int getNumber() {
+ return number;
+ }
+
+ public Date getStart() {
+ return start;
+ }
+
+ public Date getStop() {
+ return stop;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(final String title) {
+ this.title = title;
+ }
+
+ public String getChannelNumber() {
+ return channelNumber;
+ }
+
+ public String getChannelName() {
+ return channelName;
+ }
+
+ public int getPriority() {
+ return priority;
+ }
+
+ public int getLifetime() {
+ return lifetime;
+ }
+
+ public TimerState getTimerState() {
+ if (isEnabled()) {
+ if (isRecording()) {
+ return TimerState.Recording;
+ }
+ return TimerState.Active;
+ }
+ return TimerState.Inactive;
+ }
+
+ public boolean isEnabled() {
+ return (flags & ENABLED) == ENABLED;
+ }
+
+ public boolean isInstant() {
+ return (flags & INSTANT) == INSTANT;
+ }
+
+ public boolean isVps() {
+ return (flags & VPS) == VPS;
+ }
+ public boolean isRecording() {
+ return (flags & RECORDING) == RECORDING;
+ }
+
+ public void setStart(final Date start) {
+ this.start = start;
+ }
+
+ public void setStop(final Date stop) {
+ this.stop = stop;
+ }
+
+ public void setEnabled(final boolean enabled) {
+ if (enabled) {
+ flags = flags | ENABLED;
+ } else {
+ flags = flags & ~ENABLED;
+ }
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/data/WakeupState.java b/androvdr/src/de/bjusystems/androvdr/data/WakeupState.java
new file mode 100644
index 0000000..b68627b
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/data/WakeupState.java
@@ -0,0 +1,36 @@
+package de.bjusystems.androvdr.data;
+
+public class WakeupState {
+
+ public static WakeupState OK = new WakeupState(0);
+ public static WakeupState FAILED = new WakeupState(1);
+ public static WakeupState ERROR = new WakeupState(2);
+
+ private final int value;
+ private static WakeupState state;
+
+ private WakeupState(final int value) {
+ this.value = value;
+ }
+
+ public static WakeupState getState() {
+ return state;
+ }
+
+ public static void setState(final WakeupState state) {
+ WakeupState.state = state;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (!(o instanceof WakeupState)) {
+ return false;
+ }
+ return this.value == ((WakeupState)o).value;
+ }
+
+ @Override
+ public int hashCode() {
+ return Integer.valueOf(value).hashCode();
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/AndroVdrActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/AndroVdrActivity.java
new file mode 100644
index 0000000..f122c20
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/AndroVdrActivity.java
@@ -0,0 +1,228 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.ImageButton;
+import android.widget.TextView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.MenuActionHandler;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.utils.wakeup.AsyncWakeupTask;
+import de.bjusystems.androvdr.R;
+
+public class AndroVdrActivity extends Activity {
+
+ static class WakeupAction implements MenuActionHandler {
+ public void executeAction(final Context context) {
+ // create AsyncTask
+ final AsyncWakeupTask wakeupTask = new AsyncWakeupTask(context);
+ wakeupTask.execute();
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ static class MenuActivity {
+ int iconId;
+ int textId;
+ Class handler;
+ boolean enabled;
+
+ public int getIconId() {
+ return iconId;
+ }
+ public int getTextId() {
+ return textId;
+ }
+
+ public Class getHandler() {
+ return handler;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public MenuActivity(final int iconId, final int textId, final Class handler) {
+ this.iconId = iconId;
+ this.textId = textId;
+ this.handler = handler;
+ this.enabled = true;
+ }
+
+ public void setEnabled(final boolean enabled) {
+ this.enabled = enabled;
+ }
+ }
+
+ class MenuAdapter extends ArrayAdapter<MenuActivity> implements OnClickListener {
+
+ private final LayoutInflater inflater;
+
+ public MenuAdapter(final Context context, final int viewId) {
+ super(context, viewId);
+ inflater = LayoutInflater.from(context);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+
+ View view = convertView;
+ View itemView;
+ if (view == null) {
+ view = inflater.inflate(R.layout.vdrmanager_menu_item, null);
+ itemView = view.findViewById(R.id.vdrmanager_menu_item);
+ view.setTag(itemView);
+
+ // attach click listener
+ itemView.setOnClickListener(this);
+
+ } else {
+ itemView = (View) view.getTag();
+ }
+
+ // attach menu item
+ final MenuActivity menuItem = getItem(position);
+ if (itemView instanceof TextView) {
+ final TextView textView = (TextView) itemView;
+ textView.setText(menuItem.getTextId());
+ } else {
+ final ImageButton imageButton = (ImageButton) itemView;
+ imageButton.setImageResource(menuItem.getIconId());
+ }
+ itemView.setOnClickListener(this);
+ menuActivityMap.put(itemView, menuItem.getHandler());
+
+ return view;
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void onClick(final View v) {
+
+ // refresh preferences
+ Preferences.loadPreferences(getContext());
+
+ // clear state
+ ((AndroVdrApp) getApplication()).clear();
+
+ // start activity
+ final Class actionClass = menuActivityMap.get(v);
+ if (Activity.class.isAssignableFrom(actionClass)) {
+ final Intent intent = new Intent();
+ intent.setClass(getContext(), actionClass);
+ startActivity(intent);
+ } else if (MenuActionHandler.class.isAssignableFrom(actionClass)) {
+ final Class<? extends MenuActionHandler> handlerClass = actionClass;
+ try {
+ final MenuActionHandler handler = handlerClass.newInstance();
+ handler.executeAction(getContext());
+ } catch (final InstantiationException e) {
+
+ } catch (final IllegalAccessException e) {
+
+ }
+ }
+ }
+ }
+
+ MenuActivity[] menuItems = new MenuActivity[] {
+ new MenuActivity(R.drawable.whatson, R.string.action_menu_epg, EpgListActivity.class),
+ new MenuActivity(0, R.string.action_menu_search, EpgSearchActivity.class),
+ new MenuActivity(R.drawable.timers, R.string.action_menu_timers, TimerListActivity.class),
+ new MenuActivity(R.drawable.channels, R.string.action_menu_channels, ChannelListActivity.class),
+ new MenuActivity(0, R.string.action_menu_wakeup, WakeupAction.class),
+ };
+ Map<View, Class<? extends Activity>> menuActivityMap = new HashMap<View, Class<? extends Activity>>();
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // attach view
+ setContentView(R.layout.vdrmanager);
+
+ // add and register buttons
+ createButtons();
+ }
+
+ // add main menu buttons
+ private void createButtons() {
+
+ // refresh preferences
+ Preferences.loadPreferences(this);
+ final Preferences prefs = Preferences.getPreferences();
+
+ // get list
+ final AbsListView listView = (AbsListView) findViewById(R.id.vdrmanager_menu);
+ final MenuAdapter adapter = new MenuAdapter(this, R.layout.vdrmanager_menu_item);
+ listView.setAdapter(adapter);
+
+ // add menu items
+ for(final MenuActivity menuItem : menuItems) {
+ if (menuItem.getTextId() != R.string.action_menu_wakeup || prefs.isWakeupEnabled()) {
+ adapter.add(menuItem);
+ }
+ }
+
+ // set grid layout dimensions
+ if (listView instanceof GridView) {
+ final GridView grid = (GridView)listView;
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ grid.setNumColumns(2);
+ } else {
+ grid.setNumColumns(menuItems.length);
+ }
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+
+ switch (item.getItemId())
+ {
+ case R.id.main_menu_preferences:
+ // remember activity for finishing
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.clearActivitiesToFinish();
+ app.addActivityToFinish(this);
+
+ final Intent intent = new Intent();
+ intent.setClass(this, PreferencesActivity.class);
+ startActivity(intent);
+ break;
+ case R.id.main_menu_exit:
+ finish();
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public void onBackPressed() {
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/ChannelAdapter.java b/androvdr/src/de/bjusystems/androvdr/gui/ChannelAdapter.java
new file mode 100644
index 0000000..ea31f69
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/ChannelAdapter.java
@@ -0,0 +1,75 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.R;
+
+class ChannelAdapter extends ArrayAdapter<Channel> {
+
+ private final LayoutInflater inflater;
+ private final List<Channel> items;
+
+ public ChannelAdapter(final Context context) {
+ super(context, R.layout.channel_item);
+ inflater = LayoutInflater.from(context);
+ items = new ArrayList<Channel>();
+ }
+
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+
+ ChannelHolder itemHolder = new ChannelHolder();
+
+ // recycle view?
+ View view = convertView;
+ if (view == null) {
+ view = inflater.inflate(R.layout.channel_item, null);
+ itemHolder = new ChannelHolder();
+
+ itemHolder.name = (TextView) view.findViewById(R.id.channel_name);
+ itemHolder.type = (ImageView) view.findViewById(R.id.channel_type);
+
+ view.setTag(itemHolder);
+ } else {
+ itemHolder = (ChannelHolder) view.getTag();
+ }
+
+ // get item
+ final Channel item = getItem(position);
+
+ // fill item
+ if (item.isGroupSeparator()) {
+ view.setPadding(view.getPaddingLeft(), 0, view.getPaddingRight(), 0);
+ view.setBackgroundColor(Color.DKGRAY);
+ itemHolder.type.setVisibility(View.GONE);
+ itemHolder.name.setVisibility(View.VISIBLE);
+ itemHolder.name.setText(item.getName());
+ itemHolder.name.setPadding(0, 0, 0, 0);
+ } else {
+ view.setBackgroundColor(Color.BLACK);
+ itemHolder.type.setVisibility(View.VISIBLE);
+ itemHolder.type.setVisibility(View.VISIBLE);
+ itemHolder.name.setText(item.toString());
+ }
+
+ return view;
+ }
+
+ public void addItem(final Channel channel) {
+ items.add(channel);
+ }
+
+ public void clearItems() {
+ items.clear();
+ }
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/ChannelHolder.java b/androvdr/src/de/bjusystems/androvdr/gui/ChannelHolder.java
new file mode 100644
index 0000000..f0cbbb7
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/ChannelHolder.java
@@ -0,0 +1,9 @@
+package de.bjusystems.androvdr.gui;
+
+import android.widget.ImageView;
+import android.widget.TextView;
+
+class ChannelHolder {
+ public ImageView type;
+ public TextView name;
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/ChannelListActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/ChannelListActivity.java
new file mode 100644
index 0000000..16de0bb
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/ChannelListActivity.java
@@ -0,0 +1,187 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.utils.svdrp.ChannelClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncListener;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpException;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class ChannelListActivity extends Activity
+ implements OnItemClickListener, SvdrpAsyncListener<Channel> {
+
+ ChannelClient channelClient;
+ ChannelAdapter adapter;
+ Preferences prefs;
+ List<Channel> channels;
+ SvdrpProgressDialog progress;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.channel_list);
+
+ // Create adapter for ListView
+ adapter = new ChannelAdapter(this);
+ final ListView listView = (ListView) findViewById(R.id.channel_list);
+ listView.setAdapter(adapter);
+ // register context menu
+ registerForContextMenu(listView);
+
+
+ // create channel list
+ channels = new ArrayList<Channel>();
+
+ listView.setOnItemClickListener(this);
+ }
+
+ public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
+
+ // find and remember item
+ final Channel channel = (Channel) parent.getAdapter().getItem(position);
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setCurrentChannel(channel);
+ app.setChannels(channels);
+
+ // show details
+ final Intent intent = new Intent();
+ intent.setClass(this, EpgListActivity.class);
+ startActivity(intent);
+ }
+
+
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ startChannelQuery();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (channelClient != null) {
+ channelClient.abort();
+ }
+ if (progress != null) {
+ progress.dismiss();
+ progress = null;
+ }
+ }
+
+ private void startChannelQuery() {
+
+ // get channel task
+ channelClient = new ChannelClient();
+
+ // create background task
+ final SvdrpAsyncTask<Channel, SvdrpClient<Channel>> task = new SvdrpAsyncTask<Channel, SvdrpClient<Channel>>(channelClient);
+
+ // create progress
+ progress = new SvdrpProgressDialog(this, channelClient);
+
+ // attach listener
+ task.addListener(this);
+
+ // start task
+ task.run();
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Channel result) {
+
+ if (progress != null) {
+ progress.svdrpEvent(event);
+ }
+
+ switch (event) {
+ case CONNECTING:
+ adapter.clear();
+ channels.clear();
+ break;
+ case LOGIN_ERROR:
+ this.finish();
+ break;
+ case FINISHED:
+ channels.addAll(channelClient.getResults());
+ for(final Channel channel : channels) {
+ adapter.add(channel);
+ }
+ progress = null;
+ }
+ }
+
+ public void svdrpException(final SvdrpException exception) {
+ if (progress != null) {
+ progress.svdrpException(exception);
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ if (v.getId() == R.id.channel_list) {
+ final MenuInflater inflater = getMenuInflater();
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+
+ // set menu title
+ final Channel item = adapter.getItem(info.position);
+ menu.setHeaderTitle(item.getName());
+
+ inflater.inflate(R.menu.channel_list_item_menu, menu);
+ }
+ }
+
+
+
+ @Override
+ public boolean onContextItemSelected(final MenuItem item) {
+
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+ final Channel channel = adapter.getItem(info.position);
+
+ switch (item.getItemId()) {
+ case R.id.channel_item_menu_epg:
+ onItemClick(null, null, info.position, 0);
+ break;
+ case R.id.channel_item_menu_stream:
+ // show live stream
+ showStream(channel);
+ break;
+ }
+
+ return true;
+ }
+
+ private void showStream(final Channel channel) {
+ // show stream
+ final Intent intent = new Intent();
+ intent.setClass(this, VideoActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EpgDetailsActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/EpgDetailsActivity.java
new file mode 100644
index 0000000..d00d993
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EpgDetailsActivity.java
@@ -0,0 +1,91 @@
+package de.bjusystems.androvdr.gui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.Epg;
+import de.bjusystems.androvdr.data.EventFormatter;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class EpgDetailsActivity extends Activity
+ implements OnClickListener {
+
+ Preferences prefs;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.epg_detail);
+
+
+ // current event
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ final Epg event = app.getCurrentEvent();
+ final EventFormatter formatter = new EventFormatter(event);
+
+ final TextView title = (TextView)findViewById(R.id.epg_detail_title);
+ title.setText(formatter.getTitle());
+ title.setTextSize(TypedValue.COMPLEX_UNIT_PX, title.getTextSize()*(float)1.3);
+
+ ((TextView) findViewById(R.id.epg_detail_time)).setText(formatter.getTime());
+ ((TextView)findViewById(R.id.epg_detail_channel)).setText(event.getChannelName());
+ ((TextView)findViewById(R.id.epg_detail_date)).setText(formatter.getLongDate());
+ final TextView textView = (TextView)findViewById(R.id.epg_detail_description);
+ textView.setText(formatter.getDescription());
+
+ // copy color for separator lines
+ final int color = textView.getTextColors().getDefaultColor();
+ ((TextView)findViewById(R.id.epg_detail_separator_1)).setBackgroundColor(color);
+ ((TextView)findViewById(R.id.epg_detail_separator_2)).setBackgroundColor(color);
+
+ // register button handler
+ final Button timeButton = (Button) findViewById(R.id.epg_event_create_timer);
+ timeButton.setOnClickListener(this);
+
+ // set button text
+ if (event.getTimer() == null) {
+ timeButton.setText(R.string.epg_event_create_timer_text);
+ } else {
+ timeButton.setText(R.string.epg_event_modify_timer_text);
+ }
+
+ // clear list of activities to finish
+ app.clearActivitiesToFinish();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ public void onClick(final View v) {
+
+ // after timer creation/modification return to the epg list
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.addActivityToFinish(this);
+
+ // show timer details
+ final Intent intent = new Intent();
+ intent.setClass(this, TimerDetailsActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EpgListActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/EpgListActivity.java
new file mode 100644
index 0000000..fd0968c
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EpgListActivity.java
@@ -0,0 +1,408 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.List;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemSelectedListener;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.Spinner;
+import android.widget.TextView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Epg;
+import de.bjusystems.androvdr.data.EpgSearchParams;
+import de.bjusystems.androvdr.data.EpgSearchTimeValue;
+import de.bjusystems.androvdr.data.EpgSearchTimeValues;
+import de.bjusystems.androvdr.data.EventFormatter;
+import de.bjusystems.androvdr.data.EventListItem;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.tasks.DeleteTimerTask;
+import de.bjusystems.androvdr.tasks.ToggleTimerTask;
+import de.bjusystems.androvdr.utils.svdrp.EpgClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncListener;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpException;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class EpgListActivity extends Activity
+ implements OnItemClickListener, OnItemSelectedListener, SvdrpAsyncListener<Epg> {
+
+ EpgClient epgClient;
+ EventAdapter adapter;
+ Preferences prefs;
+ Spinner timeSpinner;
+ Spinner channelSpinner;
+ ArrayAdapter<EpgSearchTimeValue> timeSpinnerAdapter;
+ ListView listView;
+ SvdrpProgressDialog progress;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // application object
+ final AndroVdrApp app = (AndroVdrApp)getApplication();
+ // get state
+ final Channel channel = ((AndroVdrApp) getApplication()).getCurrentChannel();
+ final List<Channel> channels = ((AndroVdrApp) getApplication()).getChannels();
+
+ // Attach view
+ setContentView(R.layout.epg_list);
+
+ // create adapter for time spinner
+ timeSpinnerAdapter = new ArrayAdapter<EpgSearchTimeValue>(this, android.R.layout.simple_spinner_item);
+ timeSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ timeSpinner = (Spinner) findViewById(R.id.epg_list_time_spinner);
+ timeSpinner.setAdapter(timeSpinnerAdapter);
+
+ // create adapter for channel spinner
+ final ArrayAdapter<Channel> channelSpinnerAdapter = new ArrayAdapter<Channel>(this, android.R.layout.simple_spinner_item);
+ channelSpinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ channelSpinner = (Spinner) findViewById(R.id.epg_list_channel_spinner);
+ channelSpinner.setAdapter(channelSpinnerAdapter);
+
+ // get search label
+ final TextView searchLabel = (TextView) findViewById(R.id.epg_list_search_label);
+
+ // fill spinners
+ if (channels != null) {
+ // add dummy timer
+ timeSpinnerAdapter.add(new EpgSearchTimeValue());
+ // add channel values
+ for(final Channel c : channels) {
+ channelSpinnerAdapter.add(c);
+ }
+ } else {
+ // add dummy channel
+ channelSpinnerAdapter.add(new Channel());
+ // add time values
+ fillTimeSpinnerValues();
+ }
+
+ // show needed items
+ final LinearLayout timeLayout = (LinearLayout) findViewById(R.id.whatson_time);
+
+ // update gui
+ switch (app.getEpgListState()) {
+ case EPG_TIME:
+ adapter = new EventAdapter(this, false);
+ timeLayout.setVisibility(View.VISIBLE);
+ channelSpinner.setVisibility(View.GONE);
+ searchLabel.setVisibility(View.GONE);
+ timeSpinner.setOnItemSelectedListener(this);
+ timeSpinner.setSelection(0);
+ break;
+ case EPG_CHANNEL:
+ adapter = new EventAdapter(this, true);
+ timeLayout.setVisibility(View.GONE);
+ channelSpinner.setVisibility(View.VISIBLE);
+ searchLabel.setVisibility(View.GONE);
+ channelSpinner.setOnItemSelectedListener(this);
+ channelSpinner.setSelection(channel.getNumber() - 1);
+ break;
+ case EPG_SEARCH:
+ adapter = new EventAdapter(this, true);
+ timeLayout.setVisibility(View.GONE);
+ channelSpinner.setVisibility(View.GONE);
+ searchLabel.setVisibility(View.VISIBLE);
+ startSearchEpgQuery(app.getCurrentSearch());
+ break;
+ }
+
+ // Create adapter for EPG list
+ listView = (ListView) findViewById(R.id.whatson_list);
+ listView.setAdapter(adapter);
+ registerForContextMenu(listView);
+
+ // register EPG item click
+ listView.setOnItemClickListener(this);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ fillTimeSpinnerValues();
+
+ reloadIfNeeded();
+ }
+
+ private void reloadIfNeeded() {
+
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ if (app.isReload()) {
+ app.setReload(false);
+ startEpgQuery(epgClient);
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (epgClient != null) {
+ epgClient.abort();
+ }
+ if (progress != null) {
+ progress.dismiss();
+ progress = null;
+ }
+ }
+
+ public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
+
+ // find and remember item
+ final EventListItem item = adapter.getItem(position);
+
+ // prepare timer if we want to program
+ prepareTimer(item);
+
+ // show details
+ final Intent intent = new Intent();
+ intent.setClass(this, EpgDetailsActivity.class);
+ startActivity(intent);
+ }
+
+ public void onItemSelected(final AdapterView<?> parent, final View view, final int position, final long id) {
+
+ if (parent == timeSpinner) {
+ // get spinner value
+ final EpgSearchTimeValue selection = (EpgSearchTimeValue) timeSpinner.getSelectedItem();
+ // update search
+ startTimeEpgQuery(selection.getValue());
+ } else {
+ // get spinner value
+ final Channel channel = (Channel) channelSpinner.getSelectedItem();
+ // update search
+ startChannelEpgQuery(channel);
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(final Menu menu) {
+ super.onCreateOptionsMenu(menu);
+
+ final MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.epg_list_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+
+ Intent intent;
+
+ switch (item.getItemId())
+ {
+ case R.id.epg_menu_search:
+ intent = new Intent();
+ intent.setClass(this, EpgSearchActivity.class);
+ startActivity(intent);
+ break;
+ case R.id.epg_menu_times:
+ intent = new Intent();
+ intent.setClass(this, EpgSearchTimesListActivity.class);
+ startActivity(intent);
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ if (v.getId() == R.id.whatson_list) {
+ final MenuInflater inflater = getMenuInflater();
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+
+ // set menu title
+ final EventListItem item = adapter.getItem(info.position);
+ final EventFormatter formatter = new EventFormatter(item);
+ menu.setHeaderTitle(formatter.getTitle());
+
+ inflater.inflate(R.menu.epg_list_item_menu, menu);
+
+ // remove unneeded menu items
+ if (item.getEpg().getTimer() != null) {
+ menu.findItem(R.id.epg_item_menu_timer_add).setVisible(false);
+ final MenuItem enableMenuItem = menu.findItem(R.id.epg_item_menu_timer_toggle);
+ enableMenuItem.setTitle(item.getEpg().getTimer().isEnabled() ? R.string.epg_item_menu_timer_disable : R.string.epg_item_menu_timer_enable);
+ } else {
+ menu.findItem(R.id.epg_item_menu_timer_modify).setVisible(false);
+ menu.findItem(R.id.epg_item_menu_timer_delete).setVisible(false);
+ }
+ }
+ }
+
+
+
+ @Override
+ public boolean onContextItemSelected(final MenuItem item) {
+
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+ final EventListItem event = adapter.getItem(info.position);
+
+ switch (item.getItemId()) {
+ case R.id.epg_item_menu_timer_add:
+ case R.id.epg_item_menu_timer_modify:
+ {
+ prepareTimer(event);
+
+ final Intent intent = new Intent();
+ intent.setClass(this, TimerDetailsActivity.class);
+ startActivity(intent);
+ break;
+ }
+ case R.id.epg_item_menu_timer_delete:
+ {
+ deleteTimer(event);
+ break;
+ }
+ case R.id.epg_item_menu_timer_toggle:
+ {
+ toggleTimer(event);
+ }
+ }
+
+ return true;
+ }
+
+ public void onNothingSelected(final AdapterView<?> arg0) {
+ //startTimeEpgQuery(((EpgTimeSpinnerValue)timeSpinner.getAdapter().getItem(0)).getValue());
+ }
+
+ private void startSearchEpgQuery(final EpgSearchParams search) {
+
+ epgClient = new EpgClient(search);
+ startEpgQuery(epgClient);
+ }
+
+ private void startTimeEpgQuery(final String time) {
+
+ epgClient = new EpgClient(time);
+ startEpgQuery(epgClient);
+ }
+
+ private void startChannelEpgQuery(final Channel channel) {
+
+ epgClient = new EpgClient(channel);
+ startEpgQuery(epgClient);
+ }
+
+ private void startEpgQuery(final EpgClient epgClient) {
+
+ // remove old listeners
+ epgClient.clearSvdrpListener();
+
+ // create background task
+ final SvdrpAsyncTask<Epg, SvdrpClient<Epg>> task = new SvdrpAsyncTask<Epg, SvdrpClient<Epg>>(epgClient);
+
+ // create progress
+ progress = new SvdrpProgressDialog(this, epgClient);
+
+ // attach listener
+ task.addListener(this);
+
+ // start task
+ task.run();
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Epg result) {
+
+ if (progress != null) {
+ progress.svdrpEvent(event);
+ }
+
+ switch (event) {
+ case CONNECTING:
+ adapter.clearItems();
+ break;
+ case LOGIN_ERROR:
+ this.finish();
+ break;
+ case FINISHED:
+ epgClient.clearSvdrpListener();
+ for(final Epg epg : epgClient.getResults()) {
+ adapter.addItem(new EventListItem(epg));
+ }
+ adapter.sortItems();
+ listView.setSelectionAfterHeaderView();
+ progress = null;
+ break;
+ }
+ }
+
+ public void svdrpException(final SvdrpException exception) {
+ if (progress != null) {
+ progress.svdrpException(exception);
+ }
+ }
+
+ private void prepareTimer(final EventListItem item) {
+
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+
+ // remember event for details view and timer things
+ app.setCurrentEvent(item.getEpg());
+
+ // if we create or modify the attached timer we will return to a new epg list
+ app.clearActivitiesToFinish();
+ app.addActivityToFinish(this);
+ app.setNextActivity(EpgListActivity.class);
+ }
+
+ private void deleteTimer(final EventListItem item) {
+
+ final DeleteTimerTask task = new DeleteTimerTask(this, item.getEpg().getTimer()) {
+ @Override
+ public void finished() {
+ // refresh epg list after return
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setReload(true);
+ reloadIfNeeded();
+ }
+ };
+ task.start();
+ }
+
+ private void toggleTimer(final EventListItem item) {
+
+ final ToggleTimerTask task = new ToggleTimerTask(this, item.getEpg().getTimer()) {
+ @Override
+ public void finished() {
+ // refresh epg list after return
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setReload(true);
+ reloadIfNeeded();
+ }
+ };
+ task.start();
+ }
+
+ private void fillTimeSpinnerValues() {
+ final EpgSearchTimeValues values = new EpgSearchTimeValues(this);
+ timeSpinnerAdapter.clear();
+ for(final EpgSearchTimeValue value : values.getValues()) {
+ timeSpinnerAdapter.add(value);
+ }
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchActivity.java
new file mode 100644
index 0000000..f19863d
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchActivity.java
@@ -0,0 +1,63 @@
+package de.bjusystems.androvdr.gui;
+
+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.TextView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.EpgSearchParams;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class EpgSearchActivity extends Activity
+ implements OnClickListener {
+
+ Preferences prefs;
+ TextView text;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.epg_search);
+
+ // save fields
+ text = (TextView) findViewById(R.id.epg_search_text);
+
+ // register button
+ final Button button = (Button) findViewById(R.id.epg_search_button);
+ button.setOnClickListener(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ public void onClick(final View v) {
+
+ // Save search parameters
+ final EpgSearchParams search = new EpgSearchParams();
+ search.setTitle(text.getText().toString());
+ ((AndroVdrApp)getApplication()).setCurrentSearch(search);
+
+ // show timer details
+ final Intent intent = new Intent();
+ intent.setClass(this, EpgListActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchTimesListActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchTimesListActivity.java
new file mode 100644
index 0000000..7e8ab1f
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EpgSearchTimesListActivity.java
@@ -0,0 +1,130 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.List;
+
+import android.app.Activity;
+import android.app.TimePickerDialog;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.widget.TimePicker;
+import de.bjusystems.androvdr.data.EpgSearchTimeValue;
+import de.bjusystems.androvdr.data.EpgSearchTimeValues;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class EpgSearchTimesListActivity extends Activity
+ implements OnClickListener, OnTimeSetListener {
+
+ ArrayAdapter<EpgSearchTimeValue> adapter;
+ List<EpgSearchTimeValue> values;
+ Preferences prefs;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.epg_search_times_list);
+
+ // Create adapter for ListView
+ adapter = new ArrayAdapter<EpgSearchTimeValue>(this, R.layout.epg_search_times_item);
+ final ListView listView = (ListView) findViewById(R.id.epg_search_times_list);
+ listView.setAdapter(adapter);
+ registerForContextMenu(listView);
+
+ // create channel list
+ updateList();
+
+ // button handler
+ final Button addButton = (Button) findViewById(R.id.epg_search_times_add);
+ addButton.setOnClickListener(this);
+ }
+
+ public void onClick(final View v) {
+
+ // show time selection
+ final TimePickerDialog dialog = new TimePickerDialog(this, this, 0, 0, true);
+ dialog.show();
+ }
+
+ public void onTimeSet(final TimePicker view, final int hourOfDay, final int minute) {
+
+ final EpgSearchTimeValue time = new EpgSearchTimeValue(values.size(), String.format("%02d:%02d", hourOfDay, minute));
+ values.add(time);
+ adapter.add(time);
+
+ save();
+
+ updateList();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ if (v.getId() == R.id.epg_search_times_list) {
+ final MenuInflater inflater = getMenuInflater();
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+ menu.setHeaderTitle(values.get(info.position+2).toString());
+
+ inflater.inflate(R.menu.epg_search_time_item_menu, menu);
+ }
+ }
+
+
+
+ @Override
+ public boolean onContextItemSelected(final MenuItem item) {
+
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+ final EpgSearchTimeValue time = values.get(info.position+2);
+
+ if (item.getItemId() == R.id.epg_search_time_delete) {
+ values.remove(time);
+ adapter.remove(time);
+
+ save();
+ }
+
+ return true;
+ }
+
+ private void updateList() {
+
+ // get values
+ values = new EpgSearchTimeValues(this).getValues();
+ adapter.clear();
+ for(int i = 2; i < values.size(); i++) {
+ adapter.add(values.get(i));
+ }
+ }
+
+ private void save() {
+ new EpgSearchTimeValues(this).saveValues(values);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EventAdapter.java b/androvdr/src/de/bjusystems/androvdr/gui/EventAdapter.java
new file mode 100644
index 0000000..9ae014e
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EventAdapter.java
@@ -0,0 +1,171 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.GregorianCalendar;
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+import de.bjusystems.androvdr.data.EventFormatter;
+import de.bjusystems.androvdr.data.EventListItem;
+import de.bjusystems.androvdr.utils.date.DateFormatter;
+import de.bjusystems.androvdr.R;
+
+class EventAdapter extends ArrayAdapter<EventListItem> {
+
+ private final LayoutInflater inflater;
+ private final List<EventListItem> items;
+ private final boolean sortByTime;
+
+ public EventAdapter(final Context context, final boolean sortByTime) {
+ super(context, R.layout.event_item);
+ inflater = LayoutInflater.from(context);
+ items = new ArrayList<EventListItem>();
+ this.sortByTime = sortByTime;
+ }
+
+ @Override
+ public View getView(final int position, final View convertView, final ViewGroup parent) {
+
+ EventListItemHolder itemHolder = new EventListItemHolder();
+
+ // recycle view?
+ View view = convertView;
+ if (view == null) {
+ view = inflater.inflate(R.layout.event_item, null);
+ itemHolder = new EventListItemHolder();
+
+ itemHolder.state = (ImageView) view.findViewById(R.id.timer_item_state);
+ itemHolder.time = (TextView) view.findViewById(R.id.timer_item_time);
+ itemHolder.channel = (TextView) view.findViewById(R.id.timer_item_channel);
+ itemHolder.title = (TextView) view.findViewById(R.id.timer_item_title);
+
+ view.setTag(itemHolder);
+ } else {
+ itemHolder = (EventListItemHolder) view.getTag();
+ }
+
+ // get item
+ final EventListItem item = getItem(position);
+
+ // fill item
+ if (item.isHeader()) {
+ view.setPadding(view.getPaddingLeft(), 0, view.getPaddingRight(), 0);
+ view.setBackgroundColor(Color.DKGRAY);
+ itemHolder.state.setVisibility(View.GONE);
+ itemHolder.channel.setVisibility(View.GONE);
+ itemHolder.title.setVisibility(View.GONE);
+ itemHolder.time.setText(item.getHeader());
+ } else {
+ view.setBackgroundColor(Color.BLACK);
+ itemHolder.channel.setVisibility(View.VISIBLE);
+ itemHolder.title.setVisibility(View.VISIBLE);
+ itemHolder.state.setVisibility(View.VISIBLE);
+ switch (item.getTimerState()) {
+ case Active:
+ itemHolder.state.setImageResource(R.drawable.timer_active);
+ break;
+ case Inactive:
+ itemHolder.state.setImageResource(R.drawable.timer_inactive);
+ break;
+ case Recording:
+ itemHolder.state.setImageResource(R.drawable.timer_recording);
+ break;
+ case None:
+ itemHolder.state.setImageResource(R.drawable.timer_none);
+ break;
+ }
+ final EventFormatter formatter = new EventFormatter(item.getEvent());
+ itemHolder.time.setText(formatter.getTime());
+ itemHolder.channel.setText(item.getChannelName());
+ itemHolder.title.setText(formatter.getTitle());
+ }
+
+ return view;
+ }
+
+ public void addItem(final EventListItem item) {
+ items.add(item);
+ }
+
+ public void sortItems() {
+ if (sortByTime) {
+ sortItemsByTime();
+ } else {
+ sortItemsByChannel();
+ }
+ }
+
+ private void sortItemsByTime() {
+
+ // sort by start time
+ final EventListItem[] unsortedItems = items.toArray(new EventListItem[0]);
+ final Comparator<EventListItem> comparator = new Comparator<EventListItem>() {
+
+ public int compare(final EventListItem item1, final EventListItem item2) {
+ return item1.getStart().compareTo(item2.getStart());
+ }
+ };
+ Arrays.sort(unsortedItems, comparator);
+
+ // insert daily headers
+ final List<EventListItem> sortedItems = new ArrayList<EventListItem>();
+ final GregorianCalendar itemCal = new GregorianCalendar();
+ final GregorianCalendar lastHeaderCal = new GregorianCalendar();
+ lastHeaderCal.set(Calendar.YEAR, 1970);
+
+ for(final EventListItem item : unsortedItems) {
+ itemCal.setTime(item.getStart());
+
+ if (itemCal.get(Calendar.DAY_OF_YEAR) != lastHeaderCal.get(Calendar.DAY_OF_YEAR) ||
+ itemCal.get(Calendar.YEAR) != lastHeaderCal.get(Calendar.YEAR)) {
+ lastHeaderCal.setTimeInMillis(itemCal.getTimeInMillis());
+ final DateFormatter dateFormatter = new DateFormatter(lastHeaderCal);
+ sortedItems.add(new EventListItem(dateFormatter.getDailyHeader()));
+ }
+
+ sortedItems.add(item);
+ }
+
+ // fill adapter
+ clear();
+ for(final EventListItem item : sortedItems) {
+ add(item);
+ }
+ }
+
+ private void sortItemsByChannel() {
+
+ final EventListItem[] sortedItems = items.toArray(new EventListItem[0]);
+ final Comparator<EventListItem> comparator = new Comparator<EventListItem>() {
+
+ public int compare(final EventListItem item1, final EventListItem item2) {
+ return Integer.valueOf(item1.getChannelNumber()).compareTo(Integer.valueOf(item2.getChannelNumber()));
+ }
+ };
+ Arrays.sort(sortedItems, comparator);
+
+ // fill adapter
+ clear();
+ if (sortedItems.length > 0) {
+ add(new EventListItem(new DateFormatter(sortedItems[0].getStart()).getDailyHeader()));
+ }
+ for(final EventListItem item : sortedItems) {
+ add(item);
+ }
+
+ }
+
+ public void clearItems() {
+ items.clear();
+ }
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/EventListItemHolder.java b/androvdr/src/de/bjusystems/androvdr/gui/EventListItemHolder.java
new file mode 100644
index 0000000..bac1002
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/EventListItemHolder.java
@@ -0,0 +1,12 @@
+package de.bjusystems.androvdr.gui;
+
+import android.widget.ImageView;
+import android.widget.TextView;
+
+class EventListItemHolder {
+ public ImageView state;
+ public TextView title;
+ public TextView date;
+ public TextView time;
+ public TextView channel;
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/PreferencesActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/PreferencesActivity.java
new file mode 100644
index 0000000..eb1aec2
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/PreferencesActivity.java
@@ -0,0 +1,34 @@
+package de.bjusystems.androvdr.gui;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+public class PreferencesActivity extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ this.getPreferenceManager().setSharedPreferencesName(Preferences.getPreferenceFile(this));
+ this.addPreferencesFromResource(R.xml.preferences);
+ }
+
+ @Override
+ public void onBackPressed() {
+
+ // finish this activity
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.addActivityToFinish(this);
+ app.finishActivities();
+
+ // restart main activity because
+ // the buttons needs refreshing
+ final Intent intent = new Intent();
+ intent.setClass(this, AndroVdrActivity.class);
+ startActivity(intent);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/SvdrpProgressDialog.java b/androvdr/src/de/bjusystems/androvdr/gui/SvdrpProgressDialog.java
new file mode 100644
index 0000000..904cefd
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/SvdrpProgressDialog.java
@@ -0,0 +1,72 @@
+package de.bjusystems.androvdr.gui;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.widget.Toast;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpException;
+import de.bjusystems.androvdr.R;
+
+public class SvdrpProgressDialog extends ProgressDialog {
+
+ ProgressDialog progress;
+ Activity activity;
+ SvdrpClient<? extends Object> client;
+
+ public SvdrpProgressDialog(final Activity activity, final SvdrpClient<? extends Object> client) {
+ super(activity);
+ this.activity = activity;
+ this.client = client;
+ }
+
+ public void svdrpEvent(final SvdrpEvent event) {
+
+ switch (event) {
+ case CONNECTING:
+ progress = new ProgressDialog(activity);
+ progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+ setMessage(R.string.progress_connect);
+ progress.show();
+ break;
+ case LOGGED_IN:
+ setMessage(R.string.progress_login);
+ break;
+ case LOGIN_ERROR:
+ progress.dismiss();
+ showToast(R.string.progress_login_error);
+ break;
+ case COMMAND_SENT:
+ setMessage(client.getProgressTextId());
+ break;
+ case RESULT_RECEIVED:
+ break;
+ case DISCONNECTING:
+ setMessage(R.string.progress_disconnect);
+ break;
+ case DISCONNECTED:
+ break;
+ case FINISHED:
+ progress.dismiss();
+ break;
+ }
+ }
+
+ public void svdrpException(final SvdrpException exception) {
+ showToast(R.string.vdr_error_text);
+ }
+
+ private void setMessage(final int resId) {
+ progress.setMessage(activity.getText(resId));
+ }
+
+ private void showToast(final int resId) {
+ progress.dismiss();
+
+ final CharSequence text = activity.getText(resId);
+ final int duration = Toast.LENGTH_LONG;
+ final Toast toast = Toast.makeText(activity, text, duration);
+ toast.show();
+ }
+}
+
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/TimerDetailsActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/TimerDetailsActivity.java
new file mode 100644
index 0000000..1bd25ad
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/TimerDetailsActivity.java
@@ -0,0 +1,232 @@
+package de.bjusystems.androvdr.gui;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import android.app.Activity;
+import android.app.DatePickerDialog;
+import android.app.DatePickerDialog.OnDateSetListener;
+import android.app.TimePickerDialog;
+import android.app.TimePickerDialog.OnTimeSetListener;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.DatePicker;
+import android.widget.TextView;
+import android.widget.TimePicker;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.utils.date.DateFormatter;
+import de.bjusystems.androvdr.utils.svdrp.SetTimerClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncListener;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpException;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class TimerDetailsActivity extends Activity
+ implements OnClickListener, OnDateSetListener, OnTimeSetListener, SvdrpAsyncListener<Timer> {
+
+ Preferences prefs;
+ TextView dateField;
+ TextView startField;
+ TextView endField;
+ boolean editStart;
+ Timer timer;
+ SvdrpProgressDialog progress;
+ SetTimerClient setTimerClient;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.timer_detail);
+
+ // timer
+ timer = ((AndroVdrApp)getApplication()).getCurrentTimer();
+
+ // update display
+ updateDisplay();
+
+ // register buttons
+ final Button saveButton = (Button) findViewById(R.id.timer_details_save);
+ saveButton.setOnClickListener(this);
+ if (timer.getNumber() > 0) {
+ saveButton.setText(R.string.timer_details_save_title);
+ } else {
+ saveButton.setText(R.string.timer_details_create_title);
+ }
+
+ // register text fields for editing
+ dateField.setOnClickListener(this);
+ startField.setOnClickListener(this);
+ endField.setOnClickListener(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ public void onClick(final View view) {
+ switch (view.getId()) {
+ case R.id.timer_detail_day:
+ {
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(timer.getStart());
+ final DatePickerDialog dialog = new DatePickerDialog(this, this, cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
+ dialog.show();
+ break;
+ }
+ case R.id.timer_detail_start:
+ {
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(timer.getStart());
+ editStart = true;
+ final TimePickerDialog dialog = new TimePickerDialog(this, this, cal.get(Calendar.HOUR_OF_DAY),
+ cal.get(Calendar.MINUTE), true);
+ dialog.show();
+ break;
+ }
+ case R.id.timer_detail_end:
+ {
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(timer.getStop());
+ editStart = false;
+ final TimePickerDialog dialog = new TimePickerDialog(this, this, cal.get(Calendar.HOUR_OF_DAY),
+ cal.get(Calendar.MINUTE), true);
+ dialog.show();
+ break;
+ }
+ case R.id.timer_details_save:
+ {
+ // collect values
+ timer.setTitle(((TextView)findViewById(R.id.timer_detail_title)).getText().toString());
+
+ // create client for saving the timer
+ setTimerClient = new SetTimerClient(timer, false);
+
+ // create backgound task
+ final SvdrpAsyncTask<Timer, SvdrpClient<Timer>> task = new SvdrpAsyncTask<Timer, SvdrpClient<Timer>>(setTimerClient);
+
+ // create progress
+ progress = new SvdrpProgressDialog(this, setTimerClient);
+
+ // attach listener
+ task.addListener(this);
+
+ // start task
+ task.run();
+ }
+ }
+ }
+
+ public void onTimeSet(final TimePicker view, final int hourOfDay, final int minute) {
+ if (editStart) {
+ timer.setStart(calculateTime(timer.getStart(), hourOfDay, minute, null));
+ } else {
+ timer.setStop(calculateTime(timer.getStop(), hourOfDay, minute, timer.getStart()));
+ }
+ updateDisplay();
+ }
+
+ public void onDateSet(final DatePicker view, final int year, final int monthOfYear, final int dayOfMonth) {
+ timer.setStart(calculateDate(timer.getStart(), year, monthOfYear, dayOfMonth));
+ updateDisplay();
+ }
+
+ private Date calculateDate(final Date oldDate, final int year, final int monthOfYear, final int dayOfMonth) {
+
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(oldDate);
+ cal.set(Calendar.YEAR, year);
+ cal.set(Calendar.MONTH, monthOfYear);
+ cal.set(Calendar.DAY_OF_MONTH, dayOfMonth);
+
+ return cal.getTime();
+ }
+
+ private Date calculateTime(final Date oldTime, final int hourOfDay, final int minute, final Date startTime) {
+
+ // set hour and minute
+ final Calendar cal = new GregorianCalendar();
+ cal.setTime(oldTime);
+ cal.set(Calendar.HOUR_OF_DAY, hourOfDay);
+ cal.set(Calendar.MINUTE, minute);
+
+ // go to the next day if end time before start time
+ if (startTime != null) {
+ if (cal.getTime().before(startTime)) {
+ cal.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ }
+
+ return cal.getTime();
+
+ }
+
+ private void updateDisplay() {
+
+ ((TextView)findViewById(R.id.timer_detail_title)).setText(timer.getTitle());
+ ((TextView)findViewById(R.id.timer_detail_channel)).setText(timer.getChannelName());
+ dateField = (TextView)findViewById(R.id.timer_detail_day);
+ final DateFormatter dateFormatter = new DateFormatter(timer.getStart());
+ dateField.setText(dateFormatter.getDateString());
+ startField = (TextView)findViewById(R.id.timer_detail_start);
+ startField.setText(dateFormatter.getTimeString());
+ endField = (TextView)findViewById(R.id.timer_detail_end);
+ endField.setText(new DateFormatter(timer.getStop()).getTimeString());
+
+ final Button button = (Button) findViewById(R.id.timer_details_save);
+ if (timer.getNumber() > 0) {
+ // existing timer
+ button.setText(R.string.timer_details_save_title);
+ } else {
+ // new timer
+ button.setText(R.string.timer_details_create_title);
+ }
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Timer result) {
+
+ progress.svdrpEvent(event);
+
+ switch (event) {
+ case FINISHED:
+ // remove this activity from stack
+ finish();
+
+ // finish previous activities
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.finishActivities();
+
+ // refresh last view
+ app.setReload(true);
+
+ // free progress dialog
+ progress = null;
+
+ break;
+ }
+ }
+
+ public void svdrpException(final SvdrpException exception) {
+ progress.svdrpException(exception);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/TimerListActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/TimerListActivity.java
new file mode 100644
index 0000000..8dc7e51
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/TimerListActivity.java
@@ -0,0 +1,238 @@
+package de.bjusystems.androvdr.gui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListView;
+import de.bjusystems.androvdr.app.AndroVdrApp;
+import de.bjusystems.androvdr.data.EventFormatter;
+import de.bjusystems.androvdr.data.EventListItem;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.tasks.DeleteTimerTask;
+import de.bjusystems.androvdr.tasks.ToggleTimerTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncListener;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpException;
+import de.bjusystems.androvdr.utils.svdrp.TimerClient;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class TimerListActivity extends Activity
+ implements OnItemClickListener, SvdrpAsyncListener<Timer> {
+
+ TimerClient timerClient;
+ EventAdapter adapter;
+ SvdrpProgressDialog progress;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.timer_list);
+
+ // create an adapter
+ adapter = new EventAdapter(this, true);
+
+ // attach adapter to ListView
+ final ListView listView = (ListView) findViewById(R.id.timer_list);
+ listView.setAdapter(adapter);
+
+ // set click listener
+ listView.setOnItemClickListener(this);
+
+ // context menu wanted
+ registerForContextMenu(listView);
+
+ // start query
+ startTimerQuery();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ reloadIfNeeded();
+ }
+
+ private void reloadIfNeeded() {
+
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ if (app.isReload()) {
+ app.setReload(false);
+ startTimerQuery();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (timerClient != null) {
+ timerClient.abort();
+ }
+ if (progress != null) {
+ progress.dismiss();
+ progress = null;
+ }
+ }
+
+ @Override
+ public void onCreateContextMenu(final ContextMenu menu, final View v, final ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, v, menuInfo);
+
+ if (v.getId() == R.id.timer_list) {
+ final MenuInflater inflater = getMenuInflater();
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+
+ // set menu title
+ final EventListItem item = adapter.getItem(info.position);
+ final EventFormatter formatter = new EventFormatter(item);
+ menu.setHeaderTitle(formatter.getTitle());
+
+ inflater.inflate(R.menu.epg_list_item_menu, menu);
+
+ // remove unneeded menu items
+ menu.findItem(R.id.epg_item_menu_timer_add).setVisible(false);
+ final MenuItem enableMenuItem = menu.findItem(R.id.epg_item_menu_timer_toggle);
+ enableMenuItem.setTitle(item.getTimer().isEnabled() ? R.string.epg_item_menu_timer_disable : R.string.epg_item_menu_timer_enable);
+ }
+ }
+
+
+
+ @Override
+ public boolean onContextItemSelected(final MenuItem item) {
+
+ final AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
+ final EventListItem event = adapter.getItem(info.position);
+
+ switch (item.getItemId()) {
+ case R.id.epg_item_menu_timer_modify:
+ {
+ onItemClick(null, null, info.position, 0);
+ break;
+ }
+ case R.id.epg_item_menu_timer_delete:
+ {
+ deleteTimer(event);
+ break;
+ }
+ case R.id.epg_item_menu_timer_toggle:
+ {
+ toggleTimer(event);
+ }
+ }
+
+ return true;
+ }
+
+ public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) {
+
+ // save selected item
+ final Timer timer = adapter.getItem(position).getTimer();
+ if (timer == null) {
+ // header click
+ return;
+ }
+
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setCurrentTimer(timer);
+
+ // after timer editing return to the timer list
+ app.setNextActivity(TimerListActivity.class);
+ app.clearActivitiesToFinish();
+
+ // show timer details
+ final Intent intent = new Intent();
+ intent.setClass(this, TimerDetailsActivity.class);
+ startActivity(intent);
+ }
+
+ private void startTimerQuery() {
+
+ // get timer client
+ timerClient = new TimerClient();
+
+ // create backgound task
+ final SvdrpAsyncTask<Timer, SvdrpClient<Timer>> task = new SvdrpAsyncTask<Timer, SvdrpClient<Timer>>(timerClient);
+
+ // create progress dialog
+ progress = new SvdrpProgressDialog(this, timerClient);
+
+ // attach listener
+ task.addListener(this);
+
+ // start task
+ task.run();
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Timer result) {
+
+ if (progress != null) {
+ progress.svdrpEvent(event);
+ }
+
+ switch (event) {
+ case CONNECTING:
+ adapter.clearItems();
+ break;
+ case LOGIN_ERROR:
+ this.finish();
+ break;
+ case FINISHED:
+ for(final Timer timer : timerClient.getResults()) {
+ adapter.addItem(new EventListItem(timer));
+ }
+ adapter.sortItems();
+ progress = null;
+ break;
+ }
+ }
+
+ public void svdrpException(final SvdrpException exception) {
+ if (progress != null) {
+ progress.svdrpException(exception);
+ }
+ }
+
+ private void deleteTimer(final EventListItem item) {
+
+ final DeleteTimerTask task = new DeleteTimerTask(this, item.getTimer()) {
+ @Override
+ public void finished() {
+ // refresh epg list after return
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setReload(true);
+ reloadIfNeeded();
+ }
+ };
+ task.start();
+ }
+
+ private void toggleTimer(final EventListItem item) {
+
+ final ToggleTimerTask task = new ToggleTimerTask(this, item.getTimer()) {
+ @Override
+ public void finished() {
+ // refresh epg list after return
+ final AndroVdrApp app = (AndroVdrApp) getApplication();
+ app.setReload(true);
+ reloadIfNeeded();
+ }
+ };
+ task.start();
+ }
+
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/gui/VideoActivity.java b/androvdr/src/de/bjusystems/androvdr/gui/VideoActivity.java
new file mode 100644
index 0000000..3ec7981
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/gui/VideoActivity.java
@@ -0,0 +1,67 @@
+package de.bjusystems.androvdr.gui;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.MediaController;
+import android.widget.VideoView;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * This class is used for showing what's
+ * current running on all channels
+ * @author bju
+ */
+public class VideoActivity extends Activity
+ implements OnClickListener {
+
+ Preferences prefs;
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Attach view
+ setContentView(R.layout.video);
+
+ // set stream
+ final VideoView videoView = (VideoView) findViewById(R.id.video_video);
+ final MediaController mediaController = new MediaController(this);
+ mediaController.setAnchorView(videoView);
+ final Uri video = Uri.parse("http://192.168.178.20:3000/1");
+ videoView.setMediaController(mediaController);
+ videoView.setVideoURI(video);
+ videoView.start();
+
+ // register button
+ final Button button = (Button) findViewById(R.id.video_button);
+ button.setOnClickListener(this);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ public void onClick(final View v) {
+
+ // Save search parameters
+// final EpgSearchParams search = new EpgSearchParams();
+// search.setTitle(text.getText().toString());
+// ((AndroVdrApp)getApplication()).setCurrentSearch(search);
+
+ // show timer details
+// final Intent intent = new Intent();
+// intent.setClass(this, AndroVdrActivity.class);
+// startActivity(intent);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/tasks/AsyncProgressTask.java b/androvdr/src/de/bjusystems/androvdr/tasks/AsyncProgressTask.java
new file mode 100644
index 0000000..a4b1110
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/tasks/AsyncProgressTask.java
@@ -0,0 +1,55 @@
+package de.bjusystems.androvdr.tasks;
+
+import android.app.Activity;
+import de.bjusystems.androvdr.gui.SvdrpProgressDialog;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncListener;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpAsyncTask;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpClient;
+import de.bjusystems.androvdr.utils.svdrp.SvdrpEvent;
+
+public abstract class AsyncProgressTask<Result> {
+
+ class AsyncProgress extends SvdrpProgressDialog implements SvdrpAsyncListener<Result> {
+
+ public AsyncProgress(final Activity activity, final SvdrpClient<Result> client) {
+ super(activity, client);
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Object result) {
+ svdrpEvent(event);
+
+ switch (event) {
+ case FINISHED:
+ AsyncProgressTask.this.finished();
+ break;
+ }
+ }
+ }
+
+ Activity activity;
+ SvdrpClient<Result> client;
+
+ public AsyncProgressTask(final Activity activity, final SvdrpClient<Result> client) {
+ this.activity = activity;
+ this.client = client;
+ }
+
+ public void start() {
+
+ // delete timer
+/*
+ final SetTimerClient client = new SetTimerClient(timer, true) {
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_timer_delete;
+ }
+ };
+*/
+ final SvdrpAsyncTask<Result, SvdrpClient<Result>> task = new SvdrpAsyncTask<Result, SvdrpClient<Result>>(client);
+ final AsyncProgress progress = new AsyncProgress(activity, client);
+ task.addListener(progress);
+ task.run();
+ }
+
+ public abstract void finished();
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/tasks/DeleteTimerTask.java b/androvdr/src/de/bjusystems/androvdr/tasks/DeleteTimerTask.java
new file mode 100644
index 0000000..6d36db2
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/tasks/DeleteTimerTask.java
@@ -0,0 +1,18 @@
+package de.bjusystems.androvdr.tasks;
+
+import android.app.Activity;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.utils.svdrp.SetTimerClient;
+import de.bjusystems.androvdr.R;
+
+public abstract class DeleteTimerTask extends AsyncProgressTask<Timer> {
+
+ public DeleteTimerTask(final Activity activity, final Timer timer) {
+ super(activity, new SetTimerClient(timer, true) {
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_timer_delete;
+ }
+ });
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/tasks/ToggleTimerTask.java b/androvdr/src/de/bjusystems/androvdr/tasks/ToggleTimerTask.java
new file mode 100644
index 0000000..a2a3724
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/tasks/ToggleTimerTask.java
@@ -0,0 +1,25 @@
+package de.bjusystems.androvdr.tasks;
+
+import android.app.Activity;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.utils.svdrp.SetTimerClient;
+import de.bjusystems.androvdr.R;
+
+public abstract class ToggleTimerTask extends AsyncProgressTask<Timer> {
+
+ public ToggleTimerTask(final Activity activity, final Timer timer) {
+ super(activity, new SetTimerClient(timer, false) {
+ boolean enabled = timer.isEnabled();
+
+ @Override
+ public int getProgressTextId() {
+ if (enabled) {
+ return R.string.progress_timer_disable;
+ } else {
+ return R.string.progress_timer_enable;
+ }
+ }
+ });
+ timer.setEnabled(!timer.isEnabled());
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/date/DateFormatter.java b/androvdr/src/de/bjusystems/androvdr/utils/date/DateFormatter.java
new file mode 100644
index 0000000..2b9c266
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/date/DateFormatter.java
@@ -0,0 +1,43 @@
+package de.bjusystems.androvdr.utils.date;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Class for formatting date and time values
+ * @author bju
+ *
+ */
+public class DateFormatter {
+
+ private final String timeString;
+ private final String dateString;
+ private final String dailyHeader;
+
+ public DateFormatter(final Date date) {
+ timeString = DateFormat.getTimeInstance(DateFormat.SHORT).format(date);
+ dateString = DateFormat.getDateInstance(DateFormat.SHORT).format(date);
+ dailyHeader = DateFormat.getDateInstance(DateFormat.FULL).format(date);
+ }
+
+ public DateFormatter(final long seconds) {
+ this(new Date(seconds * 1000));
+ }
+
+ public DateFormatter(final Calendar cal) {
+ this(cal.getTime());
+ }
+
+ public String getDateString() {
+ return dateString;
+ }
+
+ public String getTimeString() {
+ return timeString;
+ }
+
+ public String getDailyHeader() {
+ return dailyHeader;
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/http/HttpHelper.java b/androvdr/src/de/bjusystems/androvdr/utils/http/HttpHelper.java
new file mode 100644
index 0000000..86a30d1
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/http/HttpHelper.java
@@ -0,0 +1,263 @@
+package de.bjusystems.androvdr.utils.http;
+
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.GZIPInputStream;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseInterceptor;
+import org.apache.http.HttpVersion;
+import org.apache.http.NameValuePair;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.HttpEntityWrapper;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.protocol.HttpContext;
+
+/**
+ * Apache HttpClient helper class for performing HTTP requests.
+ *
+ * This class is intentionally *not* bound to any Android classes so that it is easier
+ * to develop and test. Use calls to this class inside Android AsyncTask implementations
+ * (or manual Thread-Handlers) to make HTTP requests asynchronous and not block the UI Thread.
+ *
+ * TODO cookies
+ * TODO multi-part binary data
+ * TODO follow 302s?
+ * TODO shutdown connection mgr? - client.getConnectionManager().shutdown();
+ *
+ * @author ccollins
+ *
+ */
+public class HttpHelper {
+
+ private static final String CONTENT_TYPE = "Content-Type";
+ private static final int POST_TYPE = 1;
+ private static final int GET_TYPE = 2;
+ private static final String GZIP = "gzip";
+ private static final String ACCEPT_ENCODING = "Accept-Encoding";
+
+ public static final String MIME_FORM_ENCODED = "application/x-www-form-urlencoded";
+ public static final String MIME_TEXT_PLAIN = "text/plain";
+ public static final String HTTP_RESPONSE = "HTTP_RESPONSE";
+ public static final String HTTP_RESPONSE_ERROR = "HTTP_RESPONSE_ERROR";
+
+ private final DefaultHttpClient client;
+ private final ResponseHandler<String> responseHandler;
+
+ /**
+ * Constructor.
+ *
+ */
+ public HttpHelper() {
+
+ final HttpParams params = new BasicHttpParams();
+ params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
+ params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
+ params.setParameter(CoreProtocolPNames.USER_AGENT, "Apache-HttpClient/Android");
+ params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15000);
+ params.setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false);
+ final SchemeRegistry schemeRegistry = new SchemeRegistry();
+ schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
+ final ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
+ client = new DefaultHttpClient(cm, params);
+
+ // add gzip decompressor to handle gzipped content in responses
+ // (default we *do* always send accept encoding gzip header in request)
+ client.addResponseInterceptor(new HttpResponseInterceptor() {
+ public void process(final HttpResponse response, final HttpContext context) throws HttpException, IOException {
+ final HttpEntity entity = response.getEntity();
+ final Header contentEncodingHeader = entity.getContentEncoding();
+ if (contentEncodingHeader != null) {
+ final HeaderElement[] codecs = contentEncodingHeader.getElements();
+ for (int i = 0; i < codecs.length; i++) {
+ if (codecs[i].getName().equalsIgnoreCase(HttpHelper.GZIP)) {
+ response.setEntity(new GzipDecompressingEntity(response.getEntity()));
+ return;
+ }
+ }
+ }
+ }
+ });
+
+ responseHandler = new BasicResponseHandler();
+ }
+
+ /**
+ * Perform a simple HTTP GET operation.
+ *
+ */
+ public String performGet(final String url) {
+ return performRequest(null, url, null, null, null, null, HttpHelper.GET_TYPE);
+ }
+
+ /**
+ * Perform an HTTP GET operation with user/pass and headers.
+ *
+ */
+ public String performGet(final String url, final String user, final String pass,
+ final Map<String, String> additionalHeaders) {
+ return performRequest(null, url, user, pass, additionalHeaders, null, HttpHelper.GET_TYPE);
+ }
+
+ /**
+ * Perform a simplified HTTP POST operation.
+ *
+ */
+ public String performPost(final String url, final Map<String, String> params) {
+ return performRequest(HttpHelper.MIME_FORM_ENCODED, url, null, null, null, params, HttpHelper.POST_TYPE);
+ }
+
+ /**
+ * Perform an HTTP POST operation with user/pass, headers, request
+ parameters,
+ * and a default content-type of "application/x-www-form-urlencoded."
+ *
+ */
+ public String performPost(final String url, final String user, final String pass,
+ final Map<String, String> additionalHeaders, final Map<String, String> params) {
+ return performRequest(HttpHelper.MIME_FORM_ENCODED, url, user, pass, additionalHeaders, params,
+ HttpHelper.POST_TYPE);
+ }
+
+ /**
+ * Perform an HTTP POST operation with flexible parameters (the
+ complicated/flexible version of the method).
+ *
+ */
+ public String performPost(final String contentType, final String url, final String user, final String pass,
+ final Map<String, String> additionalHeaders, final Map<String, String> params) {
+ return performRequest(contentType, url, user, pass, additionalHeaders, params, HttpHelper.POST_TYPE);
+ }
+
+ //
+ // private methods
+ //
+ private String performRequest(final String contentType, final String url, final String user, final String pass,
+ final Map<String, String> headers, final Map<String, String> params, final int requestType) {
+
+ // add user and pass to client credentials if present
+ if ((user != null) && (pass != null)) {
+ client.getCredentialsProvider().setCredentials(AuthScope.ANY,
+ new UsernamePasswordCredentials(user, pass));
+ }
+
+ // process headers using request interceptor
+ final Map<String, String> sendHeaders = new HashMap<String, String>();
+ // add encoding header for gzip if not present
+ if (!sendHeaders.containsKey(HttpHelper.ACCEPT_ENCODING)) {
+ sendHeaders.put(HttpHelper.ACCEPT_ENCODING, HttpHelper.GZIP);
+ }
+ if ((headers != null) && (headers.size() > 0)) {
+ sendHeaders.putAll(headers);
+ }
+ if (requestType == HttpHelper.POST_TYPE) {
+ sendHeaders.put(HttpHelper.CONTENT_TYPE, contentType);
+ }
+ if (sendHeaders.size() > 0) {
+ client.addRequestInterceptor(new HttpRequestInterceptor() {
+ public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException {
+ for (final String key : sendHeaders.keySet()) {
+ if (!request.containsHeader(key)) {
+ request.addHeader(key, sendHeaders.get(key));
+ }
+ }
+ }
+ });
+ }
+
+ // handle POST or GET request respectively
+ HttpRequestBase method = null;
+ if (requestType == HttpHelper.POST_TYPE) {
+ method = new HttpPost(url);
+ // data - name/value params
+ List<NameValuePair> nvps = null;
+ if ((params != null) && (params.size() > 0)) {
+ nvps = new ArrayList<NameValuePair>();
+ for (final Map.Entry<String, String> entry : params.entrySet()) {
+ nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
+ }
+ }
+ if (nvps != null) {
+ try {
+ final HttpPost methodPost = (HttpPost) method;
+ methodPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
+ } catch (final UnsupportedEncodingException e) {
+ throw new RuntimeException("Error peforming HTTP request: " + e.getMessage(), e);
+ }
+ }
+ } else if (requestType == HttpHelper.GET_TYPE) {
+ method = new HttpGet(url);
+ }
+
+
+ // execute request
+ return execute(method);
+ }
+
+ private synchronized String execute(final HttpRequestBase method) {
+ String response = null;
+ // execute method returns?!? (rather than async) - do it here sync, and wrap async elsewhere
+ try {
+ response = client.execute(method, responseHandler);
+ } catch (final ClientProtocolException e) {
+ response = HttpHelper.HTTP_RESPONSE_ERROR + " - " + e.getClass().getSimpleName() + " " + e.getMessage();
+ //e.printStackTrace();
+ } catch (final IOException e) {
+ response = HttpHelper.HTTP_RESPONSE_ERROR + " - " + e.getClass().getSimpleName() + " " + e.getMessage();
+ //e.printStackTrace();
+ }
+ return response;
+ }
+
+ static class GzipDecompressingEntity extends HttpEntityWrapper {
+ public GzipDecompressingEntity(final HttpEntity entity) {
+ super(entity);
+ }
+
+ @Override
+ public InputStream getContent() throws IOException, IllegalStateException {
+ // the wrapped entity's getContent() decides about repeatability
+ final InputStream wrappedin = wrappedEntity.getContent();
+ return new GZIPInputStream(wrappedin);
+ }
+
+ @Override
+ public long getContentLength() {
+ // length of ungzipped content is not known
+ return -1;
+ }
+ }
+}
+
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/AliveClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/AliveClient.java
new file mode 100644
index 0000000..cc34c80
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/AliveClient.java
@@ -0,0 +1,49 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import de.bjusystems.androvdr.data.AliveState;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class AliveClient extends SvdrpClient<AliveState> {
+
+ /**
+ * Constructor
+ * @param host host
+ * @param port port
+ * @param ssl use ssl
+ */
+ public AliveClient() {
+ super();
+ }
+
+ /**
+ * Starts the EPG request
+ * @param parameter parameter for lste
+ */
+ @Override
+ public void run() throws SvdrpException {
+ runCommand("aliv");
+ }
+
+ @Override
+ public AliveState parseAnswer(final String line) {
+
+ if (line.startsWith("200")) {
+ return AliveState.ALIVE;
+ }
+ if (line.startsWith("400")) {
+ return AliveState.DEAD;
+ }
+ return AliveState.UNKNOWN;
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return 0;
+ }
+
+
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/ChannelClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/ChannelClient.java
new file mode 100644
index 0000000..b8a010a
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/ChannelClient.java
@@ -0,0 +1,44 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.R;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class ChannelClient extends SvdrpClient<Channel> {
+
+ /**
+ * Constructor
+ * @param host host
+ * @param port port
+ * @param ssl use ssl
+ */
+ public ChannelClient() {
+ super();
+ }
+
+ /**
+ * Starts the EPG request
+ * @param parameter parameter for lste
+ */
+ @Override
+ public void run() throws SvdrpException {
+ runCommand("channels " + Preferences.getPreferences().getChannels());
+ }
+
+ @Override
+ public Channel parseAnswer(final String line) {
+ return new Channel(line);
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_channels_loading;
+ }
+
+
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/EpgClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/EpgClient.java
new file mode 100644
index 0000000..5a2c214
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/EpgClient.java
@@ -0,0 +1,91 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Epg;
+import de.bjusystems.androvdr.data.EpgSearchParams;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.R;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class EpgClient extends SvdrpClient<Epg> {
+
+ /** Time to retrieve EPG for */
+ private String time;
+ /** Channel to retrieve EPG for */
+ private Channel channel;
+ /** Search parameters to retrieve EPG for */
+ private EpgSearchParams search;
+ /** Last read EPG */
+ private Epg lastEpg;
+
+ /**
+ * Constructor
+ */
+ private EpgClient() {
+ super();
+ this.time = null;
+ this.channel = null;
+ this.search = null;
+ }
+
+ /**
+ * Constructor
+ * @param time time to search for epg events
+ */
+ public EpgClient(final String time) {
+ this();
+ this.time = time;
+ }
+
+ /**
+ * Constructor
+ * @param channel channel to search for epg events
+ */
+ public EpgClient(final Channel channel) {
+ this();
+ this.channel = channel;
+ }
+
+ public EpgClient(final EpgSearchParams search) {
+ this();
+ this.search = search;
+ }
+
+ /**
+ * Starts the EPG request
+ * @param parameter parameter for lste
+ */
+ @Override
+ public void run() throws SvdrpException {
+ if (time != null) {
+ runCommand(String.format("tevents %s %s", time, Preferences.getPreferences().getChannels()));
+ } else if (channel != null) {
+ runCommand(String.format("cevents %s", channel.getNumber()));
+ } else if (search != null) {
+ runCommand(String.format("search %s %s", Preferences.getPreferences().getChannels(), search.toCommandLine()));
+ }
+ }
+
+ @Override
+ public Epg parseAnswer(final String line) {
+
+ if (line.startsWith("E")) {
+ lastEpg = new Epg(line);
+ return lastEpg;
+ } else if (line.startsWith("T")) {
+ lastEpg.setTimer(new Timer(line));
+ }
+ return null;
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_whatson_loading;
+ }
+}
+
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SetTimerClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SetTimerClient.java
new file mode 100644
index 0000000..6d870d1
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SetTimerClient.java
@@ -0,0 +1,59 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.R;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class SetTimerClient extends SvdrpClient<Timer> {
+
+ /** channel names for timer */
+ Timer timer;
+ /** timer should be deleted */
+ boolean deleteTimer;
+
+ /**
+ * Constructor
+ * @param host host
+ * @param port port
+ * @param ssl use ssl
+ */
+ public SetTimerClient(final Timer timer, final boolean deleteTimer) {
+ super();
+ this.timer = timer;
+ this.deleteTimer = deleteTimer;
+ }
+
+ /**
+ * Starts the request
+ */
+ @Override
+ public void run() throws SvdrpException {
+
+ final StringBuilder command = new StringBuilder();
+
+ command.append("timer ");
+ if (deleteTimer) {
+ command.append("-");
+ }
+ command.append(timer.getNumber());
+ command.append(" ");
+ command.append(timer.toCommandLine());
+
+ runCommand(command.toString());
+ }
+
+ @Override
+ public Timer parseAnswer(final String line) {
+ return new Timer(line);
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_timer_save;
+ }
+}
+
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncListener.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncListener.java
new file mode 100644
index 0000000..46ed03c
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncListener.java
@@ -0,0 +1,7 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+public interface SvdrpAsyncListener<Result> extends SvdrpListener<Result> {
+
+ void svdrpException(SvdrpException exception);
+
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncTask.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncTask.java
new file mode 100644
index 0000000..a361602
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpAsyncTask.java
@@ -0,0 +1,61 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.os.AsyncTask;
+
+public class SvdrpAsyncTask<Result, Client extends SvdrpClient<Result>>
+ extends AsyncTask<Void, Object, Void>
+ implements SvdrpListener<Result> {
+
+ Client client;
+ List<SvdrpAsyncListener<Result>> listeners = new ArrayList<SvdrpAsyncListener<Result>>();
+
+ public SvdrpAsyncTask(final Client client) {
+ this.client = client;
+ client.addSvdrpListener(this);
+ }
+
+ public void addListener(final SvdrpAsyncListener<Result> listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(final SvdrpAsyncListener<Result> listener) {
+ listeners.remove(listener);
+ }
+
+ public void run() {
+ execute();
+ }
+
+ @Override
+ protected Void doInBackground(final Void... params) {
+ try {
+ client.run();
+ } catch (final SvdrpException e) {
+ publishProgress(null, null, e);
+ }
+ return null;
+ }
+
+ public void svdrpEvent(final SvdrpEvent event, final Result result) {
+ publishProgress(event, result, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void onProgressUpdate(final Object... values) {
+ super.onProgressUpdate(values);
+
+ if (values[2] == null) {
+ for(final SvdrpAsyncListener<Result> listener : listeners) {
+ listener.svdrpEvent((SvdrpEvent)values[0], (Result)values[1]);
+ }
+ } else {
+ for(final SvdrpAsyncListener<Result> listener : listeners) {
+ listener.svdrpException((SvdrpException)values[2]);
+ }
+ }
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpClient.java
new file mode 100644
index 0000000..868e2f7
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpClient.java
@@ -0,0 +1,275 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.bjusystems.androvdr.data.Preferences;
+
+
+/**
+ * Class for SVDRP communication
+ * @author bju
+ *
+ */
+public abstract class SvdrpClient<Result> {
+
+ /** Socket for connection to SVDRP */
+ private Socket socket;
+ /** Output stream for sending commands */
+ private OutputStream outputStream;
+ /** Input stream for reading answer lines */
+ private InputStream inputStream;
+ /** flag for stopping the current request */
+ private boolean abort;
+ /** listener */
+ private final List<SvdrpListener<Result>> listeners = new ArrayList<SvdrpListener<Result>>();
+ /** list of results */
+ private final List<Result> results = new ArrayList<Result>();
+ /** should the listener be informed about each received result */
+ private boolean resultInfoEnabled = false;
+
+ /**
+ * Parse received answer line
+ * @param line line
+ * @return received data object or null if not completed yet
+ */
+ protected abstract Result parseAnswer(String line);
+
+ public abstract int getProgressTextId();
+
+ public abstract void run() throws SvdrpException;
+
+ /**
+ * Constructor
+ * @param prefs Preferences
+ */
+ protected SvdrpClient() {
+ results.clear();
+ }
+
+ /**
+ * Remove all listeners
+ */
+ public void clearSvdrpListener() {
+ listeners.clear();
+ }
+
+ /**
+ * Adds the listener to the list of listeners
+ * @param listener listener
+ */
+ public void addSvdrpListener(final SvdrpListener<Result> listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Removes the listener from the list of listeners
+ * @param listener listener
+ */
+ public void removeSvdrpListener(final SvdrpListener<Result> listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Cancel the current request
+ */
+ public void abort() {
+ abort = true;
+ }
+
+ /**
+ * Gets the list of results
+ * @return results
+ */
+ public List<Result> getResults() {
+ return results;
+ }
+
+ /**
+ * Connect to SVDRP
+ * @param host host
+ * @param port port
+ * @param ssl use SSL
+ * @throws IOException on errors
+ */
+ protected boolean connect() throws IOException {
+
+ final Preferences prefs = Preferences.getPreferences();
+
+ try {
+ // connect
+ informListener(SvdrpEvent.CONNECTING, null);
+ if (prefs.isSSL()) {
+ throw new IllegalArgumentException("SSL not implemented yet");
+ } else {
+ socket = new Socket(prefs.getSvdrpHost(), prefs.getSvdrpPort());
+ }
+ informListener(SvdrpEvent.CONNECTED, null);
+ } catch (final IOException e) {
+ informListener(SvdrpEvent.CONNECT_ERROR, null);
+ return false;
+ }
+
+ // create streams
+ outputStream = socket.getOutputStream();
+ inputStream = socket.getInputStream();
+
+ // password needed?
+ informListener(SvdrpEvent.LOGIN, null);
+ writeLine("passwd " + prefs.getPassword());
+ if (!readLine().startsWith("!OK")) {
+ informListener(SvdrpEvent.LOGIN_ERROR, null);
+ disconnect();
+ return false;
+ } else {
+ informListener(SvdrpEvent.LOGGED_IN, null);
+ }
+
+ return true;
+ }
+
+ /**
+ * Disconnect from SVDRP if connected
+ * @throws IOException on errors
+ */
+ protected void disconnect() throws IOException {
+ informListener(SvdrpEvent.DISCONNECTING, null);
+ if (socket != null && socket.isConnected()) {
+ socket.close();
+ socket = null;
+ }
+ informListener(SvdrpEvent.DISCONNECTED, null);
+ }
+
+ /**
+ * Sends one line to SVDRP
+ * @param line line of text
+ * @throws IOException on errors
+ */
+ protected void writeLine(final String line) throws IOException {
+
+ final String command = line + "\r\n";
+ final byte[] bytes = command.getBytes();
+ outputStream.write(bytes);
+ outputStream.flush();
+ }
+
+ /**
+ * Reads one line from SVDRP
+ * @return line read
+ * @throws IOException on errors
+ */
+ protected String readLine() throws IOException {
+
+ // handle not gzipped input
+ final ByteArrayOutputStream lineBytes = new ByteArrayOutputStream();
+
+ for(;;) {
+
+ // read next char
+ final int d = inputStream.read();
+ if (d < 0) {
+ break;
+ }
+ final char c = (char)d;
+
+ // skip '\r'
+ if (c == '\r') {
+ continue;
+ }
+
+ // with '\n' the line is completed
+ if (c == '\n') {
+ break;
+ }
+
+ // remember char
+ lineBytes.write(c);
+ }
+
+ return lineBytes.toString();
+ }
+
+ public void runCommand(final String command) throws SvdrpException {
+
+ try {
+
+ // reset cancel flag
+ abort = false;
+
+ // clear results
+ results.clear();
+
+ // connect
+ final boolean connected = connect();
+ if (!connected) {
+ return;
+ }
+
+ // send command
+ informListener(SvdrpEvent.COMMAND_SENDING, null);
+ writeLine(command);
+ informListener(SvdrpEvent.COMMAND_SENT, null);
+
+ // read first line
+ String line = readLine();
+ if (!line.startsWith("START")) {
+ throw new IOException("Answer not wellformed");
+ }
+
+ // read answer lines
+ for(;!abort;) {
+
+ // get next line
+ line = readLine();
+ if (line.length() == 0) {
+ break;
+ }
+
+ // last line?
+ if (line.startsWith("END")) {
+ break;
+ }
+
+ // error?
+ if (line.startsWith("!ERROR")) {
+ informListener(SvdrpEvent.ERROR, null);
+ break;
+ }
+
+ // delegate analysis
+ final Result result = parseAnswer(line);
+ if (result != null) {
+ results.add(result);
+ if (resultInfoEnabled) {
+ informListener(SvdrpEvent.RESULT_RECEIVED, result);
+ }
+ }
+
+ }
+
+ // disconnect
+ disconnect();
+
+ } catch (final IOException e) {
+ throw new SvdrpException(e);
+ } finally {
+ informListener(SvdrpEvent.FINISHED, null);
+ }
+ }
+
+ public void setResultInfoEnabled(final boolean resultInfoEnabled) {
+ this.resultInfoEnabled = resultInfoEnabled;
+ }
+
+ private void informListener(final SvdrpEvent event, final Result result) {
+ for(final SvdrpListener<Result> listener : listeners) {
+ listener.svdrpEvent(event, result);
+ }
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpEvent.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpEvent.java
new file mode 100644
index 0000000..7cb982d
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpEvent.java
@@ -0,0 +1,17 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+public enum SvdrpEvent {
+ CONNECTING,
+ CONNECTED,
+ CONNECT_ERROR,
+ LOGIN,
+ LOGGED_IN,
+ LOGIN_ERROR,
+ COMMAND_SENDING,
+ COMMAND_SENT,
+ RESULT_RECEIVED,
+ DISCONNECTING,
+ DISCONNECTED,
+ FINISHED,
+ ERROR
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpException.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpException.java
new file mode 100644
index 0000000..dfb8cd8
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpException.java
@@ -0,0 +1,22 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+/**
+ * Class for exception caused by SVDRP errors
+ * @author bju
+ *
+ */
+@SuppressWarnings("serial")
+public class SvdrpException extends Exception {
+
+ public SvdrpException(String text) {
+ super(text);
+ }
+
+ public SvdrpException(String text, Throwable cause) {
+ super(text, cause);
+ }
+
+ public SvdrpException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpListener.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpListener.java
new file mode 100644
index 0000000..b8f33ca
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/SvdrpListener.java
@@ -0,0 +1,7 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+
+public interface SvdrpListener<Result>{
+
+ void svdrpEvent(SvdrpEvent event, Result result);
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/TimerClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/TimerClient.java
new file mode 100644
index 0000000..dab239e
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/TimerClient.java
@@ -0,0 +1,50 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import de.bjusystems.androvdr.data.Channel;
+import de.bjusystems.androvdr.data.Timer;
+import de.bjusystems.androvdr.R;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class TimerClient extends SvdrpClient<Timer> {
+
+ /** channel names for timer */
+ Map<String, Channel> channels;
+
+ /**
+ * Constructor
+ * @param host host
+ * @param port port
+ * @param ssl use ssl
+ */
+ public TimerClient() {
+ super();
+ this.channels = new HashMap<String, Channel>();
+ }
+
+ /**
+ * Starts the EPG request
+ * @param parameter parameter for lste
+ */
+ @Override
+ public void run() throws SvdrpException {
+ runCommand("timers");
+ }
+
+ @Override
+ public Timer parseAnswer(final String line) {
+ return new Timer(line);
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return R.string.progress_timers_loading;
+ }
+}
+
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/svdrp/WakeupClient.java b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/WakeupClient.java
new file mode 100644
index 0000000..844ab8b
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/svdrp/WakeupClient.java
@@ -0,0 +1,51 @@
+package de.bjusystems.androvdr.utils.svdrp;
+
+import de.bjusystems.androvdr.data.WakeupState;
+
+/**
+ * Class for retrieving informations about the running program
+ * @author bju
+ *
+ */
+public class WakeupClient extends SvdrpClient<WakeupState> {
+
+ private WakeupState state;
+
+ /**
+ * Constructor
+ */
+ public WakeupClient() {
+ super();
+ }
+
+ /**
+ * Starts the wakeup request
+ */
+ @Override
+ public void run() throws SvdrpException {
+ runCommand("wake");
+ }
+
+ @Override
+ public WakeupState parseAnswer(final String line) {
+
+ if (line.startsWith("200")) {
+ state = WakeupState.OK;
+ } else if (line.startsWith("400")) {
+ state = WakeupState.FAILED;
+ } else {
+ state = WakeupState.ERROR;
+ }
+ return state;
+ }
+
+ @Override
+ public int getProgressTextId() {
+ return 0;
+ }
+
+ public WakeupState getState() {
+ return state;
+ }
+
+} \ No newline at end of file
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/wakeup/AsyncWakeupTask.java b/androvdr/src/de/bjusystems/androvdr/utils/wakeup/AsyncWakeupTask.java
new file mode 100644
index 0000000..7002140
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/wakeup/AsyncWakeupTask.java
@@ -0,0 +1,94 @@
+package de.bjusystems.androvdr.utils.wakeup;
+
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.os.AsyncTask;
+import android.widget.Toast;
+import de.bjusystems.androvdr.data.Preferences;
+import de.bjusystems.androvdr.data.WakeupState;
+import de.bjusystems.androvdr.utils.http.HttpHelper;
+import de.bjusystems.androvdr.utils.svdrp.WakeupClient;
+import de.bjusystems.androvdr.R;
+
+public class AsyncWakeupTask extends AsyncTask<Object, WakeupProgress, Void> {
+
+ /** Context */
+ private final Context context;
+ /** Progress dialog */
+ private ProgressDialog progressDialog;
+
+ public AsyncWakeupTask(final Context context) {
+ this.context = context;
+ }
+
+ @Override
+ protected Void doInBackground(final Object... params) {
+
+ // open progress dialog
+ publishProgress(WakeupProgress.WAKEUP_STARTED);
+
+ // Preferences
+ final Preferences prefs = Preferences.getPreferences();
+
+ boolean ok = false;
+ try {
+
+ // send request
+ if (prefs.isWakeupHttp()) {
+ // wakeup by http request
+ final HttpHelper httpHelper = new HttpHelper();
+ httpHelper.performGet(prefs.getWakeupUrl(), prefs.getWakeupUser(), prefs.getWakeupPassword(), null);
+ // request sent
+ ok = true;
+ } else {
+ // wakeup by SvdrpHelper
+ final WakeupClient client = new WakeupClient();
+ client.run();
+ ok = client.getState().equals(WakeupState.OK);
+ }
+
+ } catch (final Exception e) {
+ }
+
+ // close progress
+ publishProgress(WakeupProgress.WAKEUP_FINISHED);
+
+ if (ok) {
+ publishProgress(WakeupProgress.WAKEUP_OK);
+ } else {
+ publishProgress(WakeupProgress.WAKEUP_ERROR);
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(final WakeupProgress... values) {
+ super.onProgressUpdate(values);
+
+ switch (values[0]) {
+ case WAKEUP_STARTED:
+ final CharSequence message = context.getText(R.string.progress_wakeup_sending);
+ progressDialog = ProgressDialog.show(context, "", message);
+ break;
+ case WAKEUP_FINISHED:
+ progressDialog.dismiss();
+ break;
+ case WAKEUP_OK:
+ showToast(R.string.progress_wakeup_sent);
+ break;
+ case WAKEUP_ERROR:
+ showToast(R.string.progress_wakeup_error);
+ break;
+ }
+ }
+
+ private void showToast(final int textId) {
+
+ final CharSequence text = context.getText(textId);
+ final int duration = Toast.LENGTH_SHORT;
+ final Toast toast = Toast.makeText(context, text, duration);
+ toast.show();
+ }
+
+}
diff --git a/androvdr/src/de/bjusystems/androvdr/utils/wakeup/WakeupProgress.java b/androvdr/src/de/bjusystems/androvdr/utils/wakeup/WakeupProgress.java
new file mode 100644
index 0000000..c7f2630
--- /dev/null
+++ b/androvdr/src/de/bjusystems/androvdr/utils/wakeup/WakeupProgress.java
@@ -0,0 +1,8 @@
+package de.bjusystems.androvdr.utils.wakeup;
+
+public enum WakeupProgress {
+ WAKEUP_STARTED,
+ WAKEUP_OK,
+ WAKEUP_ERROR,
+ WAKEUP_FINISHED
+}