android/sdremote/AndroidManifest.xml                                           
            |    5 
 android/sdremote/res/layout/activity_selector.xml                              
            |   72 ++++
 android/sdremote/res/layout/activity_selector_sublayout_server.xml             
            |   20 +
 android/sdremote/res/values/strings.xml                                        
            |    3 
 android/sdremote/res/values/styles.xml                                         
            |    2 
 android/sdremote/src/org/libreoffice/impressremote/Launcher.java               
            |   23 -
 android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java       
            |  171 ++++++++++
 
android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
 |   33 +
 
android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
         |  101 ++++-
 sd/source/ui/remotecontrol/DiscoveryService.cxx                                
            |   14 
 10 files changed, 375 insertions(+), 69 deletions(-)

New commits:
commit 153c575361d59b856d916f516ca22f8b6096ad9f
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 14:59:51 2012 +0200

    Added deletion of stale detected servers, UI fixed.
    
    Change-Id: I I97a833b45e0c95a217004ae4a36e72a314d68d9f

diff --git a/android/sdremote/res/layout/activity_selector.xml 
b/android/sdremote/res/layout/activity_selector.xml
index 6f4cfa1..c5c734b 100644
--- a/android/sdremote/res/layout/activity_selector.xml
+++ b/android/sdremote/res/layout/activity_selector.xml
@@ -9,6 +9,13 @@
         android:layout_margin="10dip"
         android:orientation="vertical" >
 
+        <TextView
+            android:id="@+id/selector_label_none"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="@string/selector_noservers"
+            android:textAppearance="?android:attr/textAppearanceLarge" />
+
         <LinearLayout
             android:id="@+id/selector_container_bluetooth"
             android:layout_width="match_parent"
@@ -16,13 +23,6 @@
             android:orientation="vertical" >
 
             <TextView
-                android:id="@+id/selector_label_none"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/selector_noservers"
-                android:textAppearance="?android:attr/textAppearanceLarge" />
-
-            <TextView
                 android:id="@+id/selector_label_bluetooth"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java 
