[Libreoffice-commits] .: 81 commits - android/sdremote config_host.mk.in sd/CppunitTest_sd_uimpress.mk sd/inc sd/Library_sd.mk sd/source

Michael Meeks michael at kemper.freedesktop.org
Mon Aug 6 02:26:20 PDT 2012


 android/sdremote/.classpath                                                                |    8 
 android/sdremote/.project                                                                  |   33 
 android/sdremote/.settings/org.eclipse.jdt.core.prefs                                      |   11 
 android/sdremote/AndroidManifest.xml                                                       |   37 
 android/sdremote/ant.properties                                                            |   17 
 android/sdremote/build.xml                                                                 |   83 +
 android/sdremote/proguard-project.txt                                                      |   20 
 android/sdremote/project.properties                                                        |   14 
 android/sdremote/res/drawable-hdpi/handle_default.9.png                                    |binary
 android/sdremote/res/drawable-hdpi/handle_light.9.png                                      |binary
 android/sdremote/res/drawable-hdpi/ic_action_search.png                                    |binary
 android/sdremote/res/drawable-hdpi/ic_launcher.png                                         |binary
 android/sdremote/res/drawable-ldpi/handle_default.9.png                                    |binary
 android/sdremote/res/drawable-ldpi/handle_light.9.png                                      |binary
 android/sdremote/res/drawable-ldpi/ic_launcher.png                                         |binary
 android/sdremote/res/drawable-mdpi/handle_default.9.png                                    |binary
 android/sdremote/res/drawable-mdpi/handle_light.9.png                                      |binary
 android/sdremote/res/drawable-mdpi/ic_action_search.png                                    |binary
 android/sdremote/res/drawable-mdpi/ic_launcher.png                                         |binary
 android/sdremote/res/drawable-xhdpi/handle_default.9.png                                   |binary
 android/sdremote/res/drawable-xhdpi/handle_light.9.png                                     |binary
 android/sdremote/res/drawable-xhdpi/ic_action_search.png                                   |binary
 android/sdremote/res/drawable/actionbar_icon_overflow.png                                  |binary
 android/sdremote/res/drawable/actionbar_icon_thumbs.png                                    |binary
 android/sdremote/res/drawable/actionbar_none.png                                           |binary
 android/sdremote/res/drawable/actionbar_pressed.png                                        |binary
 android/sdremote/res/drawable/actionbar_selected.png                                       |binary
 android/sdremote/res/drawable/actionbar_thumbs.xml                                         |    9 
 android/sdremote/res/drawable/actionbar_toggle.xml                                         |    8 
 android/sdremote/res/drawable/clockbar_clock.xml                                           |   11 
 android/sdremote/res/drawable/clockbar_countdown.xml                                       |   11 
 android/sdremote/res/drawable/clockbar_icon_clock.png                                      |binary
 android/sdremote/res/drawable/clockbar_icon_countdown.png                                  |binary
 android/sdremote/res/drawable/clockbar_icon_stopwatch.png                                  |binary
 android/sdremote/res/drawable/clockbar_stopwatch.xml                                       |   11 
 android/sdremote/res/drawable/empty.png                                                    |binary
 android/sdremote/res/drawable/handle.xml                                                   |    9 
 android/sdremote/res/drawable/icon_options.png                                             |binary
 android/sdremote/res/drawable/rectangle_black.xml                                          |   11 
 android/sdremote/res/drawable/testimage.png                                                |binary
 android/sdremote/res/drawable/up_indicator_white.png                                       |binary
 android/sdremote/res/layout/activity_presentation.xml                                      |    7 
 android/sdremote/res/layout/activity_selector.xml                                          |   72 +
 android/sdremote/res/layout/activity_selector_sublayout_server.xml                         |   20 
 android/sdremote/res/layout/activity_settings.xml                                          |    6 
 android/sdremote/res/layout/fragment_blankscreen.xml                                       |   44 
 android/sdremote/res/layout/fragment_presentation.xml                                      |   48 
 android/sdremote/res/layout/fragment_thumbnail.xml                                         |   14 
 android/sdremote/res/layout/idlayout.xml                                                   |    9 
 android/sdremote/res/layout/main.xml                                                       |   13 
 android/sdremote/res/layout/presentation_actionbar.xml                                     |   25 
 android/sdremote/res/layout/presentation_clockbar.xml                                      |   36 
 android/sdremote/res/layout/presentation_clockbar_countdownbar.xml                         |   29 
 android/sdremote/res/layout/presentation_clockbar_stopwatchbar.xml                         |   28 
 android/sdremote/res/layout/slide_thumbnail.xml                                            |   22 
 android/sdremote/res/layout/testlayout.xml                                                 |   40 
 android/sdremote/res/menu/actionbar_presentation.xml                                       |   18 
 android/sdremote/res/menu/activity_presentation.xml                                        |    6 
 android/sdremote/res/values/attrs.xml                                                      |   10 
 android/sdremote/res/values/strings.xml                                                    |   27 
 android/sdremote/res/values/styles.xml                                                     |   55 +
 android/sdremote/res/xml/preferences.xml                                                   |   15 
 android/sdremote/src/org/libreoffice/impressremote/BlankScreenFragment.java                |   65 +
 android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java               |  483 ++++++++++
 android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java               |  251 +++++
 android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java                   |  171 +++
 android/sdremote/src/org/libreoffice/impressremote/SettingsActivity.java                   |   27 
 android/sdremote/src/org/libreoffice/impressremote/SettingsFragment.java                   |   13 
 android/sdremote/src/org/libreoffice/impressremote/TestClient.java                         |  196 ++++
 android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java                  |  222 ++++
 android/sdremote/src/org/libreoffice/impressremote/communication/Client.java               |   95 +
 android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java |  169 +++
 android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java        |   60 +
 android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java             |  121 ++
 android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java         |  162 +++
 android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java            |  167 +++
 android/sdremote/src/org/libreoffice/impressremote/communication/Transmitter.java          |   71 +
 android/sdremote/src/pl/polidea/coverflow/AbstractCoverFlowImageAdapter.java               |  125 ++
 android/sdremote/src/pl/polidea/coverflow/CoverFlow.java                                   |  388 ++++++++
 android/sdremote/src/pl/polidea/coverflow/ReflectingImageAdapter.java                      |  129 ++
 android/sdremote/src/pl/polidea/coverflow/ResourceImageAdapter.java                        |   90 +
 config_host.mk.in                                                                          |    1 
 sd/CppunitTest_sd_uimpress.mk                                                              |    1 
 sd/Library_sd.mk                                                                           |   11 
 sd/inc/sddll.hxx                                                                           |    1 
 sd/source/ui/app/sddll.cxx                                                                 |    3 
 sd/source/ui/inc/RemoteServer.hxx                                                          |   62 +
 sd/source/ui/remotecontrol/DiscoveryService.cxx                                            |  119 ++
 sd/source/ui/remotecontrol/DiscoveryService.hxx                                            |   57 +
 sd/source/ui/remotecontrol/ImagePreparer.cxx                                               |  463 +++++++++
 sd/source/ui/remotecontrol/ImagePreparer.hxx                                               |   55 +
 sd/source/ui/remotecontrol/Listener.cxx                                                    |  159 +++
 sd/source/ui/remotecontrol/Listener.hxx                                                    |   75 +
 sd/source/ui/remotecontrol/Receiver.cxx                                                    |  116 ++
 sd/source/ui/remotecontrol/Receiver.hxx                                                    |   41 
 sd/source/ui/remotecontrol/RemoteDialog.cxx                                                |   20 
 sd/source/ui/remotecontrol/RemoteDialog.hxx                                                |   29 
 sd/source/ui/remotecontrol/Server.cxx                                                      |  165 +++
 sd/source/ui/remotecontrol/Transmitter.cxx                                                 |   78 +
 sd/source/ui/remotecontrol/Transmitter.hxx                                                 |   47 
 sd/source/ui/slideshow/slideshow.cxx                                                       |    3 
 sd/source/ui/slideshow/slideshowimpl.cxx                                                   |    4 
 102 files changed, 5351 insertions(+), 1 deletion(-)

