[Libreoffice-commits] core.git: Branch 'feature/android-remote-ng' - 4 commits - android/sdremote

Artur Dryomov artur.dryomov at gmail.com
Thu Jun 20 09:05:46 PDT 2013


 android/sdremote/src/org/libreoffice/impressremote/Preferences.java                        |   57 +
 android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java               |   12 
 android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java                   |    8 
 android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothClient.java      |  115 ++--
 android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java      |  167 +++--
 android/sdremote/src/org/libreoffice/impressremote/communication/Client.java               |  176 +++---
 android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java |  286 ++++------
 android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java        |  205 ++++---
 android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java             |   26 
 android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java             |    4 
 android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java         |  263 +++++----
 android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java            |  145 -----
 android/sdremote/src/org/libreoffice/impressremote/communication/Timer.java                |  124 ++++
 13 files changed, 895 insertions(+), 693 deletions(-)

New commits:
commit c23d743aa05fd2b4b4d38de4ef1f64a74b09dc44
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Thu Jun 20 19:03:46 2013 +0300

    Refactor CommunicationService.
    
    Change-Id: I5107d18101a3d37e6df260563814a367c93ec10d

diff --git a/android/sdremote/src/org/libreoffice/impressremote/Preferences.java b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
index 35639da..7bc9e4b 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
@@ -17,6 +17,7 @@ public final class Preferences {
         }
 
         public static final String AUTHORIZED_REMOTES = "sdremote_authorisedremotes";
