diff options
Diffstat (limited to 'androvdr')
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 Binary files differnew file mode 100644 index 0000000..8074c4c --- /dev/null +++ b/androvdr/res/drawable-hdpi/icon.png diff --git a/androvdr/res/drawable-ldpi/icon.png b/androvdr/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..1095584 --- /dev/null +++ b/androvdr/res/drawable-ldpi/icon.png diff --git a/androvdr/res/drawable-mdpi/icon.png b/androvdr/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..a07c69f --- /dev/null +++ b/androvdr/res/drawable-mdpi/icon.png diff --git a/androvdr/res/drawable/channels.gif b/androvdr/res/drawable/channels.gif Binary files differnew file mode 100644 index 0000000..f9874ff --- /dev/null +++ b/androvdr/res/drawable/channels.gif diff --git a/androvdr/res/drawable/settings.gif b/androvdr/res/drawable/settings.gif Binary files differnew file mode 100644 index 0000000..5d36e7c --- /dev/null +++ b/androvdr/res/drawable/settings.gif diff --git a/androvdr/res/drawable/timer_active.png b/androvdr/res/drawable/timer_active.png Binary files differnew file mode 100644 index 0000000..7b67f94 --- /dev/null +++ b/androvdr/res/drawable/timer_active.png diff --git a/androvdr/res/drawable/timer_inactive.png b/androvdr/res/drawable/timer_inactive.png Binary files differnew file mode 100644 index 0000000..c7a75c4 --- /dev/null +++ b/androvdr/res/drawable/timer_inactive.png diff --git a/androvdr/res/drawable/timer_none.png b/androvdr/res/drawable/timer_none.png Binary files differnew file mode 100644 index 0000000..dbf17ad --- /dev/null +++ b/androvdr/res/drawable/timer_none.png diff --git a/androvdr/res/drawable/timer_recording.png b/androvdr/res/drawable/timer_recording.png Binary files differnew file mode 100644 index 0000000..2031530 --- /dev/null +++ b/androvdr/res/drawable/timer_recording.png diff --git a/androvdr/res/drawable/timers.gif b/androvdr/res/drawable/timers.gif Binary files differnew file mode 100644 index 0000000..3577dab --- /dev/null +++ b/androvdr/res/drawable/timers.gif diff --git a/androvdr/res/drawable/vdr_logo.jpg b/androvdr/res/drawable/vdr_logo.jpg Binary files differnew file mode 100644 index 0000000..bba3a1f --- /dev/null +++ b/androvdr/res/drawable/vdr_logo.jpg diff --git a/androvdr/res/drawable/whatson.gif b/androvdr/res/drawable/whatson.gif Binary files differnew file mode 100644 index 0000000..5a35904 --- /dev/null +++ b/androvdr/res/drawable/whatson.gif 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 +} |