New commits:
commit b2fd8230172641edbd2a4f67e214c44ce740b4b2
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Mon Aug 6 10:53:19 2012 +0200

    Some minor fixes.
    
    Change-Id: Id405b97440efc7160e76d535bddfd5580923fe24

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index 5b1b334..29ae7de 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -16,141 +16,147 @@ 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";
-
-	private static final long SEARCH_INTERVAL = 1000 * 20;
-
-	private DatagramSocket mSocket = null;
-
-	private Thread mListenerThread = null;
-
-	private boolean mFinishRequested = false;
-
-	private HashMap<String, Server> mServerList = new HashMap<String, Server>();
-
-	public ServerFinder(Context aContext) {
-		mContext = aContext;
-	}
-
-	private void listenForServer() {
-		byte[] aBuffer = new byte[500];
-		DatagramPacket aPacket = new DatagramPacket(aBuffer, aBuffer.length);
-
-		try {
-			String aCommand = null;
-			String aName = null;
-			mSocket.receive(aPacket);
-			int i;
-			for (i = 0; i < aBuffer.length; i++) {
-				if (aPacket.getData()[i] == '\n') {
-					aCommand = new String(aPacket.getData(), 0, i, CHARSET);
-					break;
-				}
-			}
-			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(), aName,
-			                System.currentTimeMillis());
-			mServerList.put(aServer.getAddress(), 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);
-
-		} 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();
-		}
-
-	}
-
-	public void startFinding() {
-		if (mSocket != null)
-			return;
-
-		mFinishRequested = false;
-
-		if (mListenerThread == null) {
-			mListenerThread = new Thread() {
-				@Override
-				public void run() {
-					long aTime = 0;
-					try {
-						mSocket = new DatagramSocket();
-						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) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
-					} catch (UnsupportedEncodingException e) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
-					} catch (IOException e) {
-						// TODO Auto-generated catch block
-						e.printStackTrace();
-					}
-
-				}
-			};
-			mListenerThread.start();
-		}
-
-	}
-
-	public void stopFinding() {
-		if (mListenerThread != null) {
-			mFinishRequested = true;
-			mListenerThread = null;
-		}
-	}
-
-	public Server[] getServerList() {
-		return mServerList.values().toArray(new Server[mServerList.size()]);
-	}
+    private Context mContext;
+
+    private static final int PORT = 1598;
+    private static final String GROUPADDRESS = "239.0.0.1";
+
+    private static final String CHARSET = "UTF-8";
+
+    private static final long SEARCH_INTERVAL = 1000 * 20;
+
+    private DatagramSocket mSocket = null;
+
+    private Thread mListenerThread = null;
+
+    private boolean mFinishRequested = false;
+
+    private HashMap<String, Server> mServerList = new HashMap<String, Server>();
+
+    public ServerFinder(Context aContext) {
+        mContext = aContext;
+    }
+
+    private void listenForServer() {
+        byte[] aBuffer = new byte[500];
+        DatagramPacket aPacket = new DatagramPacket(aBuffer, aBuffer.length);
+
+        try {
+            String aCommand = null;
+            String aName = null;
+            System.out.println("SF:Reading");
+            mSocket.receive(aPacket);
+            System.out.println("SF:Received");
+            int i;
+            for (i = 0; i < aBuffer.length; i++) {
+                if (aPacket.getData()[i] == '\n') {
+                    aCommand = new String(aPacket.getData(), 0, i, CHARSET);
+                    break;
+                }
+            }
+            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(), aName,
+                            System.currentTimeMillis());
+            mServerList.put(aServer.getAddress(), 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);
+
+        } 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();
+        }
+
+    }
+
+    public void startFinding() {
+        if (mSocket != null)
+            return;
+
+        mFinishRequested = false;
+
+        if (mListenerThread == null) {
+            mListenerThread = new Thread() {
+                @Override
+                public void run() {
+                    long aTime = 0;
+                    try {
+                        mSocket = new DatagramSocket();
+                        mSocket.setSoTimeout(1000 * 10);
+                        while (!mFinishRequested) {
+                            System.out.println("SF:Looping");
+                            if (System.currentTimeMillis() - aTime > SEARCH_INTERVAL) {
+                                System.out.println("SF:Sending");
+                                String aString = "LOREMOTE_SEARCH\n";
+                                DatagramPacket aPacket = new DatagramPacket(
+                                                aString.getBytes(CHARSET),
+                                                aString.length(),
+                                                InetAddress.getByName(GROUPADDRESS),
+                                                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) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    } catch (UnsupportedEncodingException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    } catch (IOException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+
+                }
+            };
+            mListenerThread.start();
+        }
+
+    }
+
+    public void stopFinding() {
+        if (mListenerThread != null) {
+            mFinishRequested = true;
+            mListenerThread = null;
+        }
+    }
+
+    public Server[] getServerList() {
+        return mServerList.values().toArray(new Server[mServerList.size()]);
+    }
 }
diff --git a/desktop/source/app/sofficemain.cxx b/desktop/source/app/sofficemain.cxx
index 2005939..a0fba04 100755
--- a/desktop/source/app/sofficemain.cxx
+++ b/desktop/source/app/sofficemain.cxx
@@ -99,6 +99,7 @@ extern "C" int DESKTOP_DLLPUBLIC soffice_main()
 #endif
         throw; // to get exception type printed
     }
+#endif
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk
index 8737ba0..ca00b19 100644
--- a/sd/Library_sd.mk
+++ b/sd/Library_sd.mk
@@ -35,7 +35,6 @@ $(eval $(call gb_SdiTarget_set_include,sd/sdi/sdslots,\
     $$(INCLUDE) \
 ))
 
-
 $(eval $(call gb_SdiTarget_SdiTarget,sd/sdi/sdgslots,sd/sdi/sdgslots))
 
 $(eval $(call gb_SdiTarget_set_include,sd/sdi/sdgslots,\
@@ -61,6 +60,10 @@ $(eval $(call gb_Library_set_include,sd,\
     -I$(WORKDIR)/SdiTarget/sd/sdi \
 ))
 
+$(eval $(call gb_Library_use_externals,sd,\
+ libxml2 \
+))
+
 $(eval $(call gb_Library_add_defs,sd,\
     -DSD_DLLIMPLEMENTATION \
 ))
@@ -102,6 +105,7 @@ $(eval $(call gb_Library_use_libraries,sd,\
     ucbhelper \
     utl \
     vcl \
+    xmlsecurity \
     $(gb_STDLIBS) \
 ))
 
diff --git a/sd/source/ui/remotecontrol/Server.cxx b/sd/source/ui/remotecontrol/Server.cxx
index 372103e..8371728 100644
--- a/sd/source/ui/remotecontrol/Server.cxx
+++ b/sd/source/ui/remotecontrol/Server.cxx
@@ -58,9 +58,6 @@ void RemoteServer::listenThread()
     {
     }
 
-
-    // TODO: decryption
-
     sal_uInt64 aRet, aRead;
     vector<char> aBuffer;
     vector<OString> aCommand;
@@ -86,7 +83,7 @@ void RemoteServer::listenThread()
                 aReceiver.parseCommand( aCommand );
                 aCommand.clear();
             }
-            aBuffer.erase( aBuffer.begin(), aIt + 1 ); // Also delete the newline
+            aBuffer.erase( aBuffer.begin(), aIt + 1 ); // Also delete the empty line
             aRead -= (aLocation + 1);
         }
     }