+        public static final String STORED_SERVERS = "sdremote_storedServers";
     }
 
     private Preferences() {
@@ -42,6 +43,15 @@ public final class Preferences {
 
         aPreferencesEditor.commit();
     }
+
+    public static void remove(Context aContext, String aLocation, String aKey) {
+        SharedPreferences.Editor aPreferencesEditor = getPreferences(aContext,
+            aLocation).edit();
+
+        aPreferencesEditor.remove(aKey);
+
+        aPreferencesEditor.commit();
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
index 560e5d3..a3d88da 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -155,7 +155,7 @@ public class SelectorActivity extends SherlockActivity {
     @Override
     public void onBackPressed() {
         if (mCommunicationService != null)
-            mCommunicationService.stopSearching();
+            mCommunicationService.stopSearch();
         Intent aIntent = new Intent(this, CommunicationService.class);
         stopService(aIntent);
         super.onBackPressed();
@@ -175,7 +175,7 @@ public class SelectorActivity extends SherlockActivity {
     protected void onPause() {
         super.onPause();
         if (mCommunicationService != null) {
-            mCommunicationService.stopSearching();
+            mCommunicationService.stopSearch();
         }
         doUnbindService();
         if (mProgressDialog != null) {
@@ -202,7 +202,7 @@ public class SelectorActivity extends SherlockActivity {
                         IBinder aService) {
             mCommunicationService = ((CommunicationService.CBinder) aService)
                             .getService();
-            mCommunicationService.startSearching();
+            mCommunicationService.startSearch();
             refreshLists();
         }
 
@@ -345,7 +345,7 @@ public class SelectorActivity extends SherlockActivity {
 
         @Override
         public void onClick(View aView) {
-            mCommunicationService.stopSearching();
+            mCommunicationService.stopSearch();
 
             Server aDesiredServer = null;
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 00a9039..d87ef6f 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -15,27 +15,70 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.libreoffice.impressremote.Globals;
-import org.libreoffice.impressremote.communication.Server.Protocol;
-
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Intent;
 import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.util.Log;
 import android.preference.PreferenceManager;
 import android.support.v4.content.LocalBroadcastManager;
 
-public class CommunicationService extends Service implements Runnable {
+import org.libreoffice.impressremote.Preferences;
+import org.libreoffice.impressremote.communication.Server.Protocol;
 
+public class CommunicationService extends Service implements Runnable {
     public static enum State {
         DISCONNECTED, SEARCHING, CONNECTING, CONNECTED
     }
 
+    public static final String MSG_SLIDESHOW_STARTED = "SLIDESHOW_STARTED";
+    public static final String MSG_SLIDE_CHANGED = "SLIDE_CHANGED";
+    public static final String MSG_SLIDE_PREVIEW = "SLIDE_PREVIEW";
+    public static final String MSG_SLIDE_NOTES = "SLIDE_NOTES";
+
+    public static final String MSG_SERVERLIST_CHANGED = "SERVERLIST_CHANGED";
+    public static final String MSG_PAIRING_STARTED = "PAIRING_STARTED";
+    public static final String MSG_PAIRING_SUCCESSFUL = "PAIRING_SUCCESSFUL";
+
+    public static final String STATUS_CONNECTED_SLIDESHOW_RUNNING = "STATUS_CONNECTED_SLIDESHOW_RUNNING";
+    public static final String STATUS_CONNECTED_NOSLIDESHOW = "STATUS_CONNECTED_NOSLIDESHOW";
+
+    public static final String STATUS_PAIRING_PINVALIDATION = "STATUS_PAIRING_PINVALIDATION";
+    public static final String STATUS_CONNECTION_FAILED = "STATUS_CONNECTION_FAILED";
+
+    /**
+     * Used to protect all writes to mState, mStateDesired, and mServerDesired.
+     */
+    private final Object mConnectionVariableMutex = new Object();
+
+    private State mState = State.DISCONNECTED;
+    private State mStateDesired = State.DISCONNECTED;
+
+    private Server mServerDesired = null;
+
+    private boolean mBluetoothPreviouslyEnabled;
+
+    private final IBinder mBinder = new CBinder();
+
+    private Transmitter mTransmitter;
+
+    private Client mClient;
+
+    private final Receiver mReceiver = new Receiver(this);
+
+    private final ServerFinder mNetworkFinder = new ServerFinder(this);
+    private final BluetoothFinder mBluetoothFinder = new BluetoothFinder(this);
+
+    private Thread mThread = null;
+
+    /**
+     * Key to use with getSharedPreferences to obtain a Map of stored servers.
+     * The keys are the ip/hostnames, the values are the friendly names.
+     */
+    private final Map<String, Server> mManualServers = new HashMap<String, Server>();
+
     /**
      * Get the publicly visible device name -- generally the bluetooth name,
      * however for bluetoothless devices the device model name is used.
@@ -43,41 +86,23 @@ public class CommunicationService extends Service implements Runnable {
      * @return The device name.
      */
     public static String getDeviceName() {
-        BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (aAdapter != null) {
-            String aName = aAdapter.getName();
-            if (aName != null)
-                return aName;
+        if (BluetoothAdapter.getDefaultAdapter() == null) {
+            return Build.MODEL;
         }
-        return Build.MODEL;
-    }
-
-    /**
-     * Used to protect all writes to mState, mStateDesired, and mServerDesired.
-     */
-    private Object mConnectionVariableMutex = new Object();
-
-    private State mState = State.DISCONNECTED;
 
-    public State getState() {
-        return mState;
-    }
+        if (BluetoothAdapter.getDefaultAdapter().getName() == null) {
+            return Build.MODEL;
+        }
 
-    public String getPairingPin() {
-        return Client.getPin();
+        return BluetoothAdapter.getDefaultAdapter().getName();
     }
 
     public String getPairingDeviceName() {
         return Client.getName();
     }
 
-    private State mStateDesired = State.DISCONNECTED;
-
-    private Server mServerDesired = null;
-
     @Override
     public void run() {
-        Log.i(Globals.TAG, "CommunicationService.run()");
         synchronized (this) {
             while (true) {
                 // Condition
@@ -87,57 +112,72 @@ public class CommunicationService extends Service implements Runnable {
                     // We have finished
                     return;
                 }
+
                 // Work
-                Log.i(Globals.TAG, "CommunicationService.run: at \"Work\"");
                 synchronized (mConnectionVariableMutex) {
-                    if ((mStateDesired == State.CONNECTED && mState == State.CONNECTED)
-                                    || (mStateDesired == State.DISCONNECTED && mState == State.CONNECTED)) {
-                        mClient.closeConnection();
-                        mClient = null;
-                        mState = State.DISCONNECTED;
+                    if ((mStateDesired == State.CONNECTED) && (mState == State.CONNECTED)) {
+                        closeConnection();
+                    }
+
+                    if ((mStateDesired == State.DISCONNECTED) && (mState == State.CONNECTED)) {
+                        closeConnection();
                     }
+
                     if (mStateDesired == State.CONNECTED) {
                         mState = State.CONNECTING;
-                        try {
-                            switch (mServerDesired.getProtocol()) {
-                            case NETWORK:
-                                mClient = new NetworkClient(mServerDesired,
-                                                this, mReceiver);
-                                mClient.validating();
-                                break;
-                            case BLUETOOTH:
-                                mClient = new BluetoothClient(mServerDesired,
-                                                this, mReceiver,
-                                                mBluetoothPreviouslyEnabled);
-                                mClient.validating();
-                                break;
-                            }
-                            mTransmitter = new Transmitter(mClient);
-                            mState = State.CONNECTED;
-                        } catch (IOException e) {
-                            Log.i(Globals.TAG, "CommunicationService.run: " + e);
-                            connextionFailed();
-                        }
+
+                        openConnection();
                     }
                 }
-                Log.i(Globals.TAG, "CommunicationService.finished work");
             }
         }
     }
 
-    private void connextionFailed() {
+    private void closeConnection() {
+        mClient.closeConnection();
+        mClient = null;
+
+        mState = State.DISCONNECTED;
+    }
+
+    private void openConnection() {
+        try {
+            mClient = buildClient();
+            mClient.validating();
+
+            mTransmitter = new Transmitter(mClient);
+
+            mState = State.CONNECTED;
+        } catch (IOException e) {
+            connectionFailed();
+        }
+    }
+
+    private Client buildClient() {
+        switch (mServerDesired.getProtocol()) {
+            case NETWORK:
+                return new NetworkClient(mServerDesired, this, mReceiver);
+
+            case BLUETOOTH:
+                return new BluetoothClient(mServerDesired, this, mReceiver,
+                    mBluetoothPreviouslyEnabled);
+
+            default:
+                throw new RuntimeException("Unknown desired protocol.");
+        }
+    }
+
+    private void connectionFailed() {
         mClient = null;
         mState = State.DISCONNECTED;
         Intent aIntent = new Intent(
-                CommunicationService.STATUS_CONNECTION_FAILED);
+            CommunicationService.STATUS_CONNECTION_FAILED);
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
-    private boolean mBluetoothPreviouslyEnabled;
-
-    public void startSearching() {
-        Log.i(Globals.TAG, "CommunicationService.startSearching()");
-        SharedPreferences aPref = PreferenceManager.getDefaultSharedPreferences(this);
+    public void startSearch() {
+        SharedPreferences aPref = PreferenceManager
+            .getDefaultSharedPreferences(this);
         boolean bEnableWifi = aPref.getBoolean("option_enablewifi", false);
         if (bEnableWifi)
             mNetworkFinder.startSearch();
@@ -150,8 +190,7 @@ public class CommunicationService extends Service implements Runnable {
         }
     }
 
-    public void stopSearching() {
-        Log.i(Globals.TAG, "CommunicationService.stopSearching()");
+    public void stopSearch() {
         mNetworkFinder.stopSearch();
         mBluetoothFinder.stopSearch();
         BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
@@ -163,7 +202,6 @@ public class CommunicationService extends Service implements Runnable {
     }
 
     public void connectTo(Server aServer) {
-        Log.i(Globals.TAG, "CommunicationService.connectTo(" + aServer + ")");
         synchronized (mConnectionVariableMutex) {
             if (mState == State.SEARCHING) {
                 mNetworkFinder.stopSearch();
@@ -181,7 +219,6 @@ public class CommunicationService extends Service implements Runnable {
     }
 
     public void disconnect() {
-        Log.d(Globals.TAG, "Service Disconnected");
         synchronized (mConnectionVariableMutex) {
             mStateDesired = State.DISCONNECTED;
             synchronized (this) {
@@ -190,63 +227,19 @@ public class CommunicationService extends Service implements Runnable {
         }
     }
 
-    /**
-     * Return the service to clients.
-     */
     public class CBinder extends Binder {
         public CommunicationService getService() {
             return CommunicationService.this;
         }
     }
 
-    private final IBinder mBinder = new CBinder();
-
-    public static final String MSG_SLIDESHOW_STARTED = "SLIDESHOW_STARTED";
-    public static final String MSG_SLIDE_CHANGED = "SLIDE_CHANGED";
-    public static final String MSG_SLIDE_PREVIEW = "SLIDE_PREVIEW";
-    public static final String MSG_SLIDE_NOTES = "SLIDE_NOTES";
-
-    public static final String MSG_SERVERLIST_CHANGED = "SERVERLIST_CHANGED";
-    public static final String MSG_PAIRING_STARTED = "PAIRING_STARTED";
-    public static final String MSG_PAIRING_SUCCESSFUL = "PAIRING_SUCCESSFUL";
-
-    /**
-     * Notify the UI that the service has connected to a server AND a slideshow
-     * is running.
-     * In this case the PresentationActivity should be started.
-     */
-    public static final String STATUS_CONNECTED_SLIDESHOW_RUNNING = "STATUS_CONNECTED_SLIDESHOW_RUNNING";
-    /**
-     * Notify the UI that the service has connected to a server AND no slideshow
-     * is running.
-     * In this case the StartPresentationActivity should be started.
-     */
-    public static final String STATUS_CONNECTED_NOSLIDESHOW = "STATUS_CONNECTED_NOSLIDESHOW";
-
-    public static final String STATUS_PAIRING_PINVALIDATION = "STATUS_PAIRING_PINVALIDATION";
-
-    public static final String STATUS_CONNECTION_FAILED = "STATUS_CONNECTION_FAILED";
-
-    private Transmitter mTransmitter;
-
-    private Client mClient;
-
-    private Receiver mReceiver = new Receiver(this);
-
-    private ServerFinder mNetworkFinder = new ServerFinder(this);
-    private BluetoothFinder mBluetoothFinder = new BluetoothFinder(this);
-
     @Override
     public IBinder onBind(Intent intent) {
-        // TODO Auto-generated method stub
         return mBinder;
     }
 
-    private Thread mThread = null;
-
     @Override
     public void onCreate() {
-        // TODO Create a notification (if configured).
         loadServersFromPreferences();
 
         mThread = new Thread(this);
@@ -255,7 +248,6 @@ public class CommunicationService extends Service implements Runnable {
 
     @Override
     public void onDestroy() {
-        // TODO Destroy the notification (as necessary).
         mManualServers.clear();
 
         mThread.interrupt();
@@ -267,10 +259,12 @@ public class CommunicationService extends Service implements Runnable {
     }
 
     public List<Server> getServers() {
-        ArrayList<Server> aServers = new ArrayList<Server>();
+        List<Server> aServers = new ArrayList<Server>();
+
         aServers.addAll(mNetworkFinder.getServers());
         aServers.addAll(mBluetoothFinder.getServers());
         aServers.addAll(mManualServers.values());
+
         return aServers;
     }
 
@@ -278,35 +272,23 @@ public class CommunicationService extends Service implements Runnable {
         return mReceiver.getSlideShow();
     }
 
-    public boolean isSlideShowRunning() {
-        return mReceiver.isSlideShowRunning();
-    }
-
-    /**
-     * Key to use with getSharedPreferences to obtain a Map of stored servers.
-     * The keys are the ip/hostnames, the values are the friendly names.
-     */
-    private static final String SERVERSTORAGE_KEY = "sdremote_storedServers";
-    private HashMap<String, Server> mManualServers = new HashMap<String, Server>();
-
     void loadServersFromPreferences() {
-        SharedPreferences aPref = getSharedPreferences(SERVERSTORAGE_KEY,
-                        MODE_PRIVATE);
+        SharedPreferences aPref = getSharedPreferences(
+            Preferences.Locations.STORED_SERVERS,
+            MODE_PRIVATE);
 
         @SuppressWarnings("unchecked")
-		Map<String, String> aStoredMap = (Map<String, String>) aPref.getAll();
+        Map<String, String> aStoredMap = (Map<String, String>) aPref.getAll();
 
         for (Entry<String, String> aServerEntry : aStoredMap.entrySet()) {
             mManualServers.put(aServerEntry.getKey(), new Server(
-                            Protocol.NETWORK, aServerEntry.getKey(),
-                            aServerEntry.getValue(), 0));
+                Protocol.NETWORK, aServerEntry.getKey(),
+                aServerEntry.getValue(), 0));
         }
     }
 
     /**
      * Manually add a new (network) server to the list of servers.
-     * @param aAddress
-     * @param aRemember
      */
     public void addServer(String aAddress, String aName, boolean aRemember) {
         for (String aServer : mManualServers.keySet()) {
@@ -314,31 +296,25 @@ public class CommunicationService extends Service implements Runnable {
                 return;
         }
         mManualServers.put(aAddress, new Server(Protocol.NETWORK, aAddress,
-                        aName, 0));
+            aName, 0));
         if (aRemember) {
-            SharedPreferences aPref = getSharedPreferences(SERVERSTORAGE_KEY,
-                            MODE_PRIVATE);
-            Editor aEditor = aPref.edit();
-            aEditor.putString(aAddress, aName);
-            aEditor.apply();
+
+            Preferences
+                .set(this, Preferences.Locations.STORED_SERVERS, aAddress,
+                    aName);
         }
     }
 
     public void removeServer(Server aServer) {
         mManualServers.remove(aServer.getAddress());
 
-        SharedPreferences aPref = getSharedPreferences(SERVERSTORAGE_KEY,
-                        MODE_PRIVATE);
-        Editor aEditor = aPref.edit();
-        aEditor.remove(aServer.getAddress());
-        aEditor.apply();
-
+        Preferences.remove(this, Preferences.Locations.STORED_SERVERS,
+            aServer.getAddress());
     }
 
     public Client getClient() {
         return mClient;
     }
-
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 215ba932b38420da5afa28efb4e2544dfb4fa03b
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Thu Jun 20 18:23:40 2013 +0300

    Refactor finders classes.
    
    Change-Id: Icaf80e1ff13bca059f6ee42a56f36a4b3f65a3fb

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java
index 972a8a4..4ed99a1 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothFinder.java
@@ -10,9 +10,7 @@ package org.libreoffice.impressremote.communication;
 
 import java.util.Collection;
 import java.util.HashMap;
-
-import org.libreoffice.impressremote.Globals;
-import org.libreoffice.impressremote.communication.Server.Protocol;
+import java.util.Map;
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
@@ -22,93 +20,126 @@ import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Handler;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
 
-public class BluetoothFinder {
+import org.libreoffice.impressremote.communication.Server.Protocol;
 
+public class BluetoothFinder extends BroadcastReceiver {
     // TODO: add removal of cached items
-    private Context mContext;
+    private final Context mContext;
 
-    BluetoothAdapter mAdapter;
+    private final Map<String, Server> mServers;
 
     public BluetoothFinder(Context aContext) {
         mContext = aContext;
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
+
+        mServers = new HashMap<String, Server>();
     }
 
-    public void startFinding() {
-        Log.i(Globals.TAG, "BluetoothFinder.startFinding(): mAdapter=" + mAdapter);
-        if (mAdapter == null) {
-            return; // No bluetooth adapter found (emulator, special devices)
+    public void startSearch() {
+        if (!isBluetoothAvailable()) {
+            return;
         }
-        IntentFilter aFilter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
-        aFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
-        aFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        mContext.registerReceiver(mReceiver, aFilter);
-        mAdapter.startDiscovery();
+
+        BluetoothAdapter.getDefaultAdapter().startDiscovery();
+
+        registerSearchResultsReceiver();
     }
 
-    public void stopFinding() {
-        Log.i(Globals.TAG, "BluetoothFinder.stopFinding(): mAdapter=" + mAdapter);
-        if (mAdapter == null) {
-            return; // No bluetooth adapter found (emulator, special devices)
-        }
-        mAdapter.cancelDiscovery();
-        try {
-            mContext.unregisterReceiver(mReceiver);
-        } catch (IllegalArgumentException e) {
-            // The receiver wasn't registered
-            Log.i(Globals.TAG, "BluetoothFinder.stopFinding: " + e);
+    private boolean isBluetoothAvailable() {
+        return BluetoothAdapter.getDefaultAdapter() != null;
+    }
+
+    private void registerSearchResultsReceiver() {
+        IntentFilter aIntentFilter = new IntentFilter(
+            BluetoothDevice.ACTION_FOUND);
+        aIntentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
+        aIntentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+
+        mContext.registerReceiver(this, aIntentFilter);
+    }
+
+    public void stopSearch() {
+        if (!isBluetoothAvailable()) {
+            return;
         }
+
+        BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
+
+        unregisterSearchResultsReceiver();
     }
 
-    private HashMap<String, Server> mServerList = new HashMap<String, Server>();
+    private void unregisterSearchResultsReceiver() {
+        mContext.unregisterReceiver(this);
+    }
 
-    public Collection<Server> getServerList() {
-        return mServerList.values();
+    public Collection<Server> getServers() {
+        return mServers.values();
     }
 
-    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
-
-        @Override
-        public void onReceive(Context context, Intent aIntent) {
-            Log.i(Globals.TAG, "BluetoothFinder: BroadcastReceiver.onReceive: aIntent=" + aIntent);
-            if (aIntent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
-                BluetoothDevice aDevice = (BluetoothDevice) aIntent.getExtras()
-                                .get(BluetoothDevice.EXTRA_DEVICE);
-                Log.i(Globals.TAG, "BluetoothFinder.onReceive: found " + aDevice.getName() + " at " + aDevice.getAddress());
-                if (aDevice.getName() == null)
-                    return;
-                Server aServer = new Server(Protocol.BLUETOOTH,
-                                aDevice.getAddress(), aDevice.getName(),
-                                System.currentTimeMillis());
-                mServerList.put(aServer.getAddress(), aServer);
-                Intent aNIntent = new Intent(
-                                CommunicationService.MSG_SERVERLIST_CHANGED);
-                LocalBroadcastManager.getInstance(mContext).sendBroadcast(
-                                aNIntent);
-            } else if (aIntent.getAction().equals(
-                            BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
-                            || aIntent.getAction()
-                                            .equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
-                // Start discovery again after a small delay.
-                // but check whether device is on incase the user manually
-                // disabled bluetooth
-                if (mAdapter.isEnabled()) {
-                    Handler aHandler = new Handler();
-                    aHandler.postDelayed(new Runnable() {
-                        @Override
-                        public void run() {
-                            // Looping, huh?
-                            Log.i(Globals.TAG, "BluetothFinder: looping");
-                        }
-                    }, 1000 * 15);
-                }
+    @Override
+    public void onReceive(Context aContext, Intent aIntent) {
+        if (aIntent.getAction().equals(BluetoothDevice.ACTION_FOUND)) {
+            BluetoothDevice aBluetoothDevice = (BluetoothDevice) aIntent
+                .getExtras().get(BluetoothDevice.EXTRA_DEVICE);
+
+            if (aBluetoothDevice == null) {
+                return;
             }
 
+            createServer(aBluetoothDevice);
+
+            callUpdatingServersList();
+
+            return;
         }
 
-    };
+        if (aIntent.getAction()
+            .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+            startDiscoveryDelayed();
+
+            return;
+        }
+
+        if (aIntent.getAction()
+            .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
+            startDiscoveryDelayed();
+        }
+    }
+
+    private void createServer(BluetoothDevice aBluetoothDevice) {
+        String aServerAddress = aBluetoothDevice.getAddress();
+        String aServerName = aBluetoothDevice.getName();
+
+        Server aServer = new Server(Protocol.BLUETOOTH, aServerAddress,
+            aServerName, System.currentTimeMillis());
+        mServers.put(aServerAddress, aServer);
+    }
+
+    private void callUpdatingServersList() {
+        Intent aServersListChangedIntent = new Intent(
+            CommunicationService.MSG_SERVERLIST_CHANGED);
+
+        LocalBroadcastManager.getInstance(mContext)
+            .sendBroadcast(aServersListChangedIntent);
+    }
+
+    private void startDiscoveryDelayed() {
+        // Start discovery again after a small delay.
+        // but check whether device is on in case the user manually
+        // disabled bluetooth
+
+        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
+            return;
+        }
+
+        Handler aHandler = new Handler();
+        aHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                // Looping, huh?
+            }
+        }, 1000 * 15);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index f7401fb..00a9039 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -24,6 +24,7 @@ import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.os.Binder;
+import android.os.Build;
 import android.os.IBinder;
 import android.util.Log;
 import android.preference.PreferenceManager;
@@ -31,7 +32,7 @@ import android.support.v4.content.LocalBroadcastManager;
 
 public class CommunicationService extends Service implements Runnable {
 
-    public enum State {
+    public static enum State {
         DISCONNECTED, SEARCHING, CONNECTING, CONNECTED
     }
 
@@ -48,7 +49,7 @@ public class CommunicationService extends Service implements Runnable {
             if (aName != null)
                 return aName;
         }
-        return android.os.Build.MODEL;
+        return Build.MODEL;
     }
 
     /**
@@ -139,20 +140,20 @@ public class CommunicationService extends Service implements Runnable {
         SharedPreferences aPref = PreferenceManager.getDefaultSharedPreferences(this);
         boolean bEnableWifi = aPref.getBoolean("option_enablewifi", false);
         if (bEnableWifi)
-            mNetworkFinder.startFinding();
+            mNetworkFinder.startSearch();
         BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
         if (aAdapter != null) {
             mBluetoothPreviouslyEnabled = aAdapter.isEnabled();
             if (!mBluetoothPreviouslyEnabled)
                 aAdapter.enable();
-            mBluetoothFinder.startFinding();
+            mBluetoothFinder.startSearch();
         }
     }
 
     public void stopSearching() {
         Log.i(Globals.TAG, "CommunicationService.stopSearching()");
-        mNetworkFinder.stopFinding();
-        mBluetoothFinder.stopFinding();
+        mNetworkFinder.stopSearch();
+        mBluetoothFinder.stopSearch();
         BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
         if (aAdapter != null) {
             if (!mBluetoothPreviouslyEnabled) {
@@ -165,8 +166,8 @@ public class CommunicationService extends Service implements Runnable {
         Log.i(Globals.TAG, "CommunicationService.connectTo(" + aServer + ")");
         synchronized (mConnectionVariableMutex) {
             if (mState == State.SEARCHING) {
-                mNetworkFinder.stopFinding();
-                mBluetoothFinder.stopFinding();
+                mNetworkFinder.stopSearch();
+                mBluetoothFinder.stopSearch();
                 mState = State.DISCONNECTED;
             }
             mServerDesired = aServer;
@@ -267,8 +268,8 @@ public class CommunicationService extends Service implements Runnable {
 
     public List<Server> getServers() {
         ArrayList<Server> aServers = new ArrayList<Server>();
-        aServers.addAll(mNetworkFinder.getServerList());
-        aServers.addAll(mBluetoothFinder.getServerList());
+        aServers.addAll(mNetworkFinder.getServers());
+        aServers.addAll(mBluetoothFinder.getServers());
         aServers.addAll(mManualServers.values());
         return aServers;
     }
@@ -324,7 +325,6 @@ public class CommunicationService extends Service implements Runnable {
     }
 
     public void removeServer(Server aServer) {
-
         mManualServers.remove(aServer.getAddress());
 
         SharedPreferences aPref = getSharedPreferences(SERVERSTORAGE_KEY,
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java b/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
index abaaf58..4381480 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
@@ -80,7 +80,7 @@ public class NetworkClient extends Client {
         String aPhoneName = CommunicationService.getDeviceName();
 
         sendCommand(Protocol.Commands
-            .prepareCommand(Protocol.Commands.PAIR, aPhoneName, mPin));
+            .prepareCommand(Protocol.Commands.PAIR_WITH_SERVER, aPhoneName, mPin));
     }
 
     @Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
index 11cf86e..6081669 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
@@ -22,9 +22,18 @@ final class Protocol {
         private Ports() {
         }
 
+        public static final int SERVER_SEARCH = 1598;
         public static final int CLIENT_CONNECTION = 1599;
     }
 
+    public static final class Addresses {
+        private Addresses() {
+        }
+
+        public static final String SERVER_SEARCH = "239.0.0.1";
+        public static final String SERVER_LOCAL_FOR_EMULATOR = "10.0.2.2";
+    }
+
     public static final class Messages {
         private Messages() {
         }
@@ -43,7 +52,8 @@ final class Protocol {
         private Commands() {
         }
 
-        public static final String PAIR = "LO_SERVER_CLIENT_PAIR";
+        public static final String PAIR_WITH_SERVER = "LO_SERVER_CLIENT_PAIR";
+        public static final String SEARCH_SERVERS = "LOREMOTE_SEARCH";
 
         public static final String TRANSITION_NEXT = "transition_next";
         public static final String TRANSITION_PREVIOUS = "transition_previous";
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
index f1726ad..9ac7037 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServerFinder.java
@@ -9,43 +9,161 @@
 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;
+import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
 import java.util.Collection;
 import java.util.HashMap;
-
-import org.libreoffice.impressremote.Globals;
-import org.libreoffice.impressremote.communication.Server.Protocol;
+import java.util.Map;
 
 import android.content.Context;
 import android.content.Intent;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
 
-public class ServerFinder {
+public class ServerFinder implements Runnable {
+    private final Context mContext;
 
-    private Context mContext;
+    private DatagramSocket mSocket = null;
+    private Thread mListenerThread;
+    private boolean mFinishRequested;
 
-    private static final int PORT = 1598;
-    private static final String GROUPADDRESS = "239.0.0.1";
+    private final Map<String, Server> mServers;
 
-    private static final String CHARSET = "UTF-8";
+    public ServerFinder(Context aContext) {
+        mContext = aContext;
 
-    private static final long SEARCH_INTERVAL = 1000 * 15;
+        mSocket = null;
+        mListenerThread = null;
+        mFinishRequested = false;
 
-    private DatagramSocket mSocket = null;
+        mServers = new HashMap<String, Server>();
+    }
 
-    private Thread mListenerThread = null;
+    public void startSearch() {
+        if (mSocket != null) {
+            return;
+        }
 
-    private boolean mFinishRequested = false;
+        mFinishRequested = false;
 
-    private HashMap<String, Server> mServerList = new HashMap<String, Server>();
+        if (mListenerThread == null) {
+            mListenerThread = new Thread(this);
+        }
 
-    public ServerFinder(Context aContext) {
-        mContext = aContext;
+        mListenerThread.start();
+    }
+
+    @Override
+    public void run() {
+        addLocalServerForEmulator();
+
+        long aStartSearchTime = 0;
+
+        setUpSearchSocket();
+
+        while (!mFinishRequested) {
+            if (System
+                .currentTimeMillis() - aStartSearchTime > 1000 * 15) {
+                sendSearchCommand();
+
+                aStartSearchTime = System.currentTimeMillis();
+
+                removeStaleServers();
+            }
+
+            listenForServer();
+        }
+    }
+
+    /**
+     * Check whether we are on an emulator and add it's host to the list of
+     * servers if so (although we do not know whether libo is running on
+     * the host).
+     */
+    private void addLocalServerForEmulator() {
+        if (!isLocalServerForEmulatorReachable()) {
+            return;
+        }
+
+        Server aServer = new Server(Server.Protocol.NETWORK,
+            Protocol.Addresses.SERVER_LOCAL_FOR_EMULATOR, "Android Emulator",
+            0);
+
+        mServers.put(aServer.getAddress(), aServer);
+
+        callUpdatingServersList();
+    }
+
+    private boolean isLocalServerForEmulatorReachable() {
+        try {
+            InetAddress aLocalServerAddress = InetAddress
+                .getByName(Protocol.Addresses.SERVER_LOCAL_FOR_EMULATOR);
+
+            return aLocalServerAddress.isReachable(100);
+        } catch (UnknownHostException e) {
+            return false;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
+    private void callUpdatingServersList() {
+        Intent aIntent = new Intent(
+            CommunicationService.MSG_SERVERLIST_CHANGED);
+        LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
+    }
+
+    private void setUpSearchSocket() {
+        try {
+            mSocket = new DatagramSocket();
+            mSocket.setSoTimeout(1000 * 10);
+        } catch (SocketException e) {
+            throw new RuntimeException("Unable to open search socket.");
+        }
+    }
+
+    private void sendSearchCommand() {
+        try {
+            mSocket.send(buildSearchPacket());
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to send search packet.");
+        }
+    }
+
+    private DatagramPacket buildSearchPacket() {
+        try {
+            String aSearchCommand = Protocol.Commands
+                .prepareCommand(Protocol.Commands.SEARCH_SERVERS);
+
+            DatagramPacket aSearchPacket = new DatagramPacket(
+                aSearchCommand.getBytes(), aSearchCommand.length());
+            aSearchPacket.setAddress(
+                InetAddress.getByName(Protocol.Addresses.SERVER_SEARCH));
+            aSearchPacket.setPort(Protocol.Ports.SERVER_SEARCH);
+
+            return aSearchPacket;
+        } catch (UnknownHostException e) {
+            throw new RuntimeException("Unable to find address to search.");
+        }
+    }
+
+    private void removeStaleServers() {
+        for (Server aServer : mServers.values()) {
+            if (aServer.mNoTimeout) {
+                continue;
+            }
+
+            if (System.currentTimeMillis()
+                - aServer
+                .getTimeDiscovered() > 60 * 1000) {
+                mServers
+                    .remove(aServer.getAddress());
+                callUpdatingServersList();
+            }
+        }
     }
 
     private void listenForServer() {
@@ -59,7 +177,8 @@ public class ServerFinder {
             int i;
             for (i = 0; i < aBuffer.length; i++) {
                 if (aPacket.getData()[i] == '\n') {
-                    aCommand = new String(aPacket.getData(), 0, i, CHARSET);
+                    aCommand = new String(aPacket.getData(), 0, i,
+                        Protocol.CHARSET);
                     break;
                 }
             }
@@ -69,7 +188,7 @@ public class ServerFinder {
             for (int j = i + 1; j < aBuffer.length; j++) {
                 if (aPacket.getData()[j] == '\n') {
                     aName = new String(aPacket.getData(), i + 1, j - (i + 1),
-                                    CHARSET);
+                        Protocol.CHARSET);
                     break;
                 }
             }
@@ -77,13 +196,12 @@ public class ServerFinder {
                 return;
             }
             Server aServer = new Server(Server.Protocol.NETWORK, aPacket
-                            .getAddress().getHostAddress(), aName,
-                            System.currentTimeMillis());
-            mServerList.put(aServer.getAddress(), aServer);
-            Log.i(Globals.TAG, "ServerFinder.listenForServer: contains " + aName);
+                .getAddress().getHostAddress(), aName,
+                System.currentTimeMillis());
+            mServers.put(aServer.getAddress(), aServer);
 
-            notifyActivity();
-        } catch (java.net.SocketTimeoutException e) {
+            callUpdatingServersList();
+        } catch (SocketTimeoutException e) {
             // Ignore -- we want to timeout to enable checking whether we
             // should stop listening periodically
         } catch (IOException e) {
@@ -91,100 +209,17 @@ public class ServerFinder {
 
     }
 
-    public void startFinding() {
-        if (mSocket != null)
-            return;
-
-        mFinishRequested = false;
-
+    public void stopSearch() {
         if (mListenerThread == null) {
-            mListenerThread = new Thread() {
-                @Override
-                public void run() {
-                    checkAndAddEmulator();
-                    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(GROUPADDRESS),
-                                                PORT);
-                                mSocket.send(aPacket);
-                                aTime = System.currentTimeMillis();
-                                // Remove stale servers
-                                for (Server aServer : mServerList.values()) {
-                                    if (!aServer.mNoTimeout
-                                                    && System.currentTimeMillis()
-                                                                    - aServer.getTimeDiscovered() > 60 * 1000) {
-                                        mServerList.remove(aServer.getAddress());
-                                        notifyActivity();
-
-                                    }
-                                }
-                            }
-
-                            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;
-        }
-    }
-
-    /**
-     * Check whether we are on an emulator and add it's host to the list of
-     * servers if so (although we do not know whether libo is running on
-     * the host).
-     */
-    private void checkAndAddEmulator() {
-        try {
-            if (InetAddress.getByName("10.0.2.2").isReachable(100)) {
-                Log.i(Globals.TAG, "ServerFinder.checkAndAddEmulator: NulledNot, whatever that is supposed to mean");
-                Server aServer = new Server(Protocol.NETWORK, "10.0.2.2",
-                                "Android Emulator Host", 0);
-                aServer.mNoTimeout = true;
-                mServerList.put(aServer.getAddress(), aServer);
-                notifyActivity();
-            }
-        } catch (IOException e) {
-            // Probably means we can't connect -- i.e. no emulator host
+            return;
         }
-    }
 
-    /**
-     * Notify the activity that the server list has changed.
-     */
-    private void notifyActivity() {
-        Intent aIntent = new Intent(CommunicationService.MSG_SERVERLIST_CHANGED);
-        LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
+        mFinishRequested = true;
+        mListenerThread = null;
     }
 
-    public Collection<Server> getServerList() {
-        return mServerList.values();
+    public Collection<Server> getServers() {
+        return mServers.values();
     }
 }
 
commit bc5ccdc2a5b3676da8061c0578d902d967bc04b2
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Tue Jun 18 14:05:54 2013 +0300

    Refactor clients classes
    
    * Remove logging, it should not be running on users devices.
    * Try to break long methods to small ones.
    
    Change-Id: I6ee1f211b4c9d20ff9d04f0faf96b45393c067ef

diff --git a/android/sdremote/src/org/libreoffice/impressremote/Preferences.java b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
new file mode 100644
index 0000000..35639da
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
@@ -0,0 +1,47 @@
+/* -*- Mode: Java; 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.content.Context;
+import android.content.SharedPreferences;
+
+public final class Preferences {
+    public static final class Locations {
+        private Locations() {
+        }
+
+        public static final String AUTHORIZED_REMOTES = "sdremote_authorisedremotes";
+    }
+
+    private Preferences() {
+    }
+
+    public static boolean doContain(Context aContext, String aLocation, String aKey) {
+        return getPreferences(aContext, aLocation).contains(aKey);
+    }
+
+    private static SharedPreferences getPreferences(Context aContext, String aLocation) {
+        return aContext.getSharedPreferences(aLocation, Context.MODE_PRIVATE);
+    }
+
+    public static String getString(Context aContext, String aLocation, String aKey) {
+        return getPreferences(aContext, aLocation).getString(aKey, null);
+    }
+
+    public static void set(Context aContext, String aLocation, String aKey, String aValue) {
+        SharedPreferences.Editor aPreferencesEditor = getPreferences(aContext,
+            aLocation).edit();
+
+        aPreferencesEditor.putString(aKey, aValue);
+
+        aPreferencesEditor.commit();
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothClient.java b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothClient.java
index c2e7a61..4fea919 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothClient.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothClient.java
@@ -8,99 +8,118 @@
  */
 package org.libreoffice.impressremote.communication;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.UUID;
 
-import org.libreoffice.impressremote.Globals;
-
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothSocket;
 import android.content.Intent;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
 
-/**
- * Standard Network client. Connects to a server using Sockets.
- */
 public class BluetoothClient extends Client {
+    // Standard UUID for the Serial Port Profile.
+    // https://www.bluetooth.org/en-us/specification/assigned-numbers-overview/service-discovery
+    private static final String STANDARD_SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB";
+
+    private final boolean mBluetoothWasEnabled;
 
-    private boolean mBluetoothWasEnabled;
-    private BluetoothAdapter mAdapter;
+    private final BluetoothAdapter mBluetoothAdapter;
     private BluetoothSocket mSocket;
 
-    public BluetoothClient(Server aServer,
-                    CommunicationService aCommunicationService,
-                    Receiver aReceiver, boolean aBluetoothWasEnabled)
-                    throws IOException {
+    public BluetoothClient(Server aServer, CommunicationService aCommunicationService, Receiver aReceiver, boolean aBluetoothWasEnabled) {
         super(aServer, aCommunicationService, aReceiver);
 
-        Log.i(Globals.TAG, "BluetoothClient(" + aServer + ")");
-
-        mAdapter = BluetoothAdapter.getDefaultAdapter();
         mBluetoothWasEnabled = aBluetoothWasEnabled;
+
+        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+
         if (!mBluetoothWasEnabled) {
-            mAdapter.enable();
+            mBluetoothAdapter.enable();
         }
+    }
 
-        BluetoothDevice aDevice = mAdapter
-                        .getRemoteDevice(aServer.getAddress());
-        mAdapter.cancelDiscovery();
+    @Override
+    protected void setUpServerConnection() {
+        mSocket = buildServerConnection();
+    }
 
-        // This is the "standard UUID for the Serial Port Profile".
-        // I.e. the 16-bit SerialPort UUID 0x1101 inserted into the
-        // Bluetooth BASE_UUID. See
-        // https://www.bluetooth.org/Technical/AssignedNumbers/service_discovery.htm
-        mSocket = aDevice.createRfcommSocketToServiceRecord(UUID
-                        .fromString("00001101-0000-1000-8000-00805F9B34FB"));
+    private BluetoothSocket buildServerConnection() {
+        try {
+            BluetoothDevice aBluetoothServer = mBluetoothAdapter
+                .getRemoteDevice(mServer.getAddress());
+
+            mBluetoothAdapter.cancelDiscovery();
+
+            BluetoothSocket aSocket = aBluetoothServer
+                .createRfcommSocketToServiceRecord(
+                    UUID.fromString(STANDARD_SPP_UUID));
+
+            aSocket.connect();
 
-        mSocket.connect();
-        Log.i(Globals.TAG, "BluetoothClient: connected");
+            return aSocket;
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to connect to Bluetooth host");
+        }
+    }
+
+    protected InputStream buildMessagesStream() {
+        try {
+            return mSocket.getInputStream();
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to open messages stream.");
+        }
+    }
+
+    protected OutputStream buildCommandsStream() {
+        try {
+            return mSocket.getOutputStream();
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to open commands stream.");
+        }
     }
 
     @Override
     public void closeConnection() {
         try {
-            if (mSocket != null)
-                mSocket.close();
+            mSocket.close();
         } catch (IOException e) {
-            e.printStackTrace();
+            throw new RuntimeException("Unable to close Bluetooth socket.");
         }
     }
 
     protected void onDisconnect() {
         if (!mBluetoothWasEnabled) {
-            mAdapter.disable();
+            mBluetoothAdapter.disable();
         }
     }
 
     @Override
     public void validating() throws IOException {
-        // TODO Auto-generated method stub
+        String aMessage = mMessagesReader.readLine();
 
-        mInputStream = mSocket.getInputStream();
-        mReader = new BufferedReader(new InputStreamReader(mInputStream,
-                        CHARSET));
-
-        mOutputStream = mSocket.getOutputStream();
-
-        String aTemp = mReader.readLine();
-        Log.i(Globals.TAG, "BluetoothClient: got line " + aTemp);
-        if (!aTemp.equals("LO_SERVER_SERVER_PAIRED")) {
+        if (!aMessage.equals(Protocol.Messages.PAIRED)) {
             return;
         }
-        while (mReader.readLine().length() != 0) {
+
+        while (mMessagesReader.readLine().length() != 0) {
             // Get rid of extra lines
         }
-        Intent aIntent = new Intent(CommunicationService.MSG_PAIRING_SUCCESSFUL);
-        LocalBroadcastManager.getInstance(mCommunicationService).sendBroadcast(
-                        aIntent);
-        startListening();
 
+        callSuccessfulPairing();
+
+        startListening();
     }
 
+    private void callSuccessfulPairing() {
+        Intent aSuccessfulPairingIntent = new Intent(
+            CommunicationService.MSG_PAIRING_SUCCESSFUL);
+
+        LocalBroadcastManager.getInstance(mCommunicationService)
+            .sendBroadcast(aSuccessfulPairingIntent);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
index ea6d4b9..10fa657 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Client.java
@@ -11,136 +11,158 @@ package org.libreoffice.impressremote.communication;
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
-
-import org.libreoffice.impressremote.Globals;
-import org.libreoffice.impressremote.communication.CommunicationService.State;
+import java.util.List;
 
 import android.content.Intent;
-import android.util.Log;
-
-/**
- * Generic Client for the remote control. To implement a Client for a specific
- * transport medium you must provide input and output streams (
- * <code>mInputStream</code> and <code>mOutputStream</code> before calling any
- * methods.
- */
-public abstract class Client {
+import android.text.TextUtils;
 
-    protected static final String CHARSET = "UTF-8";
+public abstract class Client implements Runnable {
+    protected final BufferedReader mMessagesReader;
+    protected final OutputStream mCommandsStream;
 
-    protected InputStream mInputStream;
-    protected BufferedReader mReader;
-    protected OutputStream mOutputStream;
     protected String mPin = "";
     protected String mName = "";
 
     private static Client latestInstance = null;
 
-    public abstract void closeConnection();
+    protected final Server mServer;
+    protected final CommunicationService mCommunicationService;
+    protected final Receiver mReceiver;
 
-    public abstract void validating() throws IOException;
-    private Receiver mReceiver;
-
-    protected Server mServer;
-
-    protected CommunicationService mCommunicationService;
-
-    protected Client(Server aServer,
-                    CommunicationService aCommunicationService,
-                    Receiver aReceiver) {
+    protected Client(Server aServer, CommunicationService aCommunicationService, Receiver aReceiver) {
         mServer = aServer;
         mName = aServer.getName();
         mCommunicationService = aCommunicationService;
         mReceiver = aReceiver;
         latestInstance = this;
+
+        setUpServerConnection();
+
+        mMessagesReader = buildMessagesReader(buildMessagesStream());
+        mCommandsStream = buildCommandsStream();
+    }
+
+    protected abstract void setUpServerConnection();
+
+    private BufferedReader buildMessagesReader(InputStream aMessagesStream) {
+        try {
+            return new BufferedReader(
+                new InputStreamReader(aMessagesStream, Protocol.CHARSET));
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException("Unable to create messages reader.");
+        }
+    }
+
+    protected abstract InputStream buildMessagesStream();
+
+    protected abstract OutputStream buildCommandsStream();
+
+    public static String getPin() {
+        if (latestInstance == null) {
+            return "";
+        }
+
+        return latestInstance.mName;
+    }
+
+    public static String getName() {
+        if (latestInstance == null) {
+            return "";
+        }
+
+        return latestInstance.mName;
     }
 
     protected void startListening() {
+        Thread aListeningThread = new Thread(this);
 
-        Thread t = new Thread() {
-            public void run() {
-                listen();
-            }
+        aListeningThread.start();
+    }
 
-        };
-        t.start();
+    @Override
+    public void run() {
+        listen();
     }
 
-    private final void listen() {
+    private void listen() {
         try {
             while (true) {
-                ArrayList<String> aList = new ArrayList<String>();
-                String aTemp;
-                // read until empty line
-                while ((aTemp = mReader.readLine()) != null
-                                && aTemp.length() != 0) {
-                    aList.add(aTemp);
-                }
-                if (aTemp == null) {
-                    Intent aIntent = new Intent(
-                                    mCommunicationService
-                                                    .getApplicationContext(),
-                                    ReconnectionActivity.class);
-                    aIntent.putExtra("server", mServer);
-                    aIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mCommunicationService.getApplicationContext()
-                                    .startActivity(aIntent);
+                List<String> aMessage = readMessage();
+
+                if (aMessage == null) {
                     return;
                 }
-                mReceiver.parseCommand(aList);
+
+                mReceiver.parseCommand(aMessage);
             }
-        } catch (UnsupportedEncodingException e) {
+        } catch (IOException e) {
+            // TODO: stream couldn't be opened
             e.printStackTrace();
-        } catch (IOException e1) {
-            // TODO stream couldn't be opened.
-            e1.printStackTrace();
         } finally {
             onDisconnect();
         }
-
     }
 
-    public static String getPin() {
-        if (latestInstance != null) {
-            return latestInstance.mPin;
-        } else {
-            return "";
+    private List<String> readMessage() throws IOException {
+        List<String> aMessage = new ArrayList<String>();
+
+        String aMessageParameter = mMessagesReader.readLine();
+
+        while ((aMessageParameter != null) && (!TextUtils
+            .isEmpty(aMessageParameter))) {
+            aMessage.add(aMessageParameter);
+
+            aMessageParameter = mMessagesReader.readLine();
         }
-    }
 
-    public static String getName() {
-        if (latestInstance != null) {
-            return latestInstance.mName;
-        } else {
-            return "";
+        if (aMessageParameter == null) {
+            startReconnection();
+
+            return null;
         }
+
+        return aMessage;
+    }
+
+    private void startReconnection() {
+        Intent aReconnectionIntent = new Intent(
+            mCommunicationService.getApplicationContext(),
+            ReconnectionActivity.class);
+        aReconnectionIntent.putExtra("server", mServer);
+        aReconnectionIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        mCommunicationService.getApplicationContext()
+            .startActivity(aReconnectionIntent);
+    }
+
+    /**
+     * Called after the Client disconnects. Can be extended to allow for
+     * cleaning up bluetooth properties etc.
+     */
+    protected void onDisconnect() {
     }
 
     /**
      * Send a valid command to the Server.
      */
-    public void sendCommand(String command) {
+    public void sendCommand(String aCommand) {
         try {
-            mOutputStream.write(command.getBytes(CHARSET));
+            mCommandsStream.write(aCommand.getBytes(Protocol.CHARSET));
         } catch (UnsupportedEncodingException e) {
-            throw new Error("Specified network encoding [" + CHARSET
-                            + " not available.");
+            throw new RuntimeException("UTF-8 must be used for commands.");
         } catch (IOException e) {
             // I.e. connection closed. This will be dealt with by the listening
             // loop.
         }
     }
 
-    /**
-     * Called after the Client disconnects. Can be extended to allow for
-     * cleaning up bluetooth properties etc.
-     */
-    protected void onDisconnect() {
-    }
+    public abstract void closeConnection();
 
+    public abstract void validating() throws IOException;
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java b/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
index fbd51fa..abaaf58 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/NetworkClient.java
@@ -8,135 +8,174 @@
  */
 package org.libreoffice.impressremote.communication;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.Socket;
 import java.net.UnknownHostException;
 import java.util.Random;
 
-import org.libreoffice.impressremote.Globals;
-
+import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
 import android.support.v4.content.LocalBroadcastManager;
-import android.util.Log;
-
-/**
- * Standard Network client. Connects to a server using Sockets.
- */
-public class NetworkClient extends Client {
 
-    private static final int PORT = 1599;
+import org.libreoffice.impressremote.Preferences;
 
+public class NetworkClient extends Client {
     private Socket mSocket;
-    private Intent mIntent;
-    private String mPin;
-    private Server mServer;
 
-    public NetworkClient(Server aServer,
-            CommunicationService aCommunicationService, Receiver aReceiver)
-            throws UnknownHostException, IOException {
+    private final String mPin;
+
+    public NetworkClient(Server aServer, CommunicationService aCommunicationService, Receiver aReceiver) {
         super(aServer, aCommunicationService, aReceiver);
-        mServer = aServer;
-        mSocket = new Socket(mServer.getAddress(), PORT);
-        mInputStream = mSocket.getInputStream();
-        mReader = new BufferedReader(new InputStreamReader(mInputStream,
-                CHARSET));
-        mOutputStream = mSocket.getOutputStream();
-
-        // Pairing.
-        mPin = setupPin(mServer);
-        mIntent = new Intent(CommunicationService.MSG_PAIRING_STARTED);
-        mIntent.putExtra("PIN", mPin);
-        LocalBroadcastManager.getInstance(mCommunicationService).sendBroadcast(
-                mIntent);
-        // Send out
-        String aName = CommunicationService.getDeviceName(); // TODO: get the
-                                                             // proper name
-        sendCommand("LO_SERVER_CLIENT_PAIR\n" + aName + "\n" + mPin + "\n\n");
+
+        mPin = loadPin();
+
+        startPairingActivity();
+        startPairing();
     }
 
-    private String setupPin(Server aServer) {
-        // Get settings
-        SharedPreferences aPreferences = mCommunicationService
-                .getSharedPreferences("sdremote_authorisedremotes",
-                        android.content.Context.MODE_PRIVATE);
-        if (aPreferences.contains(aServer.getName())) {
-            return aPreferences.getString(aServer.getName(), "");
-        } else {
-            String aPin = generatePin();
-
-            Editor aEdit = aPreferences.edit();
-            aEdit.putString(aServer.getName(), aPin);
-            aEdit.commit();
-
-            return aPin;
+    private String loadPin() {
+        Context aContext = mCommunicationService.getApplicationContext();
+
+        if (Preferences
+            .doContain(aContext, Preferences.Locations.AUTHORIZED_REMOTES,
+                mServer.getName())) {
+            return Preferences
+                .getString(aContext, Preferences.Locations.AUTHORIZED_REMOTES,
+                    mServer.getName());
         }
 
+        String aPin = generatePin();
+
+        Preferences.set(aContext, Preferences.Locations.AUTHORIZED_REMOTES,
+            mServer.getName(), aPin);
+
+        return aPin;
     }
 
     private String generatePin() {
-        Random aRandom = new Random();
-        String aPin = "" + (aRandom.nextInt(9000) + 1000);
-        while (aPin.length() < 4) {
-            aPin = "0" + aPin; // Add leading zeros if necessary
+        return String.format("%04d", generatePinNumber());
+    }
+
+    private int generatePinNumber() {
+        Random aRandomGenerator = new Random();
+
+        int aMaximumPin = (int) Math.pow(10, Protocol.PIN_NUMBERS_COUNT) - 1;
+
+        return aRandomGenerator.nextInt(aMaximumPin);
+    }
+
+    private void startPairingActivity() {
+        Intent aPairingIntent = new Intent(
+            CommunicationService.MSG_PAIRING_STARTED);
+        aPairingIntent.putExtra("PIN", mPin);
+
+        LocalBroadcastManager.getInstance(mCommunicationService)
+            .sendBroadcast(aPairingIntent);
+    }
+
+    private void startPairing() {
+        // TODO: get the proper name
+        String aPhoneName = CommunicationService.getDeviceName();
+
+        sendCommand(Protocol.Commands
+            .prepareCommand(Protocol.Commands.PAIR, aPhoneName, mPin));
+    }
+
+    @Override
+    protected void setUpServerConnection() {
+        mSocket = buildServerConnection();
+    }
+
+    private Socket buildServerConnection() {
+        try {
+            return new Socket(mServer.getAddress(),
+                Protocol.Ports.CLIENT_CONNECTION);
+        } catch (UnknownHostException e) {
+            throw new RuntimeException("Unable to connect to unknown host.");
+        } catch (IOException e) {
+            e.printStackTrace();
+            throw new RuntimeException("Unable to connect to host.");
+        }
+    }
+
+    @Override
+    protected InputStream buildMessagesStream() {
+        try {
+            return mSocket.getInputStream();
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to open messages stream.");
+        }
+    }
+
+    @Override
+    protected OutputStream buildCommandsStream() {
+        try {
+            return mSocket.getOutputStream();
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to open commands stream.");
         }
-        return aPin;
     }
 
     @Override
     public void closeConnection() {
         try {
-            if (mSocket != null)
-                mSocket.close();
+            mSocket.close();
         } catch (IOException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
+            throw new RuntimeException("Unable to close network socket.");
         }
     }
 
     @Override
     public void validating() throws IOException {
+        String aMessage = mMessagesReader.readLine();
 
-        // Wait until we get the appropriate string back...
-        String aTemp = mReader.readLine();
-
-        if (aTemp == null) {
-            throw new IOException(
-                    "End of stream reached before any data received.");
+        if (aMessage == null) {
+            throw new RuntimeException(
+                "End of stream reached before any data received.");
         }
 
-        while (!aTemp.equals("LO_SERVER_SERVER_PAIRED")) {
-            if (aTemp.equals("LO_SERVER_VALIDATING_PIN")) {
-                // Broadcast that we need a pin screen.
-                mIntent = new Intent(
-                        CommunicationService.STATUS_PAIRING_PINVALIDATION);
-                mIntent.putExtra("PIN", mPin);
-                mIntent.putExtra("SERVERNAME", mServer.getName());
-                LocalBroadcastManager.getInstance(mCommunicationService)
-                        .sendBroadcast(mIntent);
-                while (mReader.readLine().length() != 0) {
+        while (!aMessage.equals(Protocol.Messages.PAIRED)) {
+            if (aMessage.equals(Protocol.Messages.VALIDATING)) {
+                startPinValidation();
+
+                while (mMessagesReader.readLine().length() != 0) {
                     // Read off empty lines
                 }
-                aTemp = mReader.readLine();
+
+                aMessage = mMessagesReader.readLine();
             } else {
                 return;
             }
         }
 
-        mIntent = new Intent(CommunicationService.MSG_PAIRING_SUCCESSFUL);
-        LocalBroadcastManager.getInstance(mCommunicationService).sendBroadcast(
-                mIntent);
+        callSuccessfulPairing();
 
-        while (mReader.readLine().length() != 0) {
+        while (mMessagesReader.readLine().length() != 0) {
             // Get rid of extra lines
-            Log.i(Globals.TAG, "NetworkClient: extra line");
         }
-        Log.i(Globals.TAG, "NetworkClient: calling startListening");
+
         startListening();
     }
+
+    private void startPinValidation() {
+        Intent aPairingIntent = new Intent(
+            CommunicationService.STATUS_PAIRING_PINVALIDATION);
+        aPairingIntent.putExtra("PIN", mPin);
+        aPairingIntent.putExtra("SERVERNAME", mServer.getName());
+
+        LocalBroadcastManager.getInstance(mCommunicationService)
+            .sendBroadcast(aPairingIntent);
+    }
+
+    private void callSuccessfulPairing() {
+        Intent aSuccessfulPairingIntent = new Intent(
+            CommunicationService.MSG_PAIRING_SUCCESSFUL);
+
+        LocalBroadcastManager.getInstance(mCommunicationService)
+            .sendBroadcast(aSuccessfulPairingIntent);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
index 5227ee6..11cf86e 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Protocol.java
@@ -14,10 +14,24 @@ final class Protocol {
     private Protocol() {
     }
 
+    public static final String CHARSET = "UTF-8";
+
+    public static final int PIN_NUMBERS_COUNT = 4;
+
+    public static final class Ports {
+        private Ports() {
+        }
+
+        public static final int CLIENT_CONNECTION = 1599;
+    }
+
     public static final class Messages {
         private Messages() {
         }
 
+        public static final String PAIRED = "LO_SERVER_SERVER_PAIRED";
+        public static final String VALIDATING = "LO_SERVER_VALIDATING_PIN";
+
         public static final String SLIDESHOW_STARTED = "slideshow_started";
         public static final String SLIDESHOW_FINISHED = "slideshow_finished";
         public static final String SLIDE_UPDATED = "slide_updated";
@@ -29,6 +43,8 @@ final class Protocol {
         private Commands() {
         }
 
+        public static final String PAIR = "LO_SERVER_CLIENT_PAIR";
+
         public static final String TRANSITION_NEXT = "transition_next";
         public static final String TRANSITION_PREVIOUS = "transition_previous";
         public static final String GOTO_SLIDE = "goto_slide";
commit 8e97f28fe299a34a8f456d4762e6cebdb41fc311
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Mon Jun 17 18:43:33 2013 +0300

    Refactor the SlideShow class.
    
    * Move the Timer class to a separate file.
    * Remove drawing shadows for slides, it would be better to draw shadow
      only for the ViewPager in the future.
    
    Change-Id: I4373bdcf83f31ab08dccf96fd09a0a60f5d085b6

diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
index 22c2f18..ccbbfc6 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationActivity.java
@@ -13,7 +13,7 @@ import java.text.SimpleDateFormat;
 import java.util.TimeZone;
 
 import org.libreoffice.impressremote.communication.CommunicationService;
-import org.libreoffice.impressremote.communication.SlideShow.Timer;
+import org.libreoffice.impressremote.communication.Timer;
 
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
@@ -459,22 +459,22 @@ public class PresentationActivity extends SherlockFragmentActivity {
             // ------------------------------------- TIMER BUTTONS
             else if (aSource == mStopwatchButtonRun) {
                 if (aTimer.isRunning()) {
-                    aTimer.stopTimer();
+                    aTimer.stop();
                 } else {
-                    aTimer.startTimer();
+                    aTimer.start();
                 }
                 updateClockBar();
             } else if (aSource == mStopwatchButtonReset) {
                 if (aTimer.isRunning()) {
                     aTimer.reset();
-                    aTimer.startTimer();
+                    aTimer.start();
                 } else {
                     aTimer.reset();
                 }
                 updateClockBar();
             } else if (aSource == mCountdownButton) {
                 if (aTimer.isRunning()) {
-                    aTimer.stopTimer();
+                    aTimer.stop();
                     mCountdownButton.setTag(Boolean.valueOf(true));
                     updateClockBar();
                 } else {
@@ -485,7 +485,7 @@ public class PresentationActivity extends SherlockFragmentActivity {
                         editor.putString(COUNTDOWN_KEY, time);
                         editor.commit();
                         aTimer.setCountdownTime(aTime);
-                        aTimer.startTimer();
+                        aTimer.start();
                         mCountdownButton.setTag(Boolean.valueOf(true));
                         updateClockBar();
                     } catch (ParseException e) {
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
index 91a10e5..1ecb53e 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Receiver.java
@@ -22,7 +22,7 @@ public class Receiver {
 
     public Receiver(Context aContext) {
         this.mContext = aContext;
-        this.mSlideShow = new SlideShow(mContext);
+        this.mSlideShow = new SlideShow();
     }
 
     public SlideShow getSlideShow() {
@@ -89,7 +89,7 @@ public class Receiver {
     }
 
     private void finishSlideShow() {
-        this.mSlideShow = new SlideShow(mContext);
+        this.mSlideShow = new SlideShow();
 
         Intent aStatusConnectedNoSlideShowIntent = new Intent(
             CommunicationService.STATUS_CONNECTED_NOSLIDESHOW);
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
index dbb5c56..347a92c 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/SlideShow.java
@@ -8,35 +8,28 @@
  */
 package org.libreoffice.impressremote.communication;
 
-import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.RectF;
 import android.util.SparseArray;
 
-import org.libreoffice.impressremote.R;
-
 
 public class SlideShow {
-    private final Context mContext;
-
     private int mSlidesCount;
     private int mCurrentSlideIndex;
 
     private final SparseArray<Bitmap> mSlidePreviews;
     private final SparseArray<String> mSlideNotes;
 
-    public SlideShow(Context aContext) {
-        this.mContext = aContext;
+    private final Timer mTimer;
 
+    public SlideShow() {
         this.mSlidesCount = 0;
         this.mCurrentSlideIndex = 0;
 
         this.mSlidePreviews = new SparseArray<Bitmap>();
         this.mSlideNotes = new SparseArray<String>();
+
+        this.mTimer = new Timer();
     }
 
     public void setSlidesCount(int aSlidesCount) {
@@ -55,26 +48,11 @@ public class SlideShow {
         return mCurrentSlideIndex;
     }
 
-    public void setSlidePreview(int aSlideIndex, byte[] aSlidePreview) {
-        Bitmap aBitmap = BitmapFactory
-            .decodeByteArray(aSlidePreview, 0, aSlidePreview.length);
-        final int borderWidth = 8;
-
-        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
-        p.setShadowLayer(borderWidth, 0, 0, Color.BLACK);
-
-        RectF aRect = new RectF(borderWidth, borderWidth, borderWidth
-            + aBitmap.getWidth(), borderWidth
-            + aBitmap.getHeight());
-        Bitmap aOut = Bitmap.createBitmap(aBitmap.getWidth() + 2
-            * borderWidth, aBitmap.getHeight() + 2
-            * borderWidth, aBitmap.getConfig());
-        Canvas canvas = new Canvas(aOut);
-        canvas.drawColor(mContext.getResources().getColor(R.color.light_grey));
-        canvas.drawRect(aRect, p);
-        canvas.drawBitmap(aBitmap, null, aRect, null);
-
-        mSlidePreviews.put(aSlideIndex, aOut);
+    public void setSlidePreview(int aSlideIndex, byte[] aSlidePreviewBytes) {
+        Bitmap aSlidePreview = BitmapFactory
+            .decodeByteArray(aSlidePreviewBytes, 0, aSlidePreviewBytes.length);
+
+        mSlidePreviews.put(aSlideIndex, aSlidePreview);
     }
 
     public Bitmap getSlidePreview(int aSlideIndex) {
@@ -95,114 +73,9 @@ public class SlideShow {
         }
     }
 
-    // ---------------------------------------------------- TIMER --------------
-    private Timer mTimer = new Timer();
-
     public Timer getTimer() {
         return mTimer;
     }
-
-    public class Timer {
-        /**
-         * This stores the starting time of the timer if running.
-         * <p/>
-         * If paused this stores how long the timer was previously running.
-         */
-        private long aTime = 0;
-
-        private long mCountdownTime = 0;
-
-        private boolean mIsRunning = false;
-
-        private boolean mIsCountdown = false;
-
-        /**
-         * Set whether this timer should be a normal or a countdown timer.
-         *
-         * @param aIsCountdown Whether this should be a countdown timer.
-         */
-        public void setCountdown(boolean aIsCountdown) {
-            mIsCountdown = aIsCountdown;
-            if (mIsRunning) {
-                mIsRunning = false;
-                aTime = 0;
-            }
-        }
-
-        /**
-         * Set the countdown time. Can be set, and isn't lost, whatever mode
-         * the timer is running in.
-         *
-         * @param aCountdownTime The countdown time.
-         */
-        public void setCountdownTime(long aCountdownTime) {
-            mCountdownTime = aCountdownTime;
-        }
-
-        public long getCountdownTime() {
-            return mCountdownTime;
-        }
-
-        public boolean isCountdown() {
-            return mIsCountdown;
-        }
-
-        public boolean isRunning() {
-            return mIsRunning;
-        }
-
-        /**
-         * Reset the timer, and stop it it was running.
-         */
-        public void reset() {
-            mIsRunning = false;
-            aTime = 0;
-        }
-
-        public void startTimer() {
-            if (mIsRunning)
-                return;
-
-            aTime = System.currentTimeMillis() - aTime;
-            mIsRunning = true;
-        }
-
-        public void stopTimer() {
-            if (!mIsRunning)
-                return;
-
-            aTime = System.currentTimeMillis() - aTime;
-            mIsRunning = false;
-        }
-
-        /**
-         * Get either how long this timer has been running, or how long the
-         * timer still has left to run.
-         *
-         * @return
-         */
-        public long getTimeMillis() {
-            long aTimeRunning;
-            // Determine how long we've been going.
-            if (mIsRunning) {
-                aTimeRunning = System.currentTimeMillis() - aTime;
-            } else {
-                aTimeRunning = aTime;
-            }
-            // And give the time going, or time left
-            if (!mIsCountdown) {
-                return aTimeRunning;
-            } else {
-                long aRet = mCountdownTime - aTimeRunning;
-                if (aRet < 0) { // We have completed!
-                    mIsRunning = false;
-                    aRet = 0;
-                }
-                return aRet;
-            }
-
-        }
-    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Timer.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Timer.java
new file mode 100644
index 0000000..84a7932
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Timer.java
@@ -0,0 +1,124 @@
+/* -*- Mode: Java; 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.communication;
+
+public class Timer {
+    /**
+     * This stores the starting time of the timer if running.
+     * <p/>
+     * If paused this stores how long the timer was previously running.
+     */
+    private long mTime;
+    private long mCountdownTime;
+
+    private boolean mIsRunning;
+    private boolean mIsCountdown;
+
+    public Timer() {
+        mTime = 0;
+        mCountdownTime = 0;
+
+        mIsRunning = false;
+        mIsCountdown = false;
+    }
+
+    /**
+     * Set whether this timer should be a normal or a countdown timer.
+     *
+     * @param aIsCountdown Whether this should be a countdown timer.
+     */
+    public void setCountdown(boolean aIsCountdown) {
+        mIsCountdown = aIsCountdown;
+
+        if (mIsRunning) {
+            reset();
+        }
+    }
+
+    public boolean isCountdown() {
+        return mIsCountdown;
+    }
+
+    /**
+     * Set the countdown time. Can be set, and isn't lost, whatever mode
+     * the timer is running in.
+     *
+     * @param aCountdownTime The countdown time.
+     */
+    public void setCountdownTime(long aCountdownTime) {
+        mCountdownTime = aCountdownTime;
+    }
+
+    public long getCountdownTime() {
+        return mCountdownTime;
+    }
+
+    public boolean isRunning() {
+        return mIsRunning;
+    }
+
+    /**
+     * Reset the timer, and stop it it was running.
+     */
+    public void reset() {
+        mIsRunning = false;
+        mTime = 0;
+    }
+
+    public void start() {
+        if (mIsRunning) {
+            return;
+        }
+
+        mTime = System.currentTimeMillis() - mTime;
+        mIsRunning = true;
+    }
+
+    public void stop() {
+        if (!mIsRunning)
+            return;
+
+        mTime = System.currentTimeMillis() - mTime;
+        mIsRunning = false;
+    }
+
+    /**
+     * Get either how long this timer has been running, or how long the
+     * timer still has left to run.
+     *
+     * @return running time in millis.
+     */
+    public long getTimeMillis() {
+        if (mIsCountdown) {
+            return calculateCountdownRunningTime();
+        }
+
+        return calculateRunningTime();
+    }
+
+    private long calculateCountdownRunningTime() {
+        long aRunningTime = mCountdownTime - calculateRunningTime();
+
+        if (aRunningTime < 0) {
+            reset();
+        }
+
+        return aRunningTime;
+    }
+
+    private long calculateRunningTime() {
+        if (mIsRunning) {
+            return System.currentTimeMillis() - mTime;
+        }
+
+        return mTime;
+    }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list