b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
index 132b6e4..201f41c 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -70,6 +70,9 @@ public class SelectorActivity extends Activity {
        protected void onPause() {
                // TODO Auto-generated method stub
                super.onPause();
+               if (mCommunicationService != null) {
+                       mCommunicationService.stopFindingServers();
+               }
                doUnbindService();
        }
 
@@ -89,6 +92,7 @@ public class SelectorActivity extends Activity {
                                IBinder aService) {
                        mCommunicationService = ((CommunicationService.CBinder) 
aService)
                                        .getService();
+                       mCommunicationService.startFindingServers();
                }
 
                @Override
@@ -160,9 +164,8 @@ public class SelectorActivity extends Activity {
                                .setVisibility((mNetworkServers.size() != 0) ? 
View.VISIBLE
                                                : View.GONE);
 
-               mNoServerLabel.setVisibility((mBluetoothServers.size() == 0)
-                               && (mNetworkServers.size() == 0) ? View.VISIBLE
-                               : View.GONE);
+               mNoServerLabel.setVisibility(((mBluetoothServers.size() == 0) 
&& (mNetworkServers
+                               .size() == 0)) ? View.VISIBLE : View.GONE);
        }
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index a278e9d..879c962 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -59,7 +59,6 @@ public class CommunicationService extends Service {
        @Override
        public void onCreate() {
                // TODO Create a notification (if configured).
-               mFinder.startFinding();
        }
 
        @Override
@@ -75,6 +74,14 @@ public class CommunicationService extends Service {
                return mFinder.getServerList();
        }
 
+       public void startFindingServers() {
+               mFinder.startFinding();
+       }
+
+       public void stopFindingServers() {
+               mFinder.stopFinding();
+       }
+
        /**
         * Connect to a specific server. This method cannot be called on the 
main
         * activity thread.
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index c47ce80..5b1b334 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -21,6 +21,8 @@ public class ServerFinder {
        private static final int PORT = 1598;
        private static final String CHARSET = "UTF-8";
 
+       private static final long SEARCH_INTERVAL = 1000 * 20;
+
        private DatagramSocket mSocket = null;
 
        private Thread mListenerThread = null;
@@ -40,9 +42,7 @@ public class ServerFinder {
                try {
                        String aCommand = null;
                        String aName = null;
-                       System.out.println("SF:listening for packet\n");
                        mSocket.receive(aPacket);
-                       System.out.println("SF:received packet\n");
                        int i;
                        for (i = 0; i < aBuffer.length; i++) {
                                if (aPacket.getData()[i] == '\n') {
@@ -95,18 +95,34 @@ public class ServerFinder {
                        mListenerThread = new Thread() {
                                @Override
                                public void run() {
+                                       long aTime = 0;
                                        try {
                                                mSocket = new DatagramSocket();
-                                               String aString = 
"LOREMOTE_SEARCH\n";
-                                               DatagramPacket aPacket = new 
DatagramPacket(
-                                                               
aString.getBytes(CHARSET),
-                                                               
aString.length(),
-                                                               
InetAddress.getByName("239.0.0.1"),
-                                                               PORT);
-                                               mSocket.send(aPacket);
-                                               System.out.println("SF:sent 
packet\n");
                                                mSocket.setSoTimeout(1000 * 10);
                                                while (!mFinishRequested) {
+                                                       if 
(System.currentTimeMillis() - aTime > SEARCH_INTERVAL) {
+                                                               String aString 
= "LOREMOTE_SEARCH\n";
+                                                               DatagramPacket 
aPacket = new DatagramPacket(
+                                                                               
aString.getBytes(CHARSET),
+                                                                               
aString.length(),
+                                                                               
InetAddress.getByName("239.0.0.1"),
+                                                                               
PORT);
+                                                               
mSocket.send(aPacket);
+                                                               aTime = 
System.currentTimeMillis();
+                                                               for (Server 
aServer : mServerList.values()) {
+                                                                       if 
(System.currentTimeMillis()
+                                                                               
        - aServer.getTimeDiscovered() > 60 * 1000) {
+                                                                               
mServerList.remove(aServer.getAddress());
+                                                                               
Intent aIntent = new Intent(
+                                                                               
                CommunicationService.MSG_SERVERLIST_CHANGED);
+                                                                               
LocalBroadcastManager.getInstance(
+                                                                               
                mContext)
+                                                                               
                .sendBroadcast(aIntent);
+
+                                                                       }
+                                                               }
+                                                       }
+
                                                        listenForServer();
                                                }
                                        } catch (SocketException e) {
@@ -135,6 +151,6 @@ public class ServerFinder {
        }
 
        public Server[] getServerList() {
-               return mServerList.entrySet().toArray(new 
Server[mServerList.size()]);
+               return mServerList.values().toArray(new 
Server[mServerList.size()]);
        }
 }
commit 678934331dfe4a49cd7ed0408db77738beb54ada
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 14:18:41 2012 +0200

    Detect duplicates when finding servers.
    
    Change-Id: Ie922e1f930df7987f77c153474aece2668250293

diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index c30f9c2..c47ce80 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -6,7 +6,7 @@ import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.SocketException;
-import java.util.Vector;
+import java.util.HashMap;
 
 import org.libreoffice.impressremote.communication.CommunicationService.Server;
 
@@ -27,7 +27,7 @@ public class ServerFinder {
 
        private boolean mFinishRequested = false;
 
-       private Vector<Server> mServerList = new Vector<Server>();
+       private HashMap<String, Server> mServerList = new HashMap<String, 
Server>();
 
        public ServerFinder(Context aContext) {
                mContext = aContext;
@@ -65,7 +65,7 @@ public class ServerFinder {
                        Server aServer = new 
Server(CommunicationService.Protocol.NETWORK,
                                        aPacket.getAddress().toString(), aName,
                                        System.currentTimeMillis());
-                       mServerList.add(aServer);
+                       mServerList.put(aServer.getAddress(), aServer);
 
                        //                      System.out.println("SF FOUND: 
IP="
                        //                                      + 
aPacket.getAddress().toString() + " HOSTNAME="
@@ -135,6 +135,6 @@ public class ServerFinder {
        }
 
        public Server[] getServerList() {
-               return mServerList.toArray(new Server[mServerList.size()]);
+               return mServerList.entrySet().toArray(new 
Server[mServerList.size()]);
        }
 }
commit 43b033d62440b5fb634c2553eaefa2c53c9d00a6
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 14:15:37 2012 +0200

    Fixed styling of server finder.
    
    Change-Id: I74186efe472f89463b597790d46be5523ce85b6f

diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java 
b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
index 4bed710..132b6e4 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -34,7 +34,9 @@ public class SelectorActivity extends Activity {
 
        private CommunicationService mCommunicationService;
 
+       private View mBluetoothContainer;
        private LinearLayout mBluetoothList;
+       private View mNetworkContainer;
        private LinearLayout mNetworkList;
        private TextView mNoServerLabel;
 
@@ -49,7 +51,9 @@ public class SelectorActivity extends Activity {
                
LocalBroadcastManager.getInstance(this).registerReceiver(mListener,
                                aFilter);
 
+               mBluetoothContainer = 
findViewById(R.id.selector_container_bluetooth);
                mBluetoothList = (LinearLayout) 
findViewById(R.id.selector_list_bluetooth);
+               mNetworkContainer = 
findViewById(R.id.selector_container_network);
                mNetworkList = (LinearLayout) 
findViewById(R.id.selector_list_network);
                mNoServerLabel = (TextView) 
findViewById(R.id.selector_label_none);
 
@@ -109,53 +113,56 @@ public class SelectorActivity extends Activity {
        private HashMap<Server, View> mNetworkServers = new HashMap<Server, 
View>();
 
        private void refreshLists() {
-               if (mCommunicationService == null)
-                       return;
+               if (mCommunicationService != null) {
 
-               Server[] aServers = mCommunicationService.getServers();
+                       Server[] aServers = mCommunicationService.getServers();
 
-               // Bluetooth -- Remove old
-               for (Entry<Server, View> aEntry : mBluetoothServers.entrySet()) 
{
-                       if (!Arrays.asList(aServers).contains(aEntry.getKey())) 
{
-                               mBluetoothServers.remove(aEntry.getKey());
-                               mBluetoothList.removeView(aEntry.getValue());
+                       // Bluetooth -- Remove old
+                       for (Entry<Server, View> aEntry : 
mBluetoothServers.entrySet()) {
+                               if 
(!Arrays.asList(aServers).contains(aEntry.getKey())) {
+                                       
mBluetoothServers.remove(aEntry.getKey());
+                                       
mBluetoothList.removeView(aEntry.getValue());
+                               }
                        }
-               }
-               // Network -- Remove old
-               for (Entry<Server, View> aEntry : mNetworkServers.entrySet()) {
-                       if (!Arrays.asList(aServers).contains(aEntry.getKey())) 
{
-                               mNetworkServers.remove(aEntry.getKey());
-                               mNetworkList.removeView(aEntry.getValue());
-                       }
-               }
-               // Add all new
-               for (Server aServer : aServers) {
-                       boolean aIsBluetooth = (aServer.getProtocol() == 
Protocol.BLUETOOTH);
-                       HashMap<Server, View> aMap = aIsBluetooth ? 
mBluetoothServers
-                                       : mNetworkServers;
-                       LinearLayout aLayout = aIsBluetooth ? mBluetoothList : 
mNetworkList;
-
-                       if (!aMap.containsValue(aServer)) {
-                               View aView = getLayoutInflater().inflate(
-                                               
R.layout.activity_selector_sublayout_server,
-                                               aLayout);
-                               TextView aText = (TextView) aView
-                                               
.findViewById(R.id.selector_sub_label);
-                               aText.setText(aServer.getName());
-                               aMap.put(aServer, aView);
+                       // Network -- Remove old
+                       for (Entry<Server, View> aEntry : 
mNetworkServers.entrySet()) {
+                               if 
(!Arrays.asList(aServers).contains(aEntry.getKey())) {
+                                       mNetworkServers.remove(aEntry.getKey());
+                                       
mNetworkList.removeView(aEntry.getValue());
+                               }
                        }
+                       // Add all new
+                       for (Server aServer : aServers) {
+                               boolean aIsBluetooth = (aServer.getProtocol() 
== Protocol.BLUETOOTH);
+                               HashMap<Server, View> aMap = aIsBluetooth ? 
mBluetoothServers
+                                               : mNetworkServers;
+                               LinearLayout aLayout = aIsBluetooth ? 
mBluetoothList
+                                               : mNetworkList;
+
+                               if (!aMap.containsValue(aServer)) {
+                                       View aView = getLayoutInflater()
+                                                       
.inflate(R.layout.activity_selector_sublayout_server,
+                                                                       
aLayout);
+                                       TextView aText = (TextView) aView
+                                                       
.findViewById(R.id.selector_sub_label);
+                                       aText.setText(aServer.getName());
+                                       aMap.put(aServer, aView);
+                               }
 
+                       }
                }
                // Hide as necessary
 
-               mBluetoothList.setVisibility((mBluetoothServers.size() != 0) ? 
View.VISIBLE
-                               : View.INVISIBLE);
-               mNetworkList.setVisibility((mNetworkServers.size() != 0) ? 
View.VISIBLE
-                               : View.INVISIBLE);
+               mBluetoothContainer
+                               .setVisibility((mBluetoothServers.size() != 0) 
? View.VISIBLE
+                                               : View.GONE);
+               mNetworkContainer
+                               .setVisibility((mNetworkServers.size() != 0) ? 
View.VISIBLE
+                                               : View.GONE);
 
                mNoServerLabel.setVisibility((mBluetoothServers.size() == 0)
                                && (mNetworkServers.size() == 0) ? View.VISIBLE
-                               : View.INVISIBLE);
+                               : View.GONE);
        }
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
commit b86db90c6796520b9c2e34b8284ce8613ba27476
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 14:08:40 2012 +0200

    Implemented Server selector.
    
    Change-Id: Ib6d0712c498e831a559df00d301ea2d4b851deed

diff --git a/android/sdremote/AndroidManifest.xml 
b/android/sdremote/AndroidManifest.xml
index 14f457b..cea2e14 100644
--- a/android/sdremote/AndroidManifest.xml
+++ b/android/sdremote/AndroidManifest.xml
@@ -13,12 +13,9 @@
     <application
         android:label="@string/app_name"
         android:theme="@style/Theme.ImpressRemote" >
-        <activity
-            android:name="TestClient"
-            android:label="" >
+        <activity android:name=".SelectorActivity" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
-
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
diff --git a/android/sdremote/res/layout/activity_selector.xml 
b/android/sdremote/res/layout/activity_selector.xml
new file mode 100644
index 0000000..6f4cfa1
--- /dev/null
+++ b/android/sdremote/res/layout/activity_selector.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android";
+    android:layout_width="match_parent"
+    android:layout_height="match_parent" >
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="10dip"
+        android:orientation="vertical" >
+
+        <LinearLayout
+            android:id="@+id/selector_container_bluetooth"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+
+            <TextView
+                android:id="@+id/selector_label_none"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/selector_noservers"
+                android:textAppearance="?android:attr/textAppearanceLarge" />
+
+            <TextView
+                android:id="@+id/selector_label_bluetooth"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/bluetooth"
+                android:textAppearance="?android:attr/textAppearanceLarge" />
+
+            <ImageView
+                android:id="@+id/selector_divider1"
+                android:layout_width="fill_parent"
+                android:layout_height="2dip"
+                android:src="@color/medium_grey" />
+
+            <LinearLayout
+                android:id="@+id/selector_list_bluetooth"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/selector_container_network"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+
+            <TextView
+                android:id="@+id/selector_label_network"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/wifi"
+                android:textAppearance="?android:attr/textAppearanceLarge" />
+
+            <ImageView
+                android:id="@+id/selector_divider1"
+                android:layout_width="fill_parent"
+                android:layout_height="2dip"
+                android:src="@color/medium_grey" />
+
+            <LinearLayout
+                android:id="@+id/selector_list_network"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" />
+        </LinearLayout>
+    </LinearLayout>
+
+</ScrollView>
\ No newline at end of file
diff --git a/android/sdremote/res/layout/activity_selector_sublayout_server.xml 
b/android/sdremote/res/layout/activity_selector_sublayout_server.xml
new file mode 100644
index 0000000..14bec23
--- /dev/null
+++ b/android/sdremote/res/layout/activity_selector_sublayout_server.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+
+    <ImageView
+        android:id="@+id/sub_divider"
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:src="@color/medium_grey" />
+
+    <TextView
+        android:id="@+id/selector_sub_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="10dip"
+        android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/sdremote/res/values/strings.xml 
b/android/sdremote/res/values/strings.xml
index ac51b86..0e14caa 100644
--- a/android/sdremote/res/values/strings.xml
+++ b/android/sdremote/res/values/strings.xml
@@ -20,5 +20,8 @@
     <string name="options_volumeswitching_descripton">Change slides using 
volume buttons</string>
     <string name="options_switchcomputer">Switch computer</string>
     <string name="blankscreen_return">Return to Slide</string>
+    <string name="bluetooth">Bluetooth</string>
+    <string name="wifi">WI-FI</string>
+    <string name="selector_noservers">Searching for computers…</string>
 
 </resources>
\ No newline at end of file
diff --git a/android/sdremote/res/values/styles.xml 
b/android/sdremote/res/values/styles.xml
index c95fb0c..e5a4651 100644
--- a/android/sdremote/res/values/styles.xml
+++ b/android/sdremote/res/values/styles.xml
@@ -7,6 +7,7 @@
     <color name="black">#000000</color>
     <color name="light_grey">#E8E9E8</color>
     <color name="medium_grey">#C1C2C1</color>
+    <color name="text_grey">#5E5F5F</color>
 
     <integer name="thumbnail_border_width">3</integer>
 
@@ -48,6 +49,7 @@
         <item 
name="android:actionDropDownStyle">@style/Theme.ImpressRemote.ActionBarMenu</item>
         <item name="android:windowBackground">@color/light_grey</item>
         <item 
name="android:homeAsUpIndicator">@drawable/up_indicator_white</item>
+        <item name="android:textColor">@color/text_grey</item>
     </style>
 
 </resources>
\ No newline at end of file
diff --git a/android/sdremote/src/org/libreoffice/impressremote/Launcher.java 
b/android/sdremote/src/org/libreoffice/impressremote/Launcher.java
deleted file mode 100644
index 8b27ebf..0000000
--- a/android/sdremote/src/org/libreoffice/impressremote/Launcher.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-package org.libreoffice.impressremote;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class Launcher extends Activity {
-       /** Called when the activity is first created. */
-       @Override
-       public void onCreate(Bundle savedInstanceState) {
-               super.onCreate(savedInstanceState);
-               setContentView(R.layout.main);
-       }
-
-}
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java 
b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
new file mode 100644
index 0000000..4bed710
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.libreoffice.impressremote;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+import org.libreoffice.impressremote.communication.CommunicationService;
+import 
org.libreoffice.impressremote.communication.CommunicationService.Protocol;
+import org.libreoffice.impressremote.communication.CommunicationService.Server;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class SelectorActivity extends Activity {
+
+       private CommunicationService mCommunicationService;
+
+       private LinearLayout mBluetoothList;
+       private LinearLayout mNetworkList;
+       private TextView mNoServerLabel;
+
+       /** Called when the activity is first created. */
+       @Override
+       public void onCreate(Bundle savedInstanceState) {
+               super.onCreate(savedInstanceState);
+               setContentView(R.layout.activity_selector);
+
+               IntentFilter aFilter = new IntentFilter(
+                               CommunicationService.MSG_SERVERLIST_CHANGED);
+               
LocalBroadcastManager.getInstance(this).registerReceiver(mListener,
+                               aFilter);
+
+               mBluetoothList = (LinearLayout) 
findViewById(R.id.selector_list_bluetooth);
+               mNetworkList = (LinearLayout) 
findViewById(R.id.selector_list_network);
+               mNoServerLabel = (TextView) 
findViewById(R.id.selector_label_none);
+
+               refreshLists();
+       }
+
+       @Override
+       protected void onResume() {
+               super.onResume();
+               doBindService();
+       }
+
+       @Override
+       protected void onPause() {
+               // TODO Auto-generated method stub
+               super.onPause();
+               doUnbindService();
+       }
+
+       void doBindService() {
+               Intent aIntent = new Intent(this, CommunicationService.class);
+               startService(aIntent);
+               bindService(aIntent, mConnection, Context.BIND_IMPORTANT);
+       }
+
+       void doUnbindService() {
+               unbindService(mConnection);
+       }
+
+       private ServiceConnection mConnection = new ServiceConnection() {
+               @Override
+               public void onServiceConnected(ComponentName aClassName,
+                               IBinder aService) {
+                       mCommunicationService = ((CommunicationService.CBinder) 
aService)
+                                       .getService();
+               }
+
+               @Override
+               public void onServiceDisconnected(ComponentName aClassName) {
+                       mCommunicationService = null;
+               }
+       };
+
+       private BroadcastReceiver mListener = new BroadcastReceiver() {
+
+               @Override
+               public void onReceive(Context aContext, Intent aIntent) {
+                       if (aIntent.getAction().equals(
+                                       
CommunicationService.MSG_SERVERLIST_CHANGED)) {
+                               refreshLists();
+                       }
+
+               }
+       };
+
+       private HashMap<Server, View> mBluetoothServers = new HashMap<Server, 
View>();
+       private HashMap<Server, View> mNetworkServers = new HashMap<Server, 
View>();
+
+       private void refreshLists() {
+               if (mCommunicationService == null)
+                       return;
+
+               Server[] aServers = mCommunicationService.getServers();
+
+               // Bluetooth -- Remove old
+               for (Entry<Server, View> aEntry : mBluetoothServers.entrySet()) 
{
+                       if (!Arrays.asList(aServers).contains(aEntry.getKey())) 
{
+                               mBluetoothServers.remove(aEntry.getKey());
+                               mBluetoothList.removeView(aEntry.getValue());
+                       }
+               }
+               // Network -- Remove old
+               for (Entry<Server, View> aEntry : mNetworkServers.entrySet()) {
+                       if (!Arrays.asList(aServers).contains(aEntry.getKey())) 
{
+                               mNetworkServers.remove(aEntry.getKey());
+                               mNetworkList.removeView(aEntry.getValue());
+                       }
+               }
+               // Add all new
+               for (Server aServer : aServers) {
+                       boolean aIsBluetooth = (aServer.getProtocol() == 
Protocol.BLUETOOTH);
+                       HashMap<Server, View> aMap = aIsBluetooth ? 
mBluetoothServers
+                                       : mNetworkServers;
+                       LinearLayout aLayout = aIsBluetooth ? mBluetoothList : 
mNetworkList;
+
+                       if (!aMap.containsValue(aServer)) {
+                               View aView = getLayoutInflater().inflate(
+                                               
R.layout.activity_selector_sublayout_server,
+                                               aLayout);
+                               TextView aText = (TextView) aView
+                                               
.findViewById(R.id.selector_sub_label);
+                               aText.setText(aServer.getName());
+                               aMap.put(aServer, aView);
+                       }
+
+               }
+               // Hide as necessary
+
+               mBluetoothList.setVisibility((mBluetoothServers.size() != 0) ? 
View.VISIBLE
+                               : View.INVISIBLE);
+               mNetworkList.setVisibility((mNetworkServers.size() != 0) ? 
View.VISIBLE
+                               : View.INVISIBLE);
+
+               mNoServerLabel.setVisibility((mBluetoothServers.size() == 0)
+                               && (mNetworkServers.size() == 0) ? View.VISIBLE
+                               : View.INVISIBLE);
+       }
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index 5ce7897..c30f9c2 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -135,7 +135,6 @@ public class ServerFinder {
        }
 
        public Server[] getServerList() {
-               return (Server[]) mServerList.toArray();
+               return mServerList.toArray(new Server[mServerList.size()]);
        }
-
 }
commit ec7c03774b84bc8cac6d253c51543bdfa78f4ab6
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 10:50:43 2012 +0200

    Hostname transfer implemented.
    
    Change-Id: I92f2a3c00215491b6f24d52b922a4e4f2c461637

diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index b8ba315..5ce7897 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -39,7 +39,7 @@ public class ServerFinder {
 
                try {
                        String aCommand = null;
-                       String aAddress = null;
+                       String aName = null;
                        System.out.println("SF:listening for packet\n");
                        mSocket.receive(aPacket);
                        System.out.println("SF:received packet\n");
@@ -53,11 +53,24 @@ public class ServerFinder {
                        if (i == aBuffer.length || 
!aCommand.equals("LOREMOTE_ADVERTISE")) {
                                return;
                        }
+                       for (int j = i; j < aBuffer.length; j++) {
+                               if (aPacket.getData()[i] == '\n') {
+                                       aName = new String(aPacket.getData(), i 
+ 1, j, CHARSET);
+                                       break;
+                               }
+                       }
+                       if (aName == null) {
+                               return;
+                       }
                        Server aServer = new 
Server(CommunicationService.Protocol.NETWORK,
-                                       aPacket.getAddress().toString(), 
"NONAME",
+                                       aPacket.getAddress().toString(), aName,
                                        System.currentTimeMillis());
                        mServerList.add(aServer);
 
+                       //                      System.out.println("SF FOUND: 
IP="
+                       //                                      + 
aPacket.getAddress().toString() + " HOSTNAME="
+                       //                                      + aName);
+
                        Intent aIntent = new Intent(
                                        
CommunicationService.MSG_SERVERLIST_CHANGED);
                        
LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx 
b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index bc514d7..f482158 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -60,15 +60,11 @@ DiscoveryService::~DiscoveryService()
 
 void DiscoveryService::replyTo( sockaddr_in& rAddr )
 {
-//     SocketAddr aLocalAddr;
-//     mSocket.getLocalAddr( aLocalAddr );
-//     OString aAddrString = OUStringToOString( aLocalAddr.getHostname(),
-//                                              RTL_TEXTENCODING_UTF8 );
-//     OStringBuffer aBuffer( "LOREMOTE_ADVERTISE\n" );
-//     aBuffer.append( aAddrString ).append( "\n" );
-//     mSocket.sendTo( rAddr, aBuffer.getStr(), aBuffer.getLength() );
-    OString aMessage("LOREMOTE_ADVERTISE\n");
-    sendto( mSocket, aMessage.getStr(), aMessage.getLength(), 0, (sockaddr*) 
&rAddr, sizeof(rAddr) );
+    OStringBuffer aBuffer("LOREMOTE_ADVERTISE\n");
+    aBuffer.append( OUStringToOString( osl::SocketAddr::getLocalHostname(),
+            RTL_TEXTENCODING_UTF8 ) ).append( "\n\n" );
+    sendto( mSocket, aBuffer.getStr(), aBuffer.getLength(), 0,
+            (sockaddr*) &rAddr, sizeof(rAddr) );
 }
 
 void DiscoveryService::execute()
commit 911b18d623fdfcfb70f47a6c3419d25446548d32
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 10:29:09 2012 +0200

    Server discovery broadcast.
    
    Change-Id: I10f0ac295ea14128908a87f4ef6a4c4524e76262

diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 4329460..a278e9d 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -36,13 +36,15 @@ public class CommunicationService extends Service {
        public static final int MSG_SLIDE_PREVIEW = 3;
        public static final int MSG_SLIDE_NOTES = 4;
 
+       public static final String MSG_SERVERLIST_CHANGED = 
"SERVERLIST_CHANGED";
+
        private Transmitter mTransmitter;
 
        private Client mClient;
 
        private Receiver mReceiver = new Receiver();
 
-       private ServerFinder mFinder = new ServerFinder();
+       private ServerFinder mFinder = new ServerFinder(this);
 
        public void setActivityMessenger(Messenger aActivityMessenger) {
                mReceiver.setActivityMessenger(aActivityMessenger);
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index 768eba5..b8ba315 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -10,8 +10,14 @@ import java.util.Vector;
 
 import org.libreoffice.impressremote.communication.CommunicationService.Server;
 
+import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
+
 public class ServerFinder {
 
+       private Context mContext;
+
        private static final int PORT = 1598;
        private static final String CHARSET = "UTF-8";
 
@@ -23,8 +29,8 @@ public class ServerFinder {
 
        private Vector<Server> mServerList = new Vector<Server>();
 
-       public ServerFinder() {
-
+       public ServerFinder(Context aContext) {
+               mContext = aContext;
        }
 
        private void listenForServer() {
@@ -52,6 +58,10 @@ public class ServerFinder {
                                        System.currentTimeMillis());
                        mServerList.add(aServer);
 
+                       Intent aIntent = new Intent(
+                                       
CommunicationService.MSG_SERVERLIST_CHANGED);
+                       
LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
+
                } catch (java.net.SocketTimeoutException e) {
                        // Ignore -- we want to timeout to enable checking 
whether we
                        // should stop listening periodically
commit 5fe349848b632679f536b2407d9ac73ee38e50f0
Author: Andrzej J.R. Hunt <andr...@ahunt.org>
Date:   Fri Aug 3 10:18:16 2012 +0200

    Server list caching.
    
    Change-Id: I8d4508ab54a0dc0240bb677e6a9dcfdf449c5094

diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index e1669cc..4329460 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -42,6 +42,8 @@ public class CommunicationService extends Service {
 
        private Receiver mReceiver = new Receiver();
 
+       private ServerFinder mFinder = new ServerFinder();
+
        public void setActivityMessenger(Messenger aActivityMessenger) {
                mReceiver.setActivityMessenger(aActivityMessenger);
        }
@@ -55,8 +57,7 @@ public class CommunicationService extends Service {
        @Override
        public void onCreate() {
                // TODO Create a notification (if configured).
-               ServerFinder aFinder = new ServerFinder();
-               aFinder.startFinding();
+               mFinder.startFinding();
        }
 
        @Override
@@ -68,6 +69,10 @@ public class CommunicationService extends Service {
                return mTransmitter;
        }
 
+       public Server[] getServers() {
+               return mFinder.getServerList();
+       }
+
        /**
         * Connect to a specific server. This method cannot be called on the 
main
         * activity thread.
@@ -102,10 +107,6 @@ public class CommunicationService extends Service {
 
        }
 
-       public Server[] getServers() {
-               return null;
-       }
-
        public void disconnect() {
                mClient.closeConnection();
        }
@@ -118,15 +119,18 @@ public class CommunicationService extends Service {
        /**
         * Class describing a remote server.
         */
-       public class Server {
+       public static class Server {
                private Protocol mProtocol;
                private String mAddress;
                private String mName;
+               private long mTimeDiscovered;
 
-               protected Server(Protocol aProtocol, String aAddress, String 
aName) {
+               protected Server(Protocol aProtocol, String aAddress, String 
aName,
+                               long aTimeDiscovered) {
                        mProtocol = aProtocol;
                        mAddress = aAddress;
                        mName = aName;
+                       mTimeDiscovered = aTimeDiscovered;
                }
 
                public Protocol getProtocol() {
@@ -146,6 +150,10 @@ public class CommunicationService extends Service {
                        return mName;
                }
 
+               public long getTimeDiscovered() {
+                       return mTimeDiscovered;
+               }
+
        }
 
 }
diff --git 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index b78a9a4..768eba5 100644
--- 
a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ 
b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -6,6 +6,9 @@ import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
 import java.net.SocketException;
+import java.util.Vector;
+
+import org.libreoffice.impressremote.communication.CommunicationService.Server;
 
 public class ServerFinder {
 
@@ -16,6 +19,10 @@ public class ServerFinder {
 
        private Thread mListenerThread = null;
 
+       private boolean mFinishRequested = false;
+
+       private Vector<Server> mServerList = new Vector<Server>();
+
        public ServerFinder() {
 
        }
@@ -40,17 +47,14 @@ public class ServerFinder {
                        if (i == aBuffer.length || 
!aCommand.equals("LOREMOTE_ADVERTISE")) {
                                return;
                        }
-                       System.out.println("SF: " + 
aPacket.getAddress().toString());
-
-                       //                      for (int j = i + 1; j < 
aBuffer.length; j++) {
-                       //                              if 
(aPacket.getData()[j] == '\n') {
-                       //                                      aAddress = new 
String(aPacket.getData(), i + 1, j, CHARSET);
-                       //                              }
-                       //                      }
-                       //
-                       //                      if (aAddress != null) {
-                       //                              
System.out.println("Address is :" + aAddress + "\n");
-                       //                      }
+                       Server aServer = new 
Server(CommunicationService.Protocol.NETWORK,
+                                       aPacket.getAddress().toString(), 
"NONAME",
+                                       System.currentTimeMillis());
+                       mServerList.add(aServer);
+
+               } catch (java.net.SocketTimeoutException e) {
+                       // Ignore -- we want to timeout to enable checking 
whether we
+                       // should stop listening periodically
                } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
@@ -62,6 +66,8 @@ public class ServerFinder {
                if (mSocket != null)
                        return;
 
+               mFinishRequested = false;
+
                if (mListenerThread == null) {
                        mListenerThread = new Thread() {
                                @Override
@@ -76,7 +82,8 @@ public class ServerFinder {
                                                                PORT);
                                                mSocket.send(aPacket);
                                                System.out.println("SF:sent 
packet\n");
-                                               while (true) {
+                                               mSocket.setSoTimeout(1000 * 10);
+                                               while (!mFinishRequested) {
                                                        listenForServer();
                                                }
                                        } catch (SocketException e) {
@@ -99,7 +106,13 @@ public class ServerFinder {
 
        public void stopFinding() {
                if (mListenerThread != null) {
-
+                       mFinishRequested = true;
+                       mListenerThread = null;
                }
        }
+
+       public Server[] getServerList() {
+               return (Server[]) mServerList.toArray();
+       }
+
 }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to