commit c56b0a2fe8a54aef8229a7b32a8d62cc23bbd9e6
Author: Andrzej J.R. Hunt <andrzej at 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 ad72b47df44b6ac73a0b76b346d5e93811e6941f
Author: Andrzej J.R. Hunt <andrzej at 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 bbbfaf7b9e3bead70966db338c250e4cbb4fc1d9
Author: Andrzej J.R. Hunt <andrzej at 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 b5d6989e8b7a739881f54ce9db0d560fb69e7eb9
Author: Andrzej J.R. Hunt <andrzej at 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 98e52c47474e91dcaa5d41d8fd4925b17689fd65
Author: Andrzej J.R. Hunt <andrzej at 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 cb82805c524e2d65ad75221bb50eee808c4177c8
Author: Andrzej J.R. Hunt <andrzej at 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 3213339132be43ce8ca502924c741cfac53ed09e
Author: Andrzej J.R. Hunt <andrzej at 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();
+	}
+
 }
commit 5e365b05683402dcdcf527e74e472e844cff15a0
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Thu Aug 2 16:52:53 2012 +0200

    Server discovery functional.
    
    Change-Id: I8642e0ea95a8d6691b76cc4d2dc1ddfbbf2b03e2

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index d787e34..b78a9a4 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -40,16 +40,17 @@ public class ServerFinder {
 			if (i == aBuffer.length || !aCommand.equals("LOREMOTE_ADVERTISE")) {
 				return;
 			}
-
-			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");
-			}
+			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");
+			//			}
 		} catch (IOException e) {
 			// TODO Auto-generated catch block
 			e.printStackTrace();
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index 612332f..bc514d7 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -67,6 +67,8 @@ void DiscoveryService::replyTo( sockaddr_in& rAddr )
 //     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) );
 }
 
 void DiscoveryService::execute()
commit 473143eac756184028e487d23a9af6ea452e1324
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Thu Aug 2 16:40:31 2012 +0200

    Multicast listening now working.
    
    Change-Id: Icae91b26f1142d7f25d6e38af4f951be26d9b22a

diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index 2d2b367..612332f 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -15,6 +15,16 @@
 
 #include "DiscoveryService.hxx"
 
+#ifdef WIN32
+  #include <winsock.h>
+  typedef int socklen_t;
+#else
+  #include <sys/types.h>
+  #include <sys/socket.h>
+  #include <netinet/in.h>
+  #include <arpa/inet.h>
+#endif
+
 using namespace osl;
 using namespace rtl;
 using namespace sd;
@@ -22,9 +32,25 @@ using namespace std;
 
 DiscoveryService::DiscoveryService()
     :
-    Thread( "sd::DiscoveryService" ),
-    mSocket()
+    Thread( "sd::DiscoveryService" )
+//     mSocket()
 {
+    mSocket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
+
+    sockaddr_in aAddr;
+    aAddr.sin_family = AF_INET;
+    aAddr.sin_addr.s_addr = htonl(INADDR_ANY);
+    aAddr.sin_port = htons( PORT_DISCOVERY );
+
+    bind( mSocket, (sockaddr*) &aAddr, sizeof(sockaddr_in) );
+
+    struct ip_mreq multicastRequest;
+
+    multicastRequest.imr_multiaddr.s_addr = inet_addr( "239.0.0.1" );
+    multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
+
+    setsockopt( mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+        &multicastRequest, sizeof(multicastRequest));
 }
 
 DiscoveryService::~DiscoveryService()
@@ -32,15 +58,15 @@ DiscoveryService::~DiscoveryService()
 }
 
 
-void DiscoveryService::replyTo( SocketAddr& rAddr )
+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() );
+//     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() );
 }
 
 void DiscoveryService::execute()
@@ -50,24 +76,21 @@ void DiscoveryService::execute()
     vector<char> aBuffer;
     aRead = 0;
 
-
-
-    SocketAddr aListenAddr( "239.0.0.1", PORT_DISCOVERY );
-    mSocket.bind( aListenAddr );
-
-    SocketAddr aAddr;
     while ( true )
     {
         aBuffer.resize( aRead + 100 );
 
+        sockaddr_in aAddr;
+        socklen_t aLen = sizeof( aAddr );
         fprintf( stderr, "DiscoveryService waiting for packet\n" );
-        aRet = mSocket.recvFrom( &aBuffer[aRead], 100 );
+//         aRet = mSocket.recvFrom( &aBuffer[aRead], 100 );
+        recvfrom( mSocket, &aBuffer[aRead], 100, 0, (sockaddr*) &aAddr, &aLen );
         fprintf( stderr, "DiscoveryService received a packet.\n" );
-        if ( aRet == 0 )
-        {
-            fprintf( stderr, "Socket returned 0\n" );
-//             break; // I.e. transmission finished.
-        }
+//         if ( aRet == 0 )
+//         {
+//             fprintf( stderr, "Socket returned 0\n" );
+// //             break; // I.e. transmission finished.
+//         }
         aRead += aRet;
         vector<char>::iterator aIt;
         while ( (aIt = find( aBuffer.begin(), aBuffer.end(), '\n' ))
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.hxx b/sd/source/ui/remotecontrol/DiscoveryService.hxx
index aa4b349..94a2765 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.hxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.hxx
@@ -27,9 +27,13 @@ namespace css = ::com::sun::star;
 
 #define CHARSET RTL_TEXTENCODING_UTF8
 
+struct sockaddr_in;
+
 namespace sd
 {
 
+
+
     class DiscoveryService : public salhelper::Thread
     {
         public:
@@ -42,8 +46,9 @@ namespace sd
             static DiscoveryService *spService;
             void execute();
 
-            osl::DatagramSocket mSocket;
-            void replyTo( osl::SocketAddr& rAddr );
+//             osl::DatagramSocket mSocket;
+            int mSocket;
+            void replyTo( sockaddr_in& rAddr );
 
     };
 }
commit 341f89ec308bd5a66a36741d22f100721d8223de
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Thu Aug 2 16:11:06 2012 +0200

    Early non-functional multicast code.
    
    Change-Id: Id982b40e5e9df4dee037a2e54ed34206930123c9

diff --git a/android/sdremote/src/org/libreoffice/impressremote/TestClient.java b/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
index ee8c57b..dc74cd5 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
@@ -85,7 +85,8 @@ public class TestClient extends Activity {
 			mCommunicationService = ((CommunicationService.CBinder) aService)
 			                .getService();
 			mCommunicationService.connectTo(
-			                CommunicationService.Protocol.NETWORK, "10.0.2.2");
+			                CommunicationService.Protocol.NETWORK,
+			                "192.168.0.18");
 			mCommunicationService.setActivityMessenger(mMessenger);
 			enableButtons(true);
 		}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 258bff1..e1669cc 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -55,6 +55,8 @@ public class CommunicationService extends Service {
 	@Override
 	public void onCreate() {
 		// TODO Create a notification (if configured).
+		ServerFinder aFinder = new ServerFinder();
+		aFinder.startFinding();
 	}
 
 	@Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
new file mode 100644
index 0000000..d787e34
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -0,0 +1,104 @@
+package org.libreoffice.impressremote.communication;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketException;
+
+public class ServerFinder {
+
+	private static final int PORT = 1598;
+	private static final String CHARSET = "UTF-8";
+
+	private DatagramSocket mSocket = null;
+
+	private Thread mListenerThread = null;
+
+	public ServerFinder() {
+
+	}
+
+	private void listenForServer() {
+		byte[] aBuffer = new byte[500];
+		DatagramPacket aPacket = new DatagramPacket(aBuffer, aBuffer.length);
+
+		try {
+			String aCommand = null;
+			String aAddress = 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') {
+					aCommand = new String(aPacket.getData(), 0, i, CHARSET);
+					break;
+				}
+			}
+			if (i == aBuffer.length || !aCommand.equals("LOREMOTE_ADVERTISE")) {
+				return;
+			}
+
+			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");
+			}
+		} catch (IOException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+	}
+
+	public void startFinding() {
+		if (mSocket != null)
+			return;
+
+		if (mListenerThread == null) {
+			mListenerThread = new Thread() {
+				@Override
+				public void run() {
+					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");
+						while (true) {
+							listenForServer();
+						}
+					} catch (SocketException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					} catch (UnsupportedEncodingException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					} catch (IOException e) {
+						// TODO Auto-generated catch block
+						e.printStackTrace();
+					}
+
+				}
+			};
+			mListenerThread.start();
+		}
+
+	}
+
+	public void stopFinding() {
+		if (mListenerThread != null) {
+
+		}
+	}
+}
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index 1ded965..2d2b367 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -45,15 +45,24 @@ void DiscoveryService::replyTo( SocketAddr& rAddr )
 
 void DiscoveryService::execute()
 {
+    fprintf( stderr, "Discovery service is listening\n" );;
     sal_uInt64 aRet, aRead;
     vector<char> aBuffer;
     aRead = 0;
 
+
+
+    SocketAddr aListenAddr( "239.0.0.1", PORT_DISCOVERY );
+    mSocket.bind( aListenAddr );
+
     SocketAddr aAddr;
     while ( true )
     {
         aBuffer.resize( aRead + 100 );
+
+        fprintf( stderr, "DiscoveryService waiting for packet\n" );
         aRet = mSocket.recvFrom( &aBuffer[aRead], 100 );
+        fprintf( stderr, "DiscoveryService received a packet.\n" );
         if ( aRet == 0 )
         {
             fprintf( stderr, "Socket returned 0\n" );
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index f948834..defc863 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -88,7 +88,7 @@ void ImagePreparer::execute()
         }
         sendNotes( i );
     }
-     notesToHtml( 0 );
+//      notesToHtml( 0 );
     mRef.clear();
 }
 
commit e43e36facc93b9e27e4d8757124ca0e6fcd9396b
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Thu Aug 2 12:27:19 2012 +0200

    Discovery service implemented server side.
    
    Change-Id: I26c26ae96680c6264d7b927cb9206073239f2ef4

diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
index f92b9ee..1ded965 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.cxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -11,10 +11,14 @@
 #include <vector>
 
 #include <comphelper/processfactory.hxx>
+#include <rtl/strbuf.hxx>
 
 #include "DiscoveryService.hxx"
 
+using namespace osl;
+using namespace rtl;
 using namespace sd;
+using namespace std;
 
 DiscoveryService::DiscoveryService()
     :
@@ -28,10 +32,47 @@ DiscoveryService::~DiscoveryService()
 }
 
 
+void DiscoveryService::replyTo( SocketAddr& 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() );
+}
 
 void DiscoveryService::execute()
 {
+    sal_uInt64 aRet, aRead;
+    vector<char> aBuffer;
+    aRead = 0;
 
+    SocketAddr aAddr;
+    while ( true )
+    {
+        aBuffer.resize( aRead + 100 );
+        aRet = mSocket.recvFrom( &aBuffer[aRead], 100 );
+        if ( aRet == 0 )
+        {
+            fprintf( stderr, "Socket returned 0\n" );
+//             break; // I.e. transmission finished.
+        }
+        aRead += aRet;
+        vector<char>::iterator aIt;
+        while ( (aIt = find( aBuffer.begin(), aBuffer.end(), '\n' ))
+            != aBuffer.end() )
+        {
+            sal_uInt64 aLocation = aIt - aBuffer.begin();
+            OString aString( &(*aBuffer.begin()), aLocation );
+            if ( aString.compareTo( "LOREMOTE_SEARCH" ) == 0 ) {
+                replyTo( aAddr );
+            }
+            aBuffer.erase( aBuffer.begin(), aIt + 1 ); // Also delete the newline
+            aRead -= (aLocation + 1);
+        }
+    }
 }
 
 DiscoveryService *sd::DiscoveryService::spService = NULL;
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.hxx b/sd/source/ui/remotecontrol/DiscoveryService.hxx
index 863ebb5..aa4b349 100644
--- a/sd/source/ui/remotecontrol/DiscoveryService.hxx
+++ b/sd/source/ui/remotecontrol/DiscoveryService.hxx
@@ -38,11 +38,13 @@ namespace sd
         private:
             DiscoveryService();
             ~DiscoveryService();
+
             static DiscoveryService *spService;
+            void execute();
 
             osl::DatagramSocket mSocket;
+            void replyTo( osl::SocketAddr& rAddr );
 
-            void execute();
     };
 }
 
commit 1a6bcd5bcdaf542c0a0db4fcc74149b9466dc58d
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Thu Aug 2 11:28:38 2012 +0200

    Basic structure for Disovery Service.
    
    Change-Id: Idaae84c46fa96b128ab32451853922c9eb11c6cc

diff --git a/sd/Library_sd.mk b/sd/Library_sd.mk
index 0a371ce..8737ba0 100644
--- a/sd/Library_sd.mk
+++ b/sd/Library_sd.mk
@@ -317,6 +317,7 @@ $(eval $(call gb_Library_add_exception_objects,sd,\
     sd/source/ui/presenter/PresenterPreviewCache \
     sd/source/ui/presenter/PresenterTextView \
     sd/source/ui/presenter/SlideRenderer \
+    sd/source/ui/remotecontrol/DiscoveryService \
     sd/source/ui/remotecontrol/ImagePreparer \
     sd/source/ui/remotecontrol/Server \
     sd/source/ui/remotecontrol/Receiver \
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.cxx b/sd/source/ui/remotecontrol/DiscoveryService.cxx
new file mode 100644
index 0000000..f92b9ee
--- /dev/null
+++ b/sd/source/ui/remotecontrol/DiscoveryService.cxx
@@ -0,0 +1,48 @@
+/* -*- 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/.
+ */
+#include <stdlib.h>
+#include <algorithm>
+#include <vector>
+
+#include <comphelper/processfactory.hxx>
+
+#include "DiscoveryService.hxx"
+
+using namespace sd;
+
+DiscoveryService::DiscoveryService()
+    :
+    Thread( "sd::DiscoveryService" ),
+    mSocket()
+{
+}
+
+DiscoveryService::~DiscoveryService()
+{
+}
+
+
+
+void DiscoveryService::execute()
+{
+
+}
+
+DiscoveryService *sd::DiscoveryService::spService = NULL;
+
+void DiscoveryService::setup()
+{
+  if (spService)
+    return;
+
+  spService = new DiscoveryService();
+  spService->launch();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/DiscoveryService.hxx b/sd/source/ui/remotecontrol/DiscoveryService.hxx
new file mode 100644
index 0000000..863ebb5
--- /dev/null
+++ b/sd/source/ui/remotecontrol/DiscoveryService.hxx
@@ -0,0 +1,50 @@
+/* -*- 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/.
+ */
+#ifndef _SD_IMPRESSREMOTE_DISCOVERYSERVICE_HXX
+#define _SD_IMPRESSREMOTE_DISCOVERYSERVICE_HXX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <osl/socket.hxx>
+#include <rtl/ref.hxx>
+#include <salhelper/thread.hxx>
+
+namespace css = ::com::sun::star;
+
+/**
+* The port for use for the main communication between LibO and remote control app.
+*/
+#define PORT_DISCOVERY 1598
+
+#define CHARSET RTL_TEXTENCODING_UTF8
+
+namespace sd
+{
+
+    class DiscoveryService : public salhelper::Thread
+    {
+        public:
+            static void setup();
+
+        private:
+            DiscoveryService();
+            ~DiscoveryService();
+            static DiscoveryService *spService;
+
+            osl::DatagramSocket mSocket;
+
+            void execute();
+    };
+}
+
+#endif // _SD_IMPRESSREMOTE_DISCOVERYSERVICE_HXX
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
diff --git a/sd/source/ui/remotecontrol/Server.cxx b/sd/source/ui/remotecontrol/Server.cxx
index 3b896fe..372103e 100644
--- a/sd/source/ui/remotecontrol/Server.cxx
+++ b/sd/source/ui/remotecontrol/Server.cxx
@@ -14,6 +14,7 @@
 
 #include "sddll.hxx"
 
+#include "DiscoveryService.hxx"
 #include "ImagePreparer.hxx"
 #include "Listener.hxx"
 #include "Receiver.hxx"
@@ -161,6 +162,7 @@ void SdDLL::RegisterRemotes()
 {
   fprintf( stderr, "Register our remote control goodness\n" );
   sd::RemoteServer::setup();
+  sd::DiscoveryService::setup();
 
 }
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 365f3e71c10eafdb239e70180beb62b41659e753
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Tue Jul 31 17:42:22 2012 +0200

    Discovered correct filter name.
    
    Change-Id: I2542ec663addca02874f3d449a1d8a243c7e5e97

diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index 21754d1..f948834 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -342,7 +342,7 @@ OString ImagePreparer::prepareNotes( sal_uInt32 aSlideNumber )
 
 sal_Bool ExportTo( uno::Reference< drawing::XDrawPage>& aNotesPage, String aUrl )
 {
-    ::rtl::OUString aFilterName( "com.sun.star.comp.Writer.XmlFilterAdaptor" );
+    ::rtl::OUString aFilterName( "XHTML Draw File" );
     uno::Reference< document::XExporter > xExporter;
 
     {
@@ -354,6 +354,8 @@ sal_Bool ExportTo( uno::Reference< drawing::XDrawPage>& aNotesPage, String aUrl
         uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
         if ( xFilters->hasByName( aFilterName ) )
             xFilters->getByName( aFilterName ) >>= aProps;
+        else
+            fprintf( stderr, "Couldn't find by name.\n" );
 
         ::rtl::OUString aFilterImplName;
         sal_Int32 nFilterProps = aProps.getLength();
@@ -367,16 +369,25 @@ sal_Bool ExportTo( uno::Reference< drawing::XDrawPage>& aNotesPage, String aUrl
             }
         }
 
+        fprintf( stderr, "aName%s\n", OUStringToOString(aFilterImplName, RTL_TEXTENCODING_UTF8).getStr() );
         if ( !aFilterImplName.isEmpty() )
         {
             try{
             xExporter = uno::Reference< document::XExporter >
                 ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
             }catch(const uno::Exception&)
-                { xExporter.clear(); }
+                {
+                    xExporter.clear();
+                    fprintf( stderr, "Couldn't create instance of filter.\n" );
+                }
         }
     }
 
+    if (xExporter.is())
+        fprintf( stderr, "Is!\n" );
+    else
+        fprintf( stderr, "Isn't\n" );
+
     if ( xExporter.is() )
     {
         try{
commit 3a834ee08edafaea3deb0688f46e6e5087935d64
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Tue Jul 31 15:27:12 2012 +0200

    Export now building, still missing some parameters to function.
    
    Change-Id: I5d893a292f99be46b0ca29c10345fc43a4366cfe

diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index 06ebc4c..21754d1 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -33,10 +33,15 @@
 #include <rtl/ustrbuf.hxx>
 #include <sax/tools/converter.hxx>
 #include <rtl/strbuf.hxx>
+#include <unotools/streamwrap.hxx>
+
+#include <svl/itemset.hxx>
+#include <sfx2/docfile.hxx>
 
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/container/XNameAccess.hpp>
 #include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
 #include <com/sun/star/document/XExporter.hpp>
 #include <com/sun/star/lang/XServiceName.hpp>
 #include <com/sun/star/presentation/XPresentationPage.hpp>
@@ -83,7 +88,7 @@ void ImagePreparer::execute()
         }
         sendNotes( i );
     }
-//     notesToHtml( 0 );
+     notesToHtml( 0 );
     mRef.clear();
 }
 
@@ -217,7 +222,7 @@ void ImagePreparer::sendNotes( sal_uInt32 aSlideNumber )
         Transmitter::Priority::LOW );
 }
 
-
+sal_Bool ExportTo( uno::Reference< drawing::XDrawPage>& aNotesPage, String aUrl );
 OString ImagePreparer::notesToHtml( sal_uInt32 aSlideNumber )
 {
     OString aRet("");
@@ -229,34 +234,11 @@ OString ImagePreparer::notesToHtml( sal_uInt32 aSlideNumber )
     if ( !xController->isRunning() )
         return "";
 
-    // Get the filter
-    uno::Reference< lang::XMultiServiceFactory > xServiceManager(
-        ::comphelper::getProcessServiceFactory(),
-        uno::UNO_QUERY_THROW );
-
-    uno::Reference< container::XNameAccess > xFilterFactory(
-        xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY_THROW );
 
-    if ( xFilterFactory->hasByName( "com.sun.star.comp.Writer.XmlFilterAdaptor" ) )
-        fprintf ( stderr, "Is contained\n" );
-    else fprintf( stderr, "Not contained\n" );
 
-//     uno::Sequence<Any> aList(6);
-//     aList[0] <<= OUString("com.sun.star.documentconversion.XSLTFilter");
-//     aList[1] <<= OUString("");
-//     aList[2] <<= OUString("com.sun.star.comp.Impress.XMLOasisImporter");
-//     aList[3] <<= OUString("com.sun.star.comp.Impress.XMLOasisExporter"),
-//     aList[4] <<= OUString("");
-//     aList[5] <<= OUString("../share/xslt/export/xhtml/opendoc2xhtml.xsl");
-
-//     uno::Reference< lang::XMultiServiceFactory > xFilterF( xFilterFactory, uno::UNO_QUERY_THROW );
-//         xFilterF->createInstanceWithArguments(OUString("com.sun.star.comp.Writer.XmlFilterAdaptor"), aList);
-
-    css::uno::Reference< document::XFilter > xFilter( xFilterFactory->getByName(
-        "com.sun.star.comp.Writer.XmlFilterAdaptor" ), uno::UNO_QUERY_THROW );
 
     // Get the page
-    uno::Reference< lang::XComponent > xNotesPage;
+    uno::Reference< drawing::XDrawPage > xNotesPage;
     uno::Reference< drawing::XDrawPage > xSourceDoc(
         xController->getSlideByIndex( aSlideNumber ),
         uno::UNO_QUERY_THROW );
@@ -264,29 +246,13 @@ OString ImagePreparer::notesToHtml( sal_uInt32 aSlideNumber )
     uno::Reference<presentation::XPresentationPage> xPresentationPage(
         xSourceDoc, UNO_QUERY);
     if (xPresentationPage.is())
-        xNotesPage = uno::Reference< lang::XComponent >(
+        xNotesPage = uno::Reference< drawing::XDrawPage >(
             xPresentationPage->getNotesPage(), uno::UNO_QUERY_THROW );
     else
         return "";
 
-    // Start Exporting
-    uno::Reference< document::XExporter > xExporter( xFilter,
-        uno::UNO_QUERY_THROW );
-
-    xExporter->setSourceDocument( xNotesPage );
-
-    uno::Sequence< beans::PropertyValue > aProps(1);
 
-    aProps[0].Name = "URL";
-    aProps[0].Value <<= aFileURL;
-
-//     aProps[1].Name = "com.sun.star.comp.Impress.XMLOasisExporter";
-//     aProps[1].Value <<= OUString( "../share/xslt/export/xhtml/opendoc2xhtml.xsl" );
-//     aProps[2].Name = "FilterData";
-//     aProps[2].Value <<= aFilterData;
-
-    fprintf( stderr, "Trying to filter\n" );
-    xFilter->filter( aProps );
+    ExportTo( xNotesPage, aFileURL );
 
     // FIXME: error handling.
 
@@ -373,4 +339,114 @@ OString ImagePreparer::prepareNotes( sal_uInt32 aSlideNumber )
     return OUStringToOString(
         aRet, RTL_TEXTENCODING_UTF8 );
 }
+
+sal_Bool ExportTo( uno::Reference< drawing::XDrawPage>& aNotesPage, String aUrl )
+{
+    ::rtl::OUString aFilterName( "com.sun.star.comp.Writer.XmlFilterAdaptor" );
+    uno::Reference< document::XExporter > xExporter;
+
+    {
+        uno::Reference< lang::XMultiServiceFactory >  xMan = ::comphelper::getProcessServiceFactory();
+        uno::Reference < lang::XMultiServiceFactory > xFilterFact (
+                xMan->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY );
+
+        uno::Sequence < beans::PropertyValue > aProps;
+        uno::Reference < container::XNameAccess > xFilters ( xFilterFact, uno::UNO_QUERY );
+        if ( xFilters->hasByName( aFilterName ) )
+            xFilters->getByName( aFilterName ) >>= aProps;
+
+        ::rtl::OUString aFilterImplName;
+        sal_Int32 nFilterProps = aProps.getLength();
+        for ( sal_Int32 nFilterProp = 0; nFilterProp<nFilterProps; nFilterProp++ )
+        {
+            const beans::PropertyValue& rFilterProp = aProps[nFilterProp];
+            if ( rFilterProp.Name.compareToAscii("FilterService") == 0 )
+            {
+                rFilterProp.Value >>= aFilterImplName;
+                break;
+            }
+        }
+
+        if ( !aFilterImplName.isEmpty() )
+        {
+            try{
+            xExporter = uno::Reference< document::XExporter >
+                ( xFilterFact->createInstanceWithArguments( aFilterName, uno::Sequence < uno::Any >() ), uno::UNO_QUERY );
+            }catch(const uno::Exception&)
+                { xExporter.clear(); }
+        }
+    }
+
+    if ( xExporter.is() )
+    {
+        try{
+        uno::Reference< lang::XComponent >  xComp( aNotesPage, uno::UNO_QUERY_THROW );
+        uno::Reference< document::XFilter > xFilter( xExporter, uno::UNO_QUERY_THROW );
+        xExporter->setSourceDocument( xComp );
+
+        com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aOldArgs ( 2 );
+        aOldArgs[0].Name = "FileName";
+        aOldArgs[0].Value <<= OUString( aUrl );
+        aOldArgs[1].Name = "FilterName";
+        aOldArgs[1].Value <<= OUString("com.sun.star.documentconversion.XSLTFilter");
+
+        SfxMedium rMedium( aUrl , STREAM_STD_WRITE  );
+
+        const com::sun::star::beans::PropertyValue * pOldValue = aOldArgs.getConstArray();
+        com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > aArgs ( aOldArgs.getLength() );
+        com::sun::star::beans::PropertyValue * pNewValue = aArgs.getArray();
+
+
+        // put in the REAL file name, and copy all PropertyValues
+        const OUString sOutputStream ( RTL_CONSTASCII_USTRINGPARAM ( "OutputStream" ) );
+        const OUString sStream ( RTL_CONSTASCII_USTRINGPARAM ( "StreamForOutput" ) );
+        sal_Bool bHasOutputStream = sal_False;
+        sal_Bool bHasStream = sal_False;
+        sal_Bool bHasBaseURL = sal_False;
+        sal_Int32 i;
+        sal_Int32 nEnd = aOldArgs.getLength();
+
+        for ( i = 0; i < nEnd; i++ )
+        {
+            pNewValue[i] = pOldValue[i];
+            if ( pOldValue[i].Name == "FileName" )
+                pNewValue[i].Value <<= OUString ( rMedium.GetName() );
+            else if ( pOldValue[i].Name == sOutputStream )
+                bHasOutputStream = sal_True;
+            else if ( pOldValue[i].Name == sStream )
+                bHasStream = sal_True;
+            else if ( pOldValue[i].Name == "DocumentBaseURL" )
+                bHasBaseURL = sal_True;
+        }
+
+        if ( !bHasOutputStream )
+        {
+            aArgs.realloc ( ++nEnd );
+            aArgs[nEnd-1].Name = sOutputStream;
+            aArgs[nEnd-1].Value <<= uno::Reference < io::XOutputStream > ( new utl::OOutputStreamWrapper ( *rMedium.GetOutStream() ) );
+        }
+
+        // add stream as well, for OOX export and maybe others
+        if ( !bHasStream )
+        {
+            aArgs.realloc ( ++nEnd );
+            aArgs[nEnd-1].Name = sStream;
+            aArgs[nEnd-1].Value <<= com::sun::star::uno::Reference < com::sun::star::io::XStream > ( new utl::OStreamWrapper ( *rMedium.GetOutStream() ) );
+        }
+
+        if ( !bHasBaseURL )
+        {
+            aArgs.realloc ( ++nEnd );
+            aArgs[nEnd-1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "DocumentBaseURL" ) );
+            aArgs[nEnd-1].Value <<= rMedium.GetBaseURL( sal_True );
+        }
+
+        return xFilter->filter( aArgs );
+        }catch(const uno::Exception&)
+        {}
+    }
+
+    return sal_False;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
\ No newline at end of file
commit a0a31723eb5187a579f76ec358e2b320bbda7e92
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Mon Jul 30 17:54:17 2012 +0200

    Attempt to use the XHTML export filter for note export (not functional yet).
    
    Change-Id: Iaf88b879d679a9dabc31468c51fe9b943c2053e5

diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index 6372556..4b759ef 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -93,8 +93,7 @@ public class PresentationFragment extends Fragment {
 	private void updateSlideNumberDisplay() {
 		int aSlide = mSlideShow.getCurrentSlide();
 		mNumberText.setText((aSlide + 1) + "/" + mSlideShow.getSize());
-		mNotes.loadData("<html><body>" + mSlideShow.getNotes(aSlide)
-		                + "</html></body>", "text/html", null);
+		mNotes.loadData(mSlideShow.getNotes(aSlide), "text/html", null);
 	}
 
 	// -------------------------------------------------- RESIZING LISTENER ----
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index fa2f81c..06ebc4c 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -35,6 +35,7 @@
 #include <rtl/strbuf.hxx>
 
 #include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
 #include <com/sun/star/document/XFilter.hpp>
 #include <com/sun/star/document/XExporter.hpp>
 #include <com/sun/star/lang/XServiceName.hpp>
@@ -82,6 +83,7 @@ void ImagePreparer::execute()
         }
         sendNotes( i );
     }
+//     notesToHtml( 0 );
     mRef.clear();
 }
 
@@ -207,13 +209,102 @@ void ImagePreparer::sendNotes( sal_uInt32 aSlideNumber )
     aBuffer.append( OString::valueOf( sal_Int32( aSlideNumber ) ).getStr() );
     aBuffer.append( "\n" );
 
+    aBuffer.append( "<html><body>" );
     aBuffer.append( aNotes );
+    aBuffer.append( "</html></body>" );
     aBuffer.append( "\n\n" );
     pTransmitter->addMessage( aBuffer.makeStringAndClear(),
         Transmitter::Priority::LOW );
 }
 
 
+OString ImagePreparer::notesToHtml( sal_uInt32 aSlideNumber )
+{
+    OString aRet("");
+
+    OUString aFileURL;
+    FileBase::createTempFile( 0, 0, &aFileURL );
+    fprintf( stderr, OUStringToOString( aFileURL, RTL_TEXTENCODING_UTF8).getStr() );
+
+    if ( !xController->isRunning() )
+        return "";
+
+    // Get the filter
+    uno::Reference< lang::XMultiServiceFactory > xServiceManager(
+        ::comphelper::getProcessServiceFactory(),
+        uno::UNO_QUERY_THROW );
+
+    uno::Reference< container::XNameAccess > xFilterFactory(
+        xServiceManager->createInstance( "com.sun.star.document.FilterFactory" ), uno::UNO_QUERY_THROW );
+
+    if ( xFilterFactory->hasByName( "com.sun.star.comp.Writer.XmlFilterAdaptor" ) )
+        fprintf ( stderr, "Is contained\n" );
+    else fprintf( stderr, "Not contained\n" );
+
+//     uno::Sequence<Any> aList(6);
+//     aList[0] <<= OUString("com.sun.star.documentconversion.XSLTFilter");
+//     aList[1] <<= OUString("");
+//     aList[2] <<= OUString("com.sun.star.comp.Impress.XMLOasisImporter");
+//     aList[3] <<= OUString("com.sun.star.comp.Impress.XMLOasisExporter"),
+//     aList[4] <<= OUString("");
+//     aList[5] <<= OUString("../share/xslt/export/xhtml/opendoc2xhtml.xsl");
+
+//     uno::Reference< lang::XMultiServiceFactory > xFilterF( xFilterFactory, uno::UNO_QUERY_THROW );
+//         xFilterF->createInstanceWithArguments(OUString("com.sun.star.comp.Writer.XmlFilterAdaptor"), aList);
+
+    css::uno::Reference< document::XFilter > xFilter( xFilterFactory->getByName(
+        "com.sun.star.comp.Writer.XmlFilterAdaptor" ), uno::UNO_QUERY_THROW );
+
+    // Get the page
+    uno::Reference< lang::XComponent > xNotesPage;
+    uno::Reference< drawing::XDrawPage > xSourceDoc(
+        xController->getSlideByIndex( aSlideNumber ),
+        uno::UNO_QUERY_THROW );
+
+    uno::Reference<presentation::XPresentationPage> xPresentationPage(
+        xSourceDoc, UNO_QUERY);
+    if (xPresentationPage.is())
+        xNotesPage = uno::Reference< lang::XComponent >(
+            xPresentationPage->getNotesPage(), uno::UNO_QUERY_THROW );
+    else
+        return "";
+
+    // Start Exporting
+    uno::Reference< document::XExporter > xExporter( xFilter,
+        uno::UNO_QUERY_THROW );
+
+    xExporter->setSourceDocument( xNotesPage );
+
+    uno::Sequence< beans::PropertyValue > aProps(1);
+
+    aProps[0].Name = "URL";
+    aProps[0].Value <<= aFileURL;
+
+//     aProps[1].Name = "com.sun.star.comp.Impress.XMLOasisExporter";
+//     aProps[1].Value <<= OUString( "../share/xslt/export/xhtml/opendoc2xhtml.xsl" );
+//     aProps[2].Name = "FilterData";
+//     aProps[2].Value <<= aFilterData;
+
+    fprintf( stderr, "Trying to filter\n" );
+    xFilter->filter( aProps );
+
+    // FIXME: error handling.
+
+//     File aFile( aFileURL );
+//     aFile.open(0);
+//     sal_uInt64 aRead;
+//     rSize = 0;
+//     aFile.getSize( rSize );
+//     uno::Sequence<sal_Int8> aContents( rSize );
+
+//     aFile.read( aContents.getArray(), rSize, aRead );
+//     aFile.close();
+//     File::remove( aFileURL );
+//     return aContents;
+
+    return aRet;
+}
+
 // Code copied from sdremote/source/presenter/PresenterNotesView.cxx
 OString ImagePreparer::prepareNotes( sal_uInt32 aSlideNumber )
 {
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.hxx b/sd/source/ui/remotecontrol/ImagePreparer.hxx
index 130eeb6..2adf228 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.hxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.hxx
@@ -45,6 +45,7 @@ private:
 
     void sendNotes( sal_uInt32 aSlideNumber );
     rtl::OString prepareNotes( sal_uInt32 aSlideNumber );
+    rtl::OString notesToHtml( sal_uInt32 aSlideNumber );
 };
 
 }
