--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="gen"/>
+ <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
+ <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
+ <classpathentry kind="output" path="bin/classes"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>IPRemoteSwitch</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>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+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.7
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.duckdns.binomiant.ipremoteswitch"
+ android:versionCode="1"
+ android:versionName="1.0" xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <uses-sdk
+ android:minSdkVersion="22"
+ android:targetSdkVersion="22" />
+
+ <uses-permission android:name="android.permission.INTERNET"/>
+
+ <application
+ android:allowBackup="true"
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.Material" >
+ <activity
+ android:name=".MainActivity"
+ android:screenOrientation="portrait"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".PrefActivity"
+ android:label="@string/action_about" >
+ </activity>
+ <activity
+ android:name=".SettingsActivity"
+ android:label="@string/action_settings">
+ </activity>
+ </application>
+
+</manifest>
--- /dev/null
+# cache for current jar dependency. DO NOT EDIT.
+# format is <lastModified> <length> <SHA-1> <path>
+# Encoding is UTF-8
--- /dev/null
+#!/bin/bash
+#
+# Arguments: <on|off|status>
+# Returns: 1 for ON, 2 for off, 0 for tests and -1/255 on errors
+#
+
+# settings
+PING_INTERVAL=1
+SWITCH_COUNT=60
+ACK_COUNT=3
+
+GPIO_PIN=18
+cmd=
+host=
+state=
+
+CMD_ON=on
+CMD_OFF=off
+CMD_STAT=status
+
+ARGS=2
+TOOL_DIR=/home/pi
+SWITCH_LOCK=/tmp/.switch.lock
+
+ERROR=-1
+ON=1
+OFF=2
+
+# put output to log file for debugging purposes
+set -x
+exec &> /tmp/switch.log
+
+# loggs error and exits
+# param1 is the message
+# param2 is a flag for lock file deletion
+error()
+{
+ logger "error: $1"
+ if [ -z $2 ]; then
+ rm -f $SWITCH_LOCK
+ fi
+ exit $ERROR
+}
+
+# cleans up on exit
+cleanup()
+{
+ rm -f $SWITCH_LOCK
+}
+
+# setup GPIO interface
+gpio_init()
+{
+ # set direction, pull etc.
+ echo $GPIO_PIN > /sys/class/gpio/export
+ sleep 1
+ echo out > /sys/class/gpio/gpio$GPIO_PIN/direction
+ echo 1 > /sys/class/gpio/gpio$GPIO_PIN/active_low
+}
+
+# simulates a push button action via GPIO
+gpio_push()
+{
+ # set signal
+ echo 1 > /sys/class/gpio/gpio$GPIO_PIN/value
+ # wait a second
+ sleep 1
+ # set signal back
+ echo 0 > /sys/class/gpio/gpio$GPIO_PIN/value
+}
+
+# exits with actual state
+# param1 is a exit flag
+status()
+{
+ ping -i $PING_INTERVAL -c $ACK_COUNT $host &>/dev/null
+ local res=$?
+ case $res in
+ 0)
+ state=$ON
+ ;;
+ *)
+ state=$OFF
+ ;;
+ esac
+ if ! [ -z $1 ]; then
+ cleanup
+ exit $state
+ fi
+}
+
+# turns the machine on
+turn_on()
+{
+ status
+ if [ "$state" == "$OFF" ]; then
+ gpio_init
+ gpio_push
+ local counter=$(($SWITCH_COUNT/$ACK_COUNT))
+ while [ $counter -gt 0 ]; do
+ status
+ if [ "$state" == "$ON" ]; then
+ cleanup
+ exit $state
+ fi
+ let "counter-=1"
+ done
+ fi
+ cleanup
+ exit $state
+}
+
+# turns the machine on
+turn_off()
+{
+ status
+ if [ "$state" == "$ON" ]; then
+ gpio_init
+ gpio_push
+ local counter=$(($SWITCH_COUNT/$ACK_COUNT))
+ while [ $counter -gt 0 ]; do
+ status
+ if [ "$state" == "$OFF" ]; then
+ cleanup
+ exit $state
+ fi
+ let "counter-=1"
+ done
+ fi
+ cleanup
+ exit $state
+}
+
+# handles signals
+sig_handler()
+{
+ cleanup
+ exit
+}
+
+# test arguments
+if [ $# -ne $ARGS ]; then
+ error "invalid argument count $#" 0
+fi
+
+# test on parallel execution
+if [ -e $SWITCH_LOCK ]; then
+ error "lockfile exists" 0
+else
+ touch $SWITCH_LOCK
+fi
+
+# trap for signals
+trap 'sig_handler' SIGINT EXIT
+
+# execution
+cmd=$1
+host=$2
+case $cmd in
+ $CMD_ON)
+ turn_on
+ ;;
+ $CMD_OFF)
+ turn_off
+ ;;
+ $CMD_STAT)
+ status 1
+ ;;
+ *)
+ error "command $cmd not recognised"
+ ;;
+esac
--- /dev/null
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
--- /dev/null
+# 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 edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-22
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_enabled="false"
+ android:drawable="@drawable/ic_ab_back_holo_dark_am_inact" />
+
+ <item android:state_enabled="true"
+ android:drawable="@drawable/ic_ab_back_holo_dark_am_act" />
+
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_enabled="false"
+ android:drawable="@drawable/ic_ab_forward_holo_dark_am_inact" />
+
+ <item android:state_enabled="true"
+ android:drawable="@drawable/ic_ab_forward_holo_dark_am_act" />
+
+</selector>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_enabled="false"
+ android:drawable="@drawable/stat_notify_sync_inact" />
+
+ <item android:state_enabled="true"
+ android:drawable="@drawable/stat_notify_sync_act" />
+
+</selector>
\ No newline at end of file
--- /dev/null
+<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context="com.example.tabs.MainActivity" />
--- /dev/null
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ tools:context=".ConnectionFragment">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin">
+
+ <TextView
+ android:id="@+id/tabConnectionIntro"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_connection_intro"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <Button
+ android:id="@+id/buttonConnectionAction"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/tabConnectionIntro"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_button_connect" />
+
+ <TextView
+ android:id="@+id/textConnectionStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/tabConnectionIntro"
+ android:layout_below="@+id/buttonConnectionAction"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_status_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ProgressBar
+ android:id="@+id/progressConnection"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/textConnectionStatus"
+ android:layout_below="@+id/textConnectionStatus"
+ android:layout_marginTop="16dp" />
+
+ <TextView
+ android:id="@+id/connectionMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/progressConnection"
+ android:layout_toRightOf="@+id/textConnectionStatus"
+ android:text="@string/tab_status_disconnected"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ImageButton
+ android:id="@+id/toSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="250dp"
+ android:minWidth="48dp"
+ android:src="@drawable/selector_forward" />
+
+ </RelativeLayout>
+
+</ScrollView>
\ No newline at end of file
--- /dev/null
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ android:id="@+id/log_fragment"
+ tools:context=".LogFragment" >
+
+ <RelativeLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin" >
+
+ <TextView
+ android:id="@+id/logView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true" />
+
+ </RelativeLayout>
+
+</ScrollView>
+
+<!-- <fragment xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/log_fragment"
+ android:name="com.example.tabs.LogFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:layout="@layout/log"/>
+ -->
\ No newline at end of file
--- /dev/null
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ tools:context="net.ddns.ebelcrom.ipremoteswitch.MainActivity$PlaceholderFragment" >
+
+ <TextView
+ android:id="@+id/section_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</RelativeLayout>
--- /dev/null
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fillViewport="true"
+ tools:context=".SwitchFragment" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin" >
+
+ <TextView
+ android:id="@+id/tabSwitchIntro"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_switch_intro"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ToggleButton
+ android:id="@+id/buttonSwitchAction"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@+id/tabSwitchIntro"
+ android:layout_centerHorizontal="true"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_button_connect"
+ android:textOff="@string/tab_off"
+ android:textOn="@string/tab_on" />
+
+ <TextView
+ android:id="@+id/textSwitchStatus"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/tabSwitchIntro"
+ android:layout_below="@+id/buttonSwitchAction"
+ android:layout_marginTop="16dp"
+ android:text="@string/tab_status_text"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ProgressBar
+ android:id="@+id/progressSwitch"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignLeft="@+id/textSwitchStatus"
+ android:layout_below="@+id/textSwitchStatus"
+ android:layout_marginTop="16dp" />
+
+ <TextView
+ android:id="@+id/switchMessage"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignTop="@+id/progressSwitch"
+ android:layout_toRightOf="@+id/textSwitchStatus"
+ android:maxWidth="200dp"
+ android:text="@string/tab_stop_failure"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <ImageButton
+ android:id="@+id/toConnection"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:layout_marginTop="250dp"
+ android:minWidth="48dp"
+ android:src="@drawable/selector_back" />
+
+ <ImageButton
+ android:id="@+id/buttonRefresh"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_below="@+id/textSwitchStatus"
+ android:layout_marginTop="16dp"
+ android:minWidth="48dp"
+ android:src="@drawable/selector_sync" />
+ </RelativeLayout>
+
+</ScrollView>
\ No newline at end of file
--- /dev/null
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context="com.example.tabs.MainActivity" >
+
+ <item
+ android:id="@+id/action_settings"
+ android:orderInCategory="100"
+ android:showAsAction="never"
+ android:title="@string/action_settings"/>
+
+ <item
+ android:id="@+id/action_about"
+ android:orderInCategory="200"
+ android:showAsAction="never"
+ android:title="@string/action_about"/>
+
+</menu>
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme for API 11+. This theme completely replaces
+ AppBaseTheme from res/values/styles.xml on API 11+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light">
+ <!-- API 11 theme customizations can go here. -->
+ </style>
+
+</resources>
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme for API 14+. This theme completely replaces
+ AppBaseTheme from BOTH res/values/styles.xml and
+ res/values-v11/styles.xml on API 14+ devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+ <!-- API 14 theme customizations can go here. -->
+ </style>
+
+</resources>
--- /dev/null
+<resources>
+
+ <!--
+ Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively).
+ -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+
+</resources>
--- /dev/null
+<resources>
+
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="app_name">IPRemoteSwitch</string>
+
+ <!-- App actions -->
+ <string name="action_about">About</string>
+ <string name="action_settings">Settings</string>
+
+ <!-- Preferences -->
+ <string name="pref_gatew_sect">Gateway</string>
+ <string name="pref_gatew_title">Gateway WAN address</string>
+ <string name="pref_gatew_descr">WAN IP address or DNS name of your internet gateway
+ e.g. DSL router</string>
+ <string name="pref_gatew_default">example.com</string>
+ <string name="pref_gatew_port_title">Gateway WAN port</string>
+ <string name="pref_gatew_port_descr">WAN port of your internet gateway e.g. DSL
+ router</string>
+ <string name="pref_gatew_port_default">22</string>
+ <string name="pref_pc_sect">Remote PC</string>
+ <string name="pref_pc_title">Remote PC LAN address</string>
+ <string name="pref_pc_descr">LAN IP address or DNS name of your PC to be switched
+ remotely</string>
+ <string name="pref_pc_default">192.168.0.100</string>
+ <string name="pref_switch_sect">IP switch</string>
+ <string name="pref_usern_title">IP Switch username</string>
+ <string name="pref_usern_descr">Username of your IP switch account</string>
+ <string name="pref_usern_default">user</string>
+ <string name="pref_passwd_title">IP Switch password</string>
+ <string name="pref_passwd_descr">********</string>
+ <string name="pref_passwd_default">pass</string>
+
+ <!-- Connection tab -->
+ <string name="tab_connection">Connection</string>
+ <string name="tab_connection_intro">Connect to or disconnect from remote IP switch.</string>
+ <string name="tab_button_connect">Connect</string>
+ <string name="tab_button_disconnect">Disconnect</string>
+ <string name="tab_status_connecting">Connecting…</string>
+ <string name="tab_status_connected">Connected.</string>
+ <string name="tab_connection_failure">Connection failure. See log for more
+ information.</string>
+ <string name="tab_disconnection_failure">Disconnection failure. See log for more
+ information.</string>
+ <string name="tab_status_disconnecting">Disconnecting…</string>
+ <string name="tab_status_disconnected">Disconnected.</string>
+
+ <!-- Switch tab -->
+ <string name="tab_switch">Switch</string>
+ <string name="tab_switch_intro">Turn on/off remote PC.</string>
+ <string name="tab_status_starting">Starting…</string>
+ <string name="tab_status_started">Started.</string>
+ <string name="tab_start_failure">Start failure. See log for more information.</string>
+ <string name="tab_status_stopping">Stopping…</string>
+ <string name="tab_status_stopped">Stopped.</string>
+ <string name="tab_stop_failure">Stop failure. See log for more information.</string>
+ <string name="tab_refreshing">Refreshing…</string>
+ <string name="tab_refresh_failure">Refresh failure. See log for more information.</string>
+ <string name="tab_status_unknown">Unknown. Refresh status.</string>
+ <string name="tab_on">ON</string>
+ <string name="tab_off">OFF</string>
+
+ <!-- Log tab -->
+ <string name="tab_log">Log</string>
+ <string name="tab_status_text">Status:</string>
+ <string name="tab_unknown_text">Unknown</string>
+
+</resources>
\ No newline at end of file
--- /dev/null
+<resources>
+
+ <!--
+ Base application theme, dependent on API level. This theme is replaced
+ by AppBaseTheme from res/values-vXX/styles.xml on newer devices.
+ -->
+ <style name="AppBaseTheme" parent="android:Theme.Light">
+ <!--
+ Theme customizations available in newer API levels can go in
+ res/values-vXX/styles.xml, while customizations related to
+ backward-compatibility can go here.
+ -->
+ </style>
+
+ <!-- Application theme. -->
+ <style name="AppTheme" parent="AppBaseTheme">
+ <!-- All customizations that are NOT specific to a particular API-level can go here. -->
+ </style>
+
+</resources>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <PreferenceCategory
+ android:title="@string/pref_gatew_sect"
+ android:key="gateway_settings">
+
+ <EditTextPreference
+ android:defaultValue="@string/pref_gatew_default"
+ android:key="gateway_address"
+ android:title="@string/pref_gatew_title"
+ android:summary="@string/pref_gatew_descr"/>
+
+ <EditTextPreference
+ android:defaultValue="@string/pref_gatew_port_default"
+ android:key="gateway_port"
+ android:inputType="number"
+ android:title="@string/pref_gatew_port_title"
+ android:summary="@string/pref_gatew_port_descr"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/pref_pc_sect"
+ android:key="pc_settings">
+
+ <EditTextPreference
+ android:defaultValue="@string/pref_pc_default"
+ android:key="pc_address"
+ android:title="@string/pref_pc_title"
+ android:summary="@string/pref_pc_descr"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/pref_switch_sect"
+ android:key="switch_settings">
+
+ <EditTextPreference
+ android:defaultValue="@string/pref_usern_default"
+ android:key="switch_username"
+ android:title="@string/pref_usern_title"
+ android:summary="@string/pref_usern_descr"/>
+
+ <EditTextPreference
+ android:defaultValue="@string/pref_passwd_default"
+ android:key="switch_password"
+ android:inputType="textPassword"
+ android:title="@string/pref_passwd_title"
+ android:summary="@string/pref_passwd_descr"/>
+
+ </PreferenceCategory>
+
+</PreferenceScreen>
\ No newline at end of file
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Properties;
+
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+import android.app.ActionBar;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class ConnectionFragment extends Fragment {
+
+ private static final String ARG_SECTION_NUMBER = "section_number";
+
+ private static ConnectionFragment instance;
+
+ private View rootView;
+
+ private enum State {
+ DISCONNECTED, CONNECTING, CONNECTING_FAILURE, CONNECTED, DISCONNECTING,
+ DISCONNECTING_FAILURE
+ };
+
+ private State state;
+
+ private Session session;
+
+ private class Task extends AsyncTask<SettingsData, Integer, Session> {
+ private Context context;
+ private View view;
+ private JSch jsch;
+
+ public Task(Context context, View view) {
+ this.context = context;
+ this.view = view;
+ jsch = new JSch();
+ }
+
+ @Override
+ protected void onPreExecute() {
+ Button button = (Button) view.findViewById(R.id.buttonConnectionAction);
+ button.setEnabled(false);
+ }
+
+ @Override
+ protected Session doInBackground(SettingsData... params) {
+ try {
+ publishProgress(0);
+ if (State.DISCONNECTED == state) {
+ /* set state */
+ state = State.CONNECTING;
+ /* log */
+ ((MainActivity) context).log("Connecting to "
+ + params[0].gatewayAddress + ":" + params[0].gatewayPort);
+ /* open session */
+ InetAddress address = InetAddress.getByName(params[0].gatewayAddress);
+ session = jsch.getSession(params[0].username,
+ address.getHostAddress(), params[0].gatewayPort);
+ session.setPassword(params[0].password);
+ /* avoid asking for key confirmation */
+ Properties prop = new Properties();
+ prop.put("StrictHostKeyChecking", "no");
+ session.setConfig(prop);
+ session.connect();
+ /* set state */
+ state = State.CONNECTED;
+ /* update switch fragment */
+ ((MainActivity) context).enableSwitch(true, session);
+ /* log */
+ ((MainActivity) context).log("Connected");
+ return session;
+ } else if (State.CONNECTED == state) {
+ /* set state */
+ state = State.DISCONNECTING;
+ /* log */
+ ((MainActivity) context).log("Disconnecting from "
+ + params[0].gatewayAddress + ":" + params[0].gatewayPort);
+ session.disconnect();
+ /* set state */
+ state = State.DISCONNECTED;
+ /* update switch fragment */
+ ((MainActivity) context).enableSwitch(false, session);
+ /* log */
+ ((MainActivity) context).log("Disconnected");
+ return session = null;
+ }
+ } catch (UnknownHostException | JSchException e) {
+ if (State.CONNECTING == state) {
+ /* set state */
+ state = State.CONNECTING_FAILURE;
+ /* log */
+ ((MainActivity) context)
+ .log("Connection failure: " + e.getLocalizedMessage());
+ } else if (State.DISCONNECTING == state) {
+ /* set state */
+ state = State.DISCONNECTING_FAILURE;
+ /* log */
+ ((MainActivity) context)
+ .log("Disconnection failure: " + e.getLocalizedMessage());
+ }
+ } finally {
+ publishProgress(100);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onProgressUpdate(Integer... values) {
+ updateView();
+ if (100 == values[0]) {
+ if (State.CONNECTING_FAILURE == state) {
+ state = State.DISCONNECTED;
+ }
+ if (State.DISCONNECTING_FAILURE == state) {
+ state = State.CONNECTED;
+ }
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Session result) {
+ if (null != result) {
+ ImageButton toSwitch = (ImageButton) view.findViewById(R.id.toSwitch);
+ toSwitch.setEnabled(true);
+ } else if (null == result) {
+ ImageButton toSwitch = (ImageButton) view.findViewById(R.id.toSwitch);
+ toSwitch.setEnabled(false);
+ }
+ }
+ }
+
+ private Task task;
+
+ public static ConnectionFragment newInstance(int sectionNumber) {
+ if (null == instance) {
+ instance = new ConnectionFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_SECTION_NUMBER, sectionNumber);
+ instance.setArguments(args);
+ }
+ return instance;
+ }
+
+ public ConnectionFragment() {
+ state = State.DISCONNECTED;
+ }
+
+ public Session getSession() {
+ return session;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (null == rootView) {
+ rootView = inflater.inflate(R.layout.fragment_connection, container, false);
+ }
+ return rootView;
+ }
+
+ public void updateView() {
+ Button button = (Button) rootView.findViewById(R.id.buttonConnectionAction);
+ ProgressBar progress = (ProgressBar) rootView
+ .findViewById(R.id.progressConnection);
+ TextView status = (TextView) rootView.findViewById(R.id.connectionMessage);
+ ImageButton toSwitch = (ImageButton) rootView.findViewById(R.id.toSwitch);
+
+ if (State.CONNECTING == state || State.DISCONNECTING == state) {
+ progress.setVisibility(ProgressBar.VISIBLE);
+ button.setEnabled(false);
+ if (State.CONNECTING == state) {
+ button.setText(R.string.tab_button_connect);
+ status.setText(R.string.tab_status_connecting);
+ } else {
+ button.setText(R.string.tab_button_disconnect);
+ status.setText(R.string.tab_status_disconnecting);
+ }
+ toSwitch.setEnabled(false);
+ } else {
+ progress.setVisibility(ProgressBar.INVISIBLE);
+ button.setEnabled(true);
+ switch (state) {
+ case CONNECTED:
+ button.setText(R.string.tab_button_disconnect);
+ status.setText(R.string.tab_status_connected);
+ toSwitch.setEnabled(true);
+ break;
+ case CONNECTING_FAILURE:
+ button.setText(R.string.tab_button_connect);
+ status.setText(R.string.tab_connection_failure);
+ toSwitch.setEnabled(false);
+ break;
+ case DISCONNECTED:
+ button.setText(R.string.tab_button_connect);
+ status.setText(R.string.tab_status_disconnected);
+ toSwitch.setEnabled(false);
+ break;
+ case DISCONNECTING_FAILURE:
+ button.setText(R.string.tab_button_disconnect);
+ status.setText(R.string.tab_disconnection_failure);
+ toSwitch.setEnabled(false);
+ }
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ ImageButton toSwitch = (ImageButton) view.findViewById(R.id.toSwitch);
+ toSwitch.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ActionBar actionBar = getActivity().getActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ int pos = actionBar.getSelectedNavigationIndex();
+ actionBar.setSelectedNavigationItem(pos + 1);
+ }
+ });
+ toSwitch.setEnabled(false);
+
+ Button button = (Button) view.findViewById(R.id.buttonConnectionAction);
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ SettingsData settingsData = new SettingsData(
+ preferences.getString("gateway_address",
+ getString(R.string.pref_gatew_default)),
+ Integer.valueOf(preferences.getString("gateway_port",
+ getString(R.string.pref_gatew_port_default))).intValue(),
+ preferences.getString("pc_address",
+ getString(R.string.pref_pc_default)),
+ preferences.getString("switch_username",
+ getString(R.string.pref_usern_default)),
+ preferences.getString("switch_password",
+ getString(R.string.pref_passwd_default)));
+
+ task = new Task(getActivity(), rootView);
+ task.execute(settingsData);
+ }
+ });
+
+ updateView();
+ }
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import android.app.Fragment;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class LogFragment extends Fragment {
+
+ private static final String ARG_SECTION_NUMBER = "section_number";
+
+ private static LogFragment instance;
+ private View rootView;
+ private StringBuffer logBuffer;
+
+ private Handler messageHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ String aResponse = msg.getData().getString("log");
+ TextView logView = (TextView) rootView.findViewById(R.id.logView);
+ logView.append(aResponse);
+ }
+ };
+
+ public static LogFragment newInstance(int sectionNumber) {
+ if (null == instance) {
+ instance = new LogFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_SECTION_NUMBER, sectionNumber);
+ instance.setArguments(args);
+ }
+ return instance;
+ }
+
+ public LogFragment() {
+ logBuffer = new StringBuffer();
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (null == rootView) {
+ rootView = inflater.inflate(R.layout.fragment_log, container, false);
+ }
+ return rootView;
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ if (logBuffer.length() > 0) {
+ TextView logView = (TextView) rootView.findViewById(R.id.logView);
+ logView.append(logBuffer.toString());
+ logBuffer.delete(0, logBuffer.length());
+ }
+ }
+
+ public void log(String message) {
+ Date timestamp = new Date();
+ SimpleDateFormat dateFormat = new SimpleDateFormat("[HH:mm:ss.SSS] ");
+ String entry = dateFormat.format(timestamp) + message + "\n";
+
+ if (null != rootView) {
+ Message msgObj = Message.obtain();
+ Bundle b = new Bundle();
+ b.putString("log", entry);
+ msgObj.setData(b);
+ messageHandler.sendMessage(msgObj);
+ } else {
+ logBuffer.append(entry);
+ }
+ }
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import java.util.Locale;
+
+import com.jcraft.jsch.Session;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ActionBar;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.os.Bundle;
+import android.support.v4.view.ViewPager;
+import android.view.Menu;
+import android.view.MenuItem;
+
+@SuppressWarnings("deprecation")
+public class MainActivity extends Activity implements ActionBar.TabListener {
+
+ private static final int ABOUT_DIALOG = 1;
+
+ private SectionsPagerAdapter mSectionsPagerAdapter;
+
+ private ViewPager mViewPager;
+
+ private LogFragment mLogFragment;
+ private ConnectionFragment mConnectionFragment;
+ private SwitchFragment mSwitchFragment;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mConnectionFragment = ConnectionFragment.newInstance(1);
+ mSwitchFragment = SwitchFragment.newInstance(2);
+ mLogFragment = LogFragment.newInstance(3);
+
+ final ActionBar actionBar = getActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+
+ mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
+
+ mViewPager = (ViewPager) findViewById(R.id.pager);
+ mViewPager.setAdapter(mSectionsPagerAdapter);
+
+ mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ actionBar.setSelectedNavigationItem(position);
+ }
+ });
+
+ for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+ actionBar.addTab(actionBar.newTab()
+ .setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ int id = item.getItemId();
+ if (id == R.id.action_settings) {
+ startActivity(new Intent(this, SettingsActivity.class));
+ return true;
+ }
+ if (id == R.id.action_about) {
+ showDialog(ABOUT_DIALOG);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onTabSelected(ActionBar.Tab tab,
+ FragmentTransaction fragmentTransaction) {
+ mViewPager.setCurrentItem(tab.getPosition());
+ }
+
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab,
+ FragmentTransaction fragmentTransaction) {
+ }
+
+ @Override
+ public void onTabReselected(ActionBar.Tab tab,
+ FragmentTransaction fragmentTransaction) {
+ }
+
+ public class SectionsPagerAdapter extends FragmentPagerAdapter {
+
+ public SectionsPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ @Override
+ public Fragment getItem(int position) {
+ Fragment fragment = null;
+ switch (position) {
+ case 0:
+ fragment = ConnectionFragment.newInstance(position + 1);
+ break;
+ case 1:
+ fragment = SwitchFragment.newInstance(position + 1);
+ break;
+ case 2:
+ fragment = LogFragment.newInstance(position + 1);
+ break;
+ }
+ return fragment;
+ }
+
+ @Override
+ public int getCount() {
+ return 3;
+ }
+
+ @Override
+ public CharSequence getPageTitle(int position) {
+ Locale l = Locale.getDefault();
+ switch (position) {
+ case 0:
+ return getString(R.string.tab_connection).toUpperCase(l);
+ case 1:
+ return getString(R.string.tab_switch).toUpperCase(l);
+ case 2:
+ return getString(R.string.tab_log).toUpperCase(l);
+ }
+ return null;
+ }
+ }
+
+ public Dialog onCreateDialog(int id) {
+ Dialog dialog = null;
+
+ switch (id) {
+ case ABOUT_DIALOG:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("About");
+ builder.setMessage("IPRemoteSwitch v1.0\n©2016 ebelcrom");
+ builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
+ builder.setCancelable(false);
+ dialog = builder.create();
+ break;
+ }
+ return dialog;
+ }
+
+ public void log(String message) {
+ mLogFragment.log(message);
+ }
+
+ public void enableSwitch(boolean enable, Session session) {
+ mSwitchFragment.enableSwitch(enable, session);
+ }
+
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import java.util.List;
+
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceManager;
+
+public class SettingsActivity extends PreferenceActivity {
+ private static Preference.OnPreferenceChangeListener bindSummaryListener = new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object value) {
+ /* set summary text to preference value */
+ String stringValue = value.toString();
+ preference.setSummary(stringValue);
+ return true;
+ }
+ };
+
+ @Override
+ public void onBuildHeaders(List<Header> target) {
+ /* set content of this activity to the preference fragment */
+ getFragmentManager().beginTransaction()
+ .replace(android.R.id.content, new SettingsFragment()).commit();
+ }
+
+ @Override
+ protected boolean isValidFragment(String fragmentName) {
+ /* return the only preferences fragment available */
+ return SettingsFragment.class.getName().equals(fragmentName);
+ }
+
+ public void bindSummary(Preference preference) {
+ /* set a listener for changes on values except password */
+ if (!"switch_password".equals(preference.getKey())) {
+ preference.setOnPreferenceChangeListener(bindSummaryListener);
+ }
+
+ /* trigger listener immediately once except password */
+ if (!"switch_password".equals(preference.getKey())) {
+ bindSummaryListener.onPreferenceChange(preference,
+ PreferenceManager.getDefaultSharedPreferences(preference.getContext())
+ .getString(preference.getKey(), ""));
+ }
+ }
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+public class SettingsData {
+ public String gatewayAddress;
+ public int gatewayPort;
+ public String pcAddress;
+ public String username;
+ public String password;
+
+ public SettingsData(String gatewayAddress, int gatewayPort, String pcAddress,
+ String username, String password) {
+ this.gatewayAddress = gatewayAddress;
+ this.gatewayPort = gatewayPort;
+ this.pcAddress = pcAddress;
+ this.username = username;
+ this.password = password;
+ }
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+public class SettingsFragment extends PreferenceFragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ /* create preferences from resource */
+ addPreferencesFromResource(R.xml.fragment_preference);
+ /* bind summary to values */
+ Activity superActivity = getActivity();
+ SettingsActivity activity;
+ if (superActivity instanceof SettingsActivity) {
+ activity = (SettingsActivity) superActivity;
+ activity.bindSummary(findPreference("gateway_address"));
+ activity.bindSummary(findPreference("gateway_port"));
+ activity.bindSummary(findPreference("pc_address"));
+ activity.bindSummary(findPreference("switch_username"));
+ activity.bindSummary(findPreference("switch_password"));
+ }
+ }
+}
--- /dev/null
+package org.duckdns.binomiant.ipremoteswitch;
+
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSchException;
+import com.jcraft.jsch.Session;
+
+import android.app.ActionBar;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.PreferenceManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnClickListener;
+import android.widget.ImageButton;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+public class SwitchFragment extends Fragment {
+ private static final String ARG_SECTION_NUMBER = "section_number";
+
+ private static SwitchFragment instance;
+
+ private View rootView;
+
+ private enum State {
+ INACTIVE, OFF, SWITCHING_ON, SWITCHING_ON_FAILURE, ON, SWITCHING_OFF,
+ SWITCHING_OFF_FAILURE, REFRESHING, REFRESHING_FAILURE, UNKNOWN
+ };
+
+ private State state;
+
+ private Session session;
+
+ private final static String CMD_SCRIPT = "/home/pi/switch.sh ";
+ private final static String CMD_STATUS = "status ";
+ private final static String CMD_ON = "on ";
+ private final static String CMD_OFF = "off ";
+
+ private final static int RESULT_UNKNOWN = -2;
+ private final static int RESULT_ERROR = -1;
+ private final static int RESULT_ON = 1;
+ private final static int RESULT_OFF = 2;
+
+ private Handler messageHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ updateView();
+ }
+ };
+
+ private class Task extends AsyncTask<SettingsData, Void, Void> {
+ private Context context;
+
+ public Task(Context context, View view) {
+ this.context = context;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ /* set state */
+ if (State.OFF == state) {
+ state = State.SWITCHING_ON;
+ } else {
+ state = State.SWITCHING_OFF;
+ }
+ updateView();
+ }
+
+ @Override
+ protected Void doInBackground(SettingsData... params) {
+ int result = RESULT_UNKNOWN;
+ try {
+ if (State.SWITCHING_ON == state) {
+ /* log */
+ ((MainActivity) context).log("Switching on " + params[0].pcAddress);
+ /* set channel params */
+ ChannelExec channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(CMD_SCRIPT + CMD_ON + params[0].pcAddress);
+ channel.setInputStream(null);
+ channel.setOutputStream(null);
+ channel.setErrStream(null);
+ /* send command */
+ channel.connect();
+ /* wait on command termination */
+ while (true) {
+ if (channel.isClosed()) {
+ result = channel.getExitStatus();
+ break;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ /* do nothing */
+ }
+ }
+ /* close channel */
+ channel.disconnect();
+ /* set state */
+ switch (result) {
+ case RESULT_ON:
+ state = State.ON;
+ /* log */
+ ((MainActivity) context)
+ .log("Switched on " + params[0].pcAddress);
+ break;
+ case RESULT_OFF:
+ case RESULT_ERROR:
+ state = State.SWITCHING_ON_FAILURE;
+ /* log */
+ ((MainActivity) context).log(
+ "Switching on " + params[0].pcAddress + " failed");
+ break;
+ }
+ } else if (State.SWITCHING_OFF == state) {
+ /* log */
+ ((MainActivity) context).log("Switching off " + params[0].pcAddress);
+ /* set channel params */
+ ChannelExec channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(CMD_SCRIPT + CMD_OFF + params[0].pcAddress);
+ channel.setInputStream(null);
+ channel.setOutputStream(null);
+ channel.setErrStream(null);
+ /* send command */
+ channel.connect();
+ /* wait on command termination */
+ while (true) {
+ if (channel.isClosed()) {
+ result = channel.getExitStatus();
+ break;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ /* do nothing */
+ }
+ }
+ /* close channel */
+ channel.disconnect();
+ /* set state */
+ switch (result) {
+ case RESULT_OFF:
+ state = State.OFF;
+ /* log */
+ ((MainActivity) context)
+ .log("Switched off " + params[0].pcAddress);
+ break;
+ case RESULT_ON:
+ case RESULT_ERROR:
+ state = State.SWITCHING_OFF_FAILURE;
+ /* log */
+ ((MainActivity) context).log(
+ "Switching off " + params[0].pcAddress + " failed");
+ break;
+ }
+ }
+ } catch (JSchException e) {
+ if (State.SWITCHING_ON == state) {
+ /* set state */
+ state = State.SWITCHING_ON_FAILURE;
+ /* log */
+ ((MainActivity) context)
+ .log("Switching on failure: " + e.getLocalizedMessage());
+ } else if (State.SWITCHING_OFF == state) {
+ /* set state */
+ state = State.SWITCHING_OFF_FAILURE;
+ /* log */
+ ((MainActivity) context)
+ .log("Switching off failure: " + e.getLocalizedMessage());
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ updateView();
+ if (State.SWITCHING_ON_FAILURE == state) {
+ /* set state */
+ state = State.OFF;
+ }
+ if (State.SWITCHING_OFF_FAILURE == state) {
+ /* set state */
+ state = State.ON;
+ }
+ }
+ }
+
+ private Task task;
+
+ private class RefreshTask extends AsyncTask<SettingsData, Void, Void> {
+ private Context context;
+
+ public RefreshTask(Context context, View view) {
+ this.context = context;
+ }
+
+ @Override
+ protected void onPreExecute() {
+ /* set state */
+ state = State.REFRESHING;
+ updateView();
+ }
+
+ @Override
+ protected Void doInBackground(SettingsData... params) {
+ int result = RESULT_UNKNOWN;
+ try {
+ /* log */
+ ((MainActivity) context).log("Refresh state of " + params[0].pcAddress);
+ /* set channel params */
+ ChannelExec channel = (ChannelExec) session.openChannel("exec");
+ channel.setCommand(CMD_SCRIPT + CMD_STATUS + params[0].pcAddress);
+ channel.setInputStream(null);
+ channel.setOutputStream(null);
+ channel.setErrStream(null);
+ /* send command */
+ channel.connect();
+ /* wait on command termination */
+ while (true) {
+ if (channel.isClosed()) {
+ result = channel.getExitStatus();
+ break;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ /* do nothing */
+ }
+ }
+ /* close channel */
+ channel.disconnect();
+ /* set state */
+ switch (result) {
+ case RESULT_OFF:
+ state = State.OFF;
+ /* log */
+ ((MainActivity) context)
+ .log("State of is off");
+ break;
+ case RESULT_ON:
+ state = State.ON;
+ /* log */
+ ((MainActivity) context)
+ .log("State of is on");
+ break;
+ case RESULT_ERROR:
+ state = State.REFRESHING_FAILURE;
+ /* log */
+ ((MainActivity) context)
+ .log("State of unknown");
+ break;
+ }
+ } catch (JSchException e) {
+ /* log */
+ ((MainActivity) context)
+ .log("Refreshing failure: " + e.getLocalizedMessage());
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ updateView();
+ if (State.SWITCHING_ON_FAILURE == state) {
+ /* set state */
+ state = State.OFF;
+ }
+ if (State.SWITCHING_OFF_FAILURE == state) {
+ /* set state */
+ state = State.ON;
+ }
+ }
+ }
+
+ private RefreshTask refreshTask;
+
+ public static SwitchFragment newInstance(int sectionNumber) {
+ if (null == instance) {
+ instance = new SwitchFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_SECTION_NUMBER, sectionNumber);
+ instance.setArguments(args);
+ }
+ return instance;
+ }
+
+ public SwitchFragment() {
+ state = State.INACTIVE;
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ if (null == rootView) {
+ rootView = inflater.inflate(R.layout.fragment_switch, container, false);
+ }
+ return rootView;
+ }
+
+ public void updateView() {
+ ToggleButton button = (ToggleButton) rootView
+ .findViewById(R.id.buttonSwitchAction);
+ ProgressBar progress = (ProgressBar) rootView.findViewById(R.id.progressSwitch);
+ TextView status = (TextView) rootView.findViewById(R.id.switchMessage);
+ ImageButton toConnection = (ImageButton) rootView.findViewById(R.id.toConnection);
+ ImageButton buttonRefresh = (ImageButton) rootView
+ .findViewById(R.id.buttonRefresh);
+
+ if (State.SWITCHING_ON == state || State.SWITCHING_OFF == state) {
+ progress.setVisibility(ProgressBar.VISIBLE);
+ button.setEnabled(false);
+ toConnection.setEnabled(true);
+ buttonRefresh.setEnabled(false);
+ if (State.SWITCHING_ON == state) {
+ button.setChecked(true);
+ status.setText(R.string.tab_status_starting);
+ } else {
+ button.setChecked(false);
+ status.setText(R.string.tab_status_stopping);
+ }
+ } else if (State.INACTIVE == state) {
+ progress.setVisibility(ProgressBar.INVISIBLE);
+ button.setEnabled(false);
+ button.setChecked(false);
+ status.setText(R.string.tab_status_unknown);
+ toConnection.setEnabled(false);
+ buttonRefresh.setEnabled(false);
+ } else if (State.UNKNOWN == state) {
+ progress.setVisibility(ProgressBar.INVISIBLE);
+ button.setEnabled(false);
+ button.setChecked(false);
+ status.setText(R.string.tab_status_unknown);
+ toConnection.setEnabled(true);
+ buttonRefresh.setEnabled(true);
+ } else if (State.REFRESHING == state) {
+ progress.setVisibility(ProgressBar.VISIBLE);
+ button.setEnabled(false);
+ button.setChecked(false);
+ status.setText(R.string.tab_refreshing);
+ toConnection.setEnabled(true);
+ buttonRefresh.setEnabled(false);
+ } else {
+ progress.setVisibility(ProgressBar.INVISIBLE);
+ button.setEnabled(true);
+ toConnection.setEnabled(true);
+ buttonRefresh.setEnabled(true);
+ switch (state) {
+ case ON:
+ button.setChecked(true);
+ status.setText(R.string.tab_status_started);
+ break;
+ case SWITCHING_ON_FAILURE:
+ button.setChecked(false);
+ status.setText(R.string.tab_start_failure);
+ break;
+ case OFF:
+ button.setChecked(false);
+ status.setText(R.string.tab_status_stopped);
+ break;
+ case SWITCHING_OFF_FAILURE:
+ button.setChecked(true);
+ status.setText(R.string.tab_stop_failure);
+ break;
+ case REFRESHING_FAILURE:
+ status.setText(R.string.tab_refresh_failure);
+ }
+ }
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ ImageButton toConnection = (ImageButton) view.findViewById(R.id.toConnection);
+ toConnection.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ActionBar actionBar = getActivity().getActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ int pos = actionBar.getSelectedNavigationIndex();
+ actionBar.setSelectedNavigationItem(pos - 1);
+ }
+ });
+
+ ToggleButton button = (ToggleButton) view.findViewById(R.id.buttonSwitchAction);
+ button.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ SettingsData settingsData = new SettingsData(
+ preferences.getString("gateway_address",
+ getString(R.string.pref_gatew_default)),
+ Integer.valueOf(preferences.getString("gateway_port",
+ getString(R.string.pref_gatew_port_default))).intValue(),
+ preferences.getString("pc_address",
+ getString(R.string.pref_pc_default)),
+ preferences.getString("switch_username",
+ getString(R.string.pref_usern_default)),
+ preferences.getString("switch_password",
+ getString(R.string.pref_passwd_default)));
+
+ task = new Task(getActivity(), rootView);
+ task.execute(settingsData);
+ }
+ });
+
+ ImageButton refreshButton = (ImageButton) view.findViewById(R.id.buttonRefresh);
+ refreshButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ SharedPreferences preferences = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ SettingsData settingsData = new SettingsData(
+ preferences.getString("gateway_address",
+ getString(R.string.pref_gatew_default)),
+ Integer.valueOf(preferences.getString("gateway_port",
+ getString(R.string.pref_gatew_port_default))).intValue(),
+ preferences.getString("pc_address",
+ getString(R.string.pref_pc_default)),
+ preferences.getString("switch_username",
+ getString(R.string.pref_usern_default)),
+ preferences.getString("switch_password",
+ getString(R.string.pref_passwd_default)));
+
+ refreshTask = new RefreshTask(getActivity(), rootView);
+ refreshTask.execute(settingsData);
+ }
+ });
+
+ updateView();
+ }
+
+ public void enableSwitch(boolean enable, Session session) {
+ this.session = session;
+ if (enable)
+ state = State.UNKNOWN;
+ else
+ state = State.INACTIVE;
+
+ if (null != rootView) {
+ Message msgObj = Message.obtain();
+ Bundle b = new Bundle();
+ messageHandler.sendMessage(msgObj);
+ }
+ }
+
+}