commit 292bc25e49a1797ef07736c227d74aa105822e6a
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Mon Jul 30 09:56:15 2012 +0200

    Basic (unstyled) note export and display working.
    
    Change-Id: Ic17267131d9a777955cd55415e5fe1e106d09e10

diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index cf45e09..6372556 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -91,8 +91,10 @@ public class PresentationFragment extends Fragment {
 	}
 
 	private void updateSlideNumberDisplay() {
-		mNumberText.setText((mSlideShow.getCurrentSlide() + 1) + "/"
-		                + mSlideShow.getSize());
+		int aSlide = mSlideShow.getCurrentSlide();
+		mNumberText.setText((aSlide + 1) + "/" + mSlideShow.getSize());
+		mNotes.loadData("<html><body>" + mSlideShow.getNotes(aSlide)
+		                + "</html></body>", "text/html", null);
 	}
 
 	// -------------------------------------------------- RESIZING LISTENER ----
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index b03c03b..258bff1 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -34,6 +34,7 @@ public class CommunicationService extends Service {
 	public static final int MSG_SLIDESHOW_STARTED = 1;
 	public static final int MSG_SLIDE_CHANGED = 2;
 	public static final int MSG_SLIDE_PREVIEW = 3;
+	public static final int MSG_SLIDE_NOTES = 4;
 
 	private Transmitter mTransmitter;
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
index e78f07e..1cecd49 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
@@ -90,6 +90,28 @@ public class Receiver {
 					// TODO Auto-generated catch block
 					e.printStackTrace();
 				}
+			} else if (aInstruction.equals("slide_notes")) {
+				int aSlideNumber = Integer.parseInt(aCommand.get(1));
+				String aNotes = new String();
+				for (int i = 2; i < aCommand.size(); i++) {
+					aNotes += aCommand.get(i);
+				}
+
+				// Store image internally
+				mSlideShow.putNotes(aSlideNumber, aNotes);
+
+				// Notify the frontend
+				Message aMessage = Message.obtain(null,
+				                CommunicationService.MSG_SLIDE_NOTES);
+				Bundle aData = new Bundle();
+				aData.putInt("slide_number", aSlideNumber);
+				aMessage.setData(aData);
+				try {
+					mActivityMessenger.send(aMessage);
+				} catch (RemoteException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
 			}
 
 		}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
index 75b13a8..74f9ba9 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
@@ -15,6 +15,8 @@ import android.util.SparseArray;
 public class SlideShow {
 
 	private SparseArray<byte[]> mPreviewImages = new SparseArray<byte[]>();
+	private SparseArray<String> mNotes = new SparseArray<String>();
+
 	private int mSize = 0;
 	private int mCurrentSlide = 0;
 
@@ -46,6 +48,14 @@ public class SlideShow {
 		return BitmapFactory.decodeByteArray(aImage, 0, aImage.length);
 	}
 
+	protected void putNotes(int aSlide, String aNotes) {
+		mNotes.put(aSlide, aNotes);
+	}
+
+	public String getNotes(int aSlide) {
+		return mNotes.get(aSlide);
+	}
+
 	// ---------------------------------------------------- TIMER --------------
 	private Timer mTimer = new Timer();
 
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index 17fdc09..fa2f81c 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -38,6 +38,7 @@
 #include <com/sun/star/document/XFilter.hpp>
 #include <com/sun/star/document/XExporter.hpp>
 #include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/presentation/XPresentationPage.hpp>
 #include <com/sun/star/text/XTextRange.hpp>
 
 using namespace ::sd;
@@ -221,16 +222,24 @@ OString ImagePreparer::prepareNotes( sal_uInt32 aSlideNumber )
     if ( !xController->isRunning() )
         return "";
 
+    uno::Reference<css::drawing::XDrawPage> aNotesPage;
     uno::Reference< drawing::XDrawPage > xSourceDoc(
         xController->getSlideByIndex( aSlideNumber ),
         uno::UNO_QUERY_THROW );
+    uno::Reference<presentation::XPresentationPage> xPresentationPage(
+        xSourceDoc, UNO_QUERY);
+    if (xPresentationPage.is())
+        aNotesPage = xPresentationPage->getNotesPage();
+    else
+        return "";
+
 
     static const ::rtl::OUString sNotesShapeName (
         "com.sun.star.presentation.NotesShape" );
     static const ::rtl::OUString sTextShapeName (
         "com.sun.star.drawing.TextShape" );
 
-    uno::Reference<container::XIndexAccess> xIndexAccess ( xSourceDoc, UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xIndexAccess ( aNotesPage, UNO_QUERY);
     if (xIndexAccess.is())
     {
 
commit 0c1f4762caf333d2f32671d2113e450bccd003b8
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Mon Jul 30 09:25:18 2012 +0200

    Notes export now working.
    
    Change-Id: I025c3e6421614c68ea76c9b8afd351abca8b6fad

diff --git a/android/sdremote/src/org/libreoffice/impressremote/TestClient.java b/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
index 501cf97..ee8c57b 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/TestClient.java
@@ -58,7 +58,6 @@ public class TestClient extends Activity {
 	@Override
 	protected void onPause() {
 		super.onPause();
-		// doUnbindService();
 	}
 
 	@Override
@@ -66,6 +65,7 @@ public class TestClient extends Activity {
 		// TODO Auto-generated method stub
 		mCommunicationService.disconnect();
 		stopService(new Intent(this, CommunicationService.class));
+		doUnbindService();
 		finish();
 		super.onBackPressed();
 	}
diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index c129f3b..17fdc09 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -184,8 +184,32 @@ uno::Sequence<sal_Int8> ImagePreparer::preparePreview(
 void ImagePreparer::sendNotes( sal_uInt32 aSlideNumber )
 {
 
-    OString aOut = prepareNotes( aSlideNumber );
+    OString aNotes = prepareNotes( aSlideNumber );
 
+    if ( aNotes.getLength() == 0 )
+        return;
+
+//     OUStringBuffer aStrBuffer;
+//     ::sax::Converter::encodeBase64( aStrBuffer, aTemp );
+//
+//     OString aNotes = OUStringToOString(
+//         aStrBuffer.makeStringAndClear(), RTL_TEXTENCODING_UTF8 );
+
+    if ( !xController->isRunning() )
+        return;
+
+    // Start the writing
+    OStringBuffer aBuffer;
+
+    aBuffer.append( "slide_notes\n" );
+
+    aBuffer.append( OString::valueOf( sal_Int32( aSlideNumber ) ).getStr() );
+    aBuffer.append( "\n" );
+
+    aBuffer.append( aNotes );
+    aBuffer.append( "\n\n" );
+    pTransmitter->addMessage( aBuffer.makeStringAndClear(),
+        Transmitter::Priority::LOW );
 }
 
 
commit 191985e3e50ea0770c29d264b79f58497e9a894d
Author: Andrzej J.R. Hunt <andrzej at ahunt.org>
Date:   Mon Jul 30 09:11:16 2012 +0200

    Note extraction code added.
    
    Change-Id: I94f53dd24122943a4b81fc228115e3da7ff5c90e

diff --git a/sd/source/ui/remotecontrol/ImagePreparer.cxx b/sd/source/ui/remotecontrol/ImagePreparer.cxx
index b81ff77..c129f3b 100644
--- a/sd/source/ui/remotecontrol/ImagePreparer.cxx
+++ b/sd/source/ui/remotecontrol/ImagePreparer.cxx
@@ -1,12 +1,30 @@
 /* -*- 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/.
- */
-
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org.  If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
 #include "ImagePreparer.hxx"
 
 #include <comphelper/processfactory.hxx>
@@ -19,11 +37,14 @@
 #include <com/sun/star/beans/PropertyValue.hpp>
 #include <com/sun/star/document/XFilter.hpp>
 #include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/lang/XServiceName.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
 
-using namespace sd;
-using namespace rtl;
-using namespace osl;
+using namespace ::sd;
+using namespace ::rtl;
+using namespace ::osl;
 using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
 
 ImagePreparer::ImagePreparer(
     const uno::Reference<presentation::XSlideShowController>& rxController,
@@ -51,7 +72,15 @@ void ImagePreparer::execute()
         }
         sendPreview( i );
     }
-    fprintf( stderr, "ImagePreparer done\n" );
+    fprintf( stderr, "Preparing slide notes\n" );
+    for ( sal_uInt32 i = 0; i < aSlides; i++ )
+    {
+        if ( !xController->isRunning() ) // stopped/disposed of.
+        {
+            break;
+        }
+        sendNotes( i );
+    }
     mRef.clear();
 }
 
@@ -105,6 +134,7 @@ uno::Sequence<sal_Int8> ImagePreparer::preparePreview(
 
     if ( !xController->isRunning() )
         return uno::Sequence<sal_Int8>();
+
     uno::Reference< lang::XComponent > xSourceDoc(
         xController->getSlideByIndex( aSlideNumber ),
         uno::UNO_QUERY_THROW );
@@ -151,4 +181,72 @@ uno::Sequence<sal_Int8> ImagePreparer::preparePreview(
 
 }
 
+void ImagePreparer::sendNotes( sal_uInt32 aSlideNumber )
+{
+
+    OString aOut = prepareNotes( aSlideNumber );
+
+}
+
+

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list