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

Artur Dryomov artur.dryomov at gmail.com
Sun Jul 14 12:15:14 PDT 2013


 android/sdremote/AndroidManifest.xml                                                         |    6 
 android/sdremote/res/drawable-hdpi/ic_action_add_computer.png                                |binary
 android/sdremote/res/drawable-hdpi/ic_action_cancel.png                                      |binary
 android/sdremote/res/drawable-hdpi/ic_action_save.png                                        |binary
 android/sdremote/res/drawable-mdpi/ic_action_add_computer.png                                |binary
 android/sdremote/res/drawable-mdpi/ic_action_cancel.png                                      |binary
 android/sdremote/res/drawable-mdpi/ic_action_save.png                                        |binary
 android/sdremote/res/drawable-xhdpi/ic_action_add_computer.png                               |binary
 android/sdremote/res/drawable-xhdpi/ic_action_cancel.png                                     |binary
 android/sdremote/res/drawable-xhdpi/ic_action_save.png                                       |binary
 android/sdremote/res/layout-v11/action_bar_computer_creation.xml                             |   50 +
 android/sdremote/res/layout/action_bar_computer_creation.xml                                 |   54 +
 android/sdremote/res/layout/activity_computer_creation.xml                                   |   25 
 android/sdremote/res/menu/menu_action_bar_computers.xml                                      |    6 
 android/sdremote/res/menu/menu_context_computers.xml                                         |    8 
 android/sdremote/res/values/colors.xml                                                       |    2 
 android/sdremote/res/values/dimens.xml                                                       |   10 
 android/sdremote/res/values/strings.xml                                                      |   10 
 android/sdremote/res/values/themes.xml                                                       |   10 
 android/sdremote/src/org/libreoffice/impressremote/ActivityChangeBroadcastProcessor.java     |   14 
 android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java           |    2 
 android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java           |   14 
 android/sdremote/src/org/libreoffice/impressremote/ComputerCreationActivity.java             |  118 +++
 android/sdremote/src/org/libreoffice/impressremote/ComputersActivity.java                    |    2 
 android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java                    |  101 +++
 android/sdremote/src/org/libreoffice/impressremote/Intents.java                              |  122 +++
 android/sdremote/src/org/libreoffice/impressremote/PairingActivity.java                      |    3 
 android/sdremote/src/org/libreoffice/impressremote/Preferences.java                          |    6 
 android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java                 |   12 
 android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java                     |   11 
 android/sdremote/src/org/libreoffice/impressremote/StartPresentationActivity.java            |    2 
 android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java                    |    8 
 android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java |    8 
 android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java   |  308 ++--------
 android/sdremote/src/org/libreoffice/impressremote/communication/PairingProvider.java        |   69 ++
 android/sdremote/src/org/libreoffice/impressremote/communication/Server.java                 |    4 
 android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java         |  116 +++
 android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java       |   13 
 38 files changed, 840 insertions(+), 274 deletions(-)

New commits:
commit a8fbd1a253156f7bd066a83110e1fe61003a727f
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Sun Jul 14 22:07:31 2013 +0300

    Move pairing operations from CommunicationService to a PairingProvider.
    
    Clean up CommunicationService as well.
    
    Change-Id: I0fcea89b2531192869f4e039dba7e06528f22def

diff --git a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
index 7f58b85..57e0cb7 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -27,6 +27,7 @@ import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.content.LocalBroadcastManager;
@@ -229,7 +230,7 @@ public class SelectorActivity extends SherlockActivity {
                         String aFormat = getResources().getString(
                                 R.string.selector_dialog_connectionfailed);
                         String aDialogText = MessageFormat.format(aFormat,
-                                mCommunicationService.getPairingDeviceName());
+                                Build.MODEL);
 
                         AlertDialog.Builder builder = new AlertDialog.Builder(
                                 SelectorActivity.this);
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index c819456..9b2f47a 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -31,37 +31,48 @@ public class CommunicationService extends Service implements Runnable, MessagesL
      */
     private final Object mConnectionVariableMutex = new Object();
 
-    private State mState = State.DISCONNECTED;
-    private State mStateDesired = State.DISCONNECTED;
+    private State mState;
+    private State mStateDesired;
 
-    private Server mServerDesired = null;
+    private Server mServerDesired;
 
-    private final IBinder mBinder = new CBinder();
+    private IBinder mBinder;
 
-    private final ServersManager mServersManager = new ServersManager(this);
+    private ServersManager mServersManager;
 
-    private Thread mThread = null;
+    private ServerConnection mServerConnection;
 
-    /**
-     * Get the publicly visible device name -- generally the bluetooth name,
-     * however for bluetoothless devices the device model name is used.
-     *
-     * @return The device name.
-     */
-    public static String getDeviceName() {
-        if (BluetoothAdapter.getDefaultAdapter() == null) {
-            return Build.MODEL;
-        }
+    private MessagesReceiver mMessagesReceiver;
+    private CommandsTransmitter mCommandsTransmitter;
 
-        if (BluetoothAdapter.getDefaultAdapter().getName() == null) {
-            return Build.MODEL;
-        }
+    private SlideShow mSlideShow;
+
+    private Thread mThread;
+
+    @Override
+    public void onCreate() {
+        mState = State.DISCONNECTED;
+        mStateDesired = State.DISCONNECTED;
+
+        mServerDesired = null;
 
-        return BluetoothAdapter.getDefaultAdapter().getName();
+        mBinder = new CBinder();
+
+        mServersManager = new ServersManager(this);
+
+        mThread = new Thread(this);
+        mThread.start();
+    }
+
+    public class CBinder extends Binder {
+        public CommunicationService getService() {
+            return CommunicationService.this;
+        }
     }
 
-    public String getPairingDeviceName() {
-        return getDeviceName();
+    @Override
+    public IBinder onBind(Intent intent) {
+        return mBinder;
     }
 
     @Override
@@ -101,11 +112,6 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         }
     }
 
-    private ServerConnection mServerConnection;
-
-    private MessagesReceiver mMessagesReceiver;
-    private CommandsTransmitter mCommandsTransmitter;
-
     private void closeConnection() {
         mServerConnection.close();
 
@@ -118,7 +124,7 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         mMessagesReceiver = new MessagesReceiver(mServerConnection, this);
         mCommandsTransmitter = new CommandsTransmitter(mServerConnection);
 
-        if (isPairingNecessary()) {
+        if (PairingProvider.isPairingNecessary(mServerDesired)) {
             pair();
         }
 
@@ -138,29 +144,11 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         }
     }
 
-    private boolean isPairingNecessary() {
-        return mServerDesired.getProtocol() == Server.Protocol.TCP;
-    }
-
     private void pair() {
-        mCommandsTransmitter.pair(getDeviceName(), loadPin());
-    }
-
-    private String loadPin() {
-        if (Preferences.doContain(this,
-            Preferences.Locations.AUTHORIZED_REMOTES,
-            mServerDesired.getAddress())) {
-            return Preferences
-                .getString(this, Preferences.Locations.AUTHORIZED_REMOTES,
-                    mServerDesired.getAddress());
-        }
-
-        String aPin = Protocol.Pin.generate();
-
-        Preferences.set(this, Preferences.Locations.AUTHORIZED_REMOTES,
-            mServerDesired.getAddress(), aPin);
+        String aPairingDeviceName = PairingProvider.getPairingDeviceName(this);
+        String aPairingPin = PairingProvider.getPairingPin(this, mServerDesired);
 
-        return aPin;
+        mCommandsTransmitter.pair(aPairingDeviceName, aPairingPin);
     }
 
     private void connectionFailed() {
@@ -188,6 +176,10 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         }
     }
 
+    public List<Server> getServers() {
+        return mServersManager.getServers();
+    }
+
     public void connectTo(Server aServer) {
         synchronized (mConnectionVariableMutex) {
             if (mState == State.SEARCHING) {
@@ -213,57 +205,32 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         }
     }
 
-    public class CBinder extends Binder {
-        public CommunicationService getService() {
-            return CommunicationService.this;
-        }
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        return mBinder;
-    }
-
-    @Override
-    public void onCreate() {
-        mThread = new Thread(this);
-        mThread.start();
-    }
-
-    @Override
-    public void onDestroy() {
-        stopSearch();
-
-        mThread.interrupt();
-        mThread = null;
-    }
-
     public CommandsTransmitter getTransmitter() {
         return mCommandsTransmitter;
     }
 
-    public List<Server> getServers() {
-        return mServersManager.getServers();
-    }
-
     public SlideShow getSlideShow() {
         return mSlideShow;
     }
 
-    /**
-     * Manually add a new (network) server to the list of servers.
-     */
+    @Deprecated
     public void addServer(String aAddress, String aName, boolean aRemember) {
         mServersManager.addTcpServer(aAddress, aName);
     }
 
+    public void addServer(String aAddress, String aName) {
+        mServersManager.addTcpServer(aAddress, aName);
+    }
+
     public void removeServer(Server aServer) {
         mServersManager.removeServer(aServer);
     }
 
     @Override
     public void onPinValidation() {
-        Intent aIntent = Intents.buildPairingValidationIntent(loadPin());
+        String aPin = PairingProvider.getPairingPin(this, mServerDesired);
+
+        Intent aIntent = Intents.buildPairingValidationIntent(aPin);
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
@@ -273,8 +240,6 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
-    private SlideShow mSlideShow;
-
     @Override
     public void onSlideShowStart(int aSlidesCount, int aCurrentSlideIndex) {
         mSlideShow = new SlideShow();
@@ -317,6 +282,14 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         Intent aIntent = Intents.buildSlideNotesIntent(aSlideIndex);
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
+
+    @Override
+    public void onDestroy() {
+        stopSearch();
+
+        mThread.interrupt();
+        mThread = null;
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/PairingProvider.java b/android/sdremote/src/org/libreoffice/impressremote/communication/PairingProvider.java
new file mode 100644
index 0000000..e6550fb
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/PairingProvider.java
@@ -0,0 +1,69 @@
+package org.libreoffice.impressremote.communication;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.os.Build;
+
+import org.libreoffice.impressremote.Preferences;
+
+public final class PairingProvider {
+    private Context mContext;
+
+    private PairingProvider(Context aContext) {
+        mContext = aContext;
+    }
+
+    public static boolean isPairingNecessary(Server aServer) {
+        return aServer.getProtocol() == Server.Protocol.TCP;
+    }
+
+    public static String getPairingPin(Context aContext, Server aServer) {
+        return new PairingProvider(aContext).getPairingPin(aServer);
+    }
+
+    private String getPairingPin(Server aServer) {
+        if (isPinSaved(aServer)) {
+            return getSavedPin(aServer);
+        }
+
+        String aPin = Protocol.Pin.generate();
+
+        savePin(aServer, aPin);
+
+        return aPin;
+    }
+
+    private boolean isPinSaved(Server aServer) {
+        return getSavedPin(aServer) != null;
+    }
+
+    private String getSavedPin(Server aServer) {
+        String aLocation = Preferences.Locations.AUTHORIZED_REMOTES;
+        String aServerAddress = aServer.getAddress();
+
+        return Preferences.getString(mContext, aLocation, aServerAddress);
+    }
+
+    private void savePin(Server aServer, String aPin) {
+        String aLocation = Preferences.Locations.AUTHORIZED_REMOTES;
+        String aServerAddress = aServer.getAddress();
+
+        Preferences.set(mContext, aLocation, aServerAddress, aPin);
+    }
+
+    public static String getPairingDeviceName(Context aContext) {
+        return new PairingProvider(aContext).getPairingDeviceName();
+    }
+
+    public String getPairingDeviceName() {
+        if (BluetoothAdapter.getDefaultAdapter() == null) {
+            return Build.MODEL;
+        }
+
+        if (BluetoothAdapter.getDefaultAdapter().getName() == null) {
+            return Build.MODEL;
+        }
+
+        return BluetoothAdapter.getDefaultAdapter().getName();
+    }
+}
commit 499037275a37a2ffc785b388f73655a509598ea5
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Sun Jul 14 22:01:38 2013 +0300

    Add adding and removing computers.
    
    Change-Id: I52166bbe848e1b877a91d8ad83859e9f6345c3aa

diff --git a/android/sdremote/AndroidManifest.xml b/android/sdremote/AndroidManifest.xml
index e8225a3..72d692b 100644
--- a/android/sdremote/AndroidManifest.xml
+++ b/android/sdremote/AndroidManifest.xml
@@ -37,6 +37,12 @@
         </activity>
 
         <activity
+            android:name=".ComputerCreationActivity"
+            android:label="Creation"
+            android:theme="@style/Theme.ImpressRemote.ComputerCreation">
+        </activity>
+
+        <activity
             android:name=".SelectorActivity"
             android:label="@string/selector_choose_a_computer"
             android:uiOptions="splitActionBarWhenNarrow">
diff --git a/android/sdremote/res/drawable-hdpi/ic_action_add_computer.png b/android/sdremote/res/drawable-hdpi/ic_action_add_computer.png
new file mode 100755
index 0000000..ad8ada6
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/ic_action_add_computer.png differ
diff --git a/android/sdremote/res/drawable-hdpi/ic_action_cancel.png b/android/sdremote/res/drawable-hdpi/ic_action_cancel.png
new file mode 100755
index 0000000..094eea5
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/ic_action_cancel.png differ
diff --git a/android/sdremote/res/drawable-hdpi/ic_action_save.png b/android/sdremote/res/drawable-hdpi/ic_action_save.png
new file mode 100755
index 0000000..53cf687
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/ic_action_save.png differ
diff --git a/android/sdremote/res/drawable-mdpi/ic_action_add_computer.png b/android/sdremote/res/drawable-mdpi/ic_action_add_computer.png
new file mode 100755
index 0000000..4d5d484
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/ic_action_add_computer.png differ
diff --git a/android/sdremote/res/drawable-mdpi/ic_action_cancel.png b/android/sdremote/res/drawable-mdpi/ic_action_cancel.png
new file mode 100755
index 0000000..3336760
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/ic_action_cancel.png differ
diff --git a/android/sdremote/res/drawable-mdpi/ic_action_save.png b/android/sdremote/res/drawable-mdpi/ic_action_save.png
new file mode 100755
index 0000000..35cda8e
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/ic_action_save.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/ic_action_add_computer.png b/android/sdremote/res/drawable-xhdpi/ic_action_add_computer.png
new file mode 100755
index 0000000..23b9a1c
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/ic_action_add_computer.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/ic_action_cancel.png b/android/sdremote/res/drawable-xhdpi/ic_action_cancel.png
new file mode 100755
index 0000000..f391760
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/ic_action_cancel.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/ic_action_save.png b/android/sdremote/res/drawable-xhdpi/ic_action_save.png
new file mode 100755
index 0000000..b52dc37
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/ic_action_save.png differ
diff --git a/android/sdremote/res/layout-v11/action_bar_computer_creation.xml b/android/sdremote/res/layout-v11/action_bar_computer_creation.xml
new file mode 100644
index 0000000..0c7c5c8
--- /dev/null
+++ b/android/sdremote/res/layout-v11/action_bar_computer_creation.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:divider="?android:attr/dividerVertical"
+              android:showDividers="middle"
+              android:dividerPadding="@dimen/padding_horizontal_action_bar_divider"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/button_cancel"
+        style="?android:actionButtonStyle"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent">
+
+        <TextView
+            style="?android:actionBarTabTextStyle"
+            android:text="@string/button_cancel"
+            android:drawableLeft="@drawable/ic_action_cancel"
+            android:drawablePadding="@dimen/padding_action_bar_button_drawable"
+            android:paddingRight="@dimen/padding_horizontal_action_bar_button"
+            android:gravity="center_vertical"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/button_save"
+        style="?android:actionButtonStyle"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent">
+
+        <TextView
+            style="?android:actionBarTabTextStyle"
+            android:text="@string/button_save"
+            android:drawableLeft="@drawable/ic_action_save"
+            android:drawablePadding="@dimen/padding_action_bar_button_drawable"
+            android:paddingRight="@dimen/padding_horizontal_action_bar_button"
+            android:gravity="center_vertical"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </FrameLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/sdremote/res/layout/action_bar_computer_creation.xml b/android/sdremote/res/layout/action_bar_computer_creation.xml
new file mode 100644
index 0000000..5e6ea36
--- /dev/null
+++ b/android/sdremote/res/layout/action_bar_computer_creation.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <FrameLayout
+        android:id="@+id/button_cancel"
+        style="@style/Widget.Sherlock.ActionButton"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent">
+
+        <TextView
+            style="@style/Widget.Sherlock.ActionBar.TabText"
+            android:text="@string/button_cancel"
+            android:drawableLeft="@drawable/ic_action_cancel"
+            android:drawablePadding="@dimen/padding_action_bar_button_drawable"
+            android:paddingRight="@dimen/padding_horizontal_action_bar_button"
+            android:gravity="center_vertical"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </FrameLayout>
+
+    <View
+        android:layout_width="@dimen/width_action_bar_divider"
+        android:layout_height="match_parent"
+        android:layout_marginTop="@dimen/margin_vertical_action_bar_divider"
+        android:layout_marginBottom="@dimen/margin_vertical_action_bar_divider"
+        android:background="@color/background_action_bar_divider"/>
+
+    <FrameLayout
+        android:id="@+id/button_save"
+        style="@style/Widget.Sherlock.ActionButton"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent">
+
+        <TextView
+            style="@style/Widget.Sherlock.ActionBar.TabText"
+            android:text="@string/button_save"
+            android:drawableLeft="@drawable/ic_action_save"
+            android:drawablePadding="@dimen/padding_action_bar_button_drawable"
+            android:paddingRight="@dimen/padding_horizontal_action_bar_button"
+            android:gravity="center_vertical"
+            android:layout_gravity="center"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"/>
+
+    </FrameLayout>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/sdremote/res/layout/activity_computer_creation.xml b/android/sdremote/res/layout/activity_computer_creation.xml
new file mode 100644
index 0000000..be1f313
--- /dev/null
+++ b/android/sdremote/res/layout/activity_computer_creation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:padding="@dimen/padding_creation_layout"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <EditText
+        android:id="@+id/edit_ip_address"
+        android:singleLine="true"
+        android:inputType="text"
+        android:hint="@string/hint_ip_address"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+    <EditText
+        android:id="@+id/edit_name"
+        android:singleLine="true"
+        android:inputType="text"
+        android:hint="@string/hint_name"
+        android:paddingTop="@dimen/padding_vertical_edit"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/sdremote/res/menu/menu_action_bar_computers.xml b/android/sdremote/res/menu/menu_action_bar_computers.xml
index ee7cfb8..7835fa9 100644
--- a/android/sdremote/res/menu/menu_action_bar_computers.xml
+++ b/android/sdremote/res/menu/menu_action_bar_computers.xml
@@ -2,6 +2,12 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
 
     <item
+        android:id="@+id/menu_add_computer"
+        android:title="@string/menu_add_computer"
+        android:icon="@drawable/ic_action_add_computer"
+        android:showAsAction="always"/>
+
+    <item
         android:id="@+id/menu_licenses"
         android:title="@string/menu_licenses"
         android:showAsAction="never"/>
diff --git a/android/sdremote/res/menu/menu_context_computers.xml b/android/sdremote/res/menu/menu_context_computers.xml
new file mode 100644
index 0000000..d2490c0
--- /dev/null
+++ b/android/sdremote/res/menu/menu_context_computers.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/menu_remove_computer"
+        android:title="@string/menu_remove_computer"/>
+
+</menu>
\ No newline at end of file
diff --git a/android/sdremote/res/values/colors.xml b/android/sdremote/res/values/colors.xml
index 5cbe66a..f15f73b 100644
--- a/android/sdremote/res/values/colors.xml
+++ b/android/sdremote/res/values/colors.xml
@@ -3,6 +3,8 @@
 
     <color name="background_action_bar">#e46f1f</color>
 
+    <color name="background_action_bar_divider">#55ffffff</color>
+
     <color name="orange">#EE4400</color>
     <color name="grey">#303030</color>
     <color name="white">#FFFFFF</color>
diff --git a/android/sdremote/res/values/dimens.xml b/android/sdremote/res/values/dimens.xml
index 4af0408..694e02e 100644
--- a/android/sdremote/res/values/dimens.xml
+++ b/android/sdremote/res/values/dimens.xml
@@ -1,11 +1,21 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
+    <dimen name="padding_action_bar_button_drawable">8dp</dimen>
+    <dimen name="padding_creation_layout">16dp</dimen>
+
     <dimen name="padding_horizontal_list_item">8dp</dimen>
     <dimen name="padding_horizontal_connection_layout">40dp</dimen>
+    <dimen name="padding_horizontal_action_bar_button">20dp</dimen>
+    <dimen name="padding_horizontal_action_bar_divider">12dp</dimen>
 
     <dimen name="padding_vertical_pin">10dp</dimen>
     <dimen name="padding_vertical_error_message">10dp</dimen>
+    <dimen name="padding_vertical_edit">8dp</dimen>
+
+    <dimen name="margin_vertical_action_bar_divider">12dp</dimen>
+
+    <dimen name="width_action_bar_divider">0.5dp</dimen>
 
     <dimen name="text_size_list_item">18sp</dimen>
     <dimen name="text_size_pin">35sp</dimen>
diff --git a/android/sdremote/res/values/strings.xml b/android/sdremote/res/values/strings.xml
index ab3a73b..4e7502d 100644
--- a/android/sdremote/res/values/strings.xml
+++ b/android/sdremote/res/values/strings.xml
@@ -73,11 +73,21 @@
 
     <string name="menu_licenses">Open source licenses</string>
     <string name="menu_reconnect">Reconnect</string>
+    <string name="menu_add_computer">Add computer</string>
+    <string name="menu_remove_computer">Remove</string>
+
+    <string name="button_cancel">Cancel</string>
+    <string name="button_save">Save</string>
 
     <string name="message_impress_pin_validation">Go to “Slide Show → Impress Remote” in LibreOffice Impress and enter the code.</string>
     <string name="message_connection_failed_title">Connection failed</string>
     <string name="message_impress_remote_enabling">Make sure you enabled remote control. Go to “Tools → Options → LibreOffice Impress → General” in LibreOffice Impress.</string>
     <string name="message_impress_wifi_enabling">You should enable experimental features at “Tools → Options → LibreOffice → Advanced” as well.</string>
     <string name="message_impress_pairing_check">If you have Bluetooth pairing issues check instructions related to your desktop OS.</string>
+    <string name="message_ip_address_validation">You should type a valid IP address.</string>
+    <string name="message_name_validation">Name should not be empty.</string>
+
+    <string name="hint_ip_address">IP address</string>
+    <string name="hint_name">Name</string>
 
 </resources>
diff --git a/android/sdremote/res/values/themes.xml b/android/sdremote/res/values/themes.xml
index 2dcde14..21f5be1 100644
--- a/android/sdremote/res/values/themes.xml
+++ b/android/sdremote/res/values/themes.xml
@@ -37,6 +37,16 @@
         <item name="displayOptions">showTitle|showHome|useLogo</item>
     </style>
 
+    <style name="Theme.ImpressRemote.ComputerCreation" parent="Theme.ImpressRemote">
+        <item name="android:actionBarStyle">@style/Theme.ImpressRemote.ComputerCreation.ActionBar</item>
+        <item name="actionBarStyle">@style/Theme.ImpressRemote.ComputerCreation.ActionBar</item>
+    </style>
+
+    <style name="Theme.ImpressRemote.ComputerCreation.ActionBar" parent="Theme.ImpressRemote.ActionBar">
+        <item name="android:displayOptions">showCustom</item>
+        <item name="displayOptions">showCustom</item>
+    </style>
+
     <style name="Theme.ImpressRemote.ActionBarWidget" parent="android:style/Widget.Holo.Light">
         <item name="android:background">@color/orange</item>
         <item name="android:textColor">@color/white</item>
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerCreationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerCreationActivity.java
new file mode 100644
index 0000000..4311ff2
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerCreationActivity.java
@@ -0,0 +1,118 @@
+package org.libreoffice.impressremote;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Patterns;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+
+public class ComputerCreationActivity extends SherlockFragmentActivity implements View.OnClickListener {
+    @Override
+    protected void onCreate(Bundle aSavedInstanceState) {
+        super.onCreate(aSavedInstanceState);
+        setContentView(R.layout.activity_computer_creation);
+
+        setUpActionBar();
+    }
+
+    private void setUpActionBar() {
+        View aView = buildCustomActionBarView();
+        ActionBar.LayoutParams aLayoutParams = buildCustomActionBarLayoutParams();
+
+        getSupportActionBar().setCustomView(aView, aLayoutParams);
+
+        getCancelButton().setOnClickListener(this);
+        getSaveButton().setOnClickListener(this);
+    }
+
+    private View buildCustomActionBarView() {
+        Context aContext = getSupportActionBar().getThemedContext();
+        LayoutInflater aInflater = (LayoutInflater) aContext.getSystemService(
+            LAYOUT_INFLATER_SERVICE);
+
+        return aInflater.inflate(R.layout.action_bar_computer_creation, null);
+    }
+
+    private ActionBar.LayoutParams buildCustomActionBarLayoutParams() {
+        return new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+            ViewGroup.LayoutParams.MATCH_PARENT);
+    }
+
+    private View getCancelButton() {
+        return getSupportActionBar().getCustomView().findViewById(R.id.button_cancel);
+    }
+
+    private View getSaveButton() {
+        return getSupportActionBar().getCustomView().findViewById(R.id.button_save);
+    }
+
+    @Override
+    public void onClick(View aView) {
+        if (aView.equals(getCancelButton())) {
+            cancelCreation();
+
+            return;
+        }
+
+
+        if (aView.equals(getSaveButton())) {
+            saveServer();
+        }
+    }
+
+    private void cancelCreation() {
+        finish();
+    }
+
+    private void saveServer() {
+        String aIpAddress = getText(getIpAddressEdit());
+        String aName = getText(getNameEdit());
+
+        if (!isIpAddressValid(aIpAddress)) {
+            getIpAddressEdit().setError(getText(R.string.message_ip_address_validation));
+        }
+
+        if (TextUtils.isEmpty(aName)) {
+            getNameEdit().setError(getText(R.string.message_name_validation));
+        }
+
+        if (isServerInformationValid(aIpAddress, aName)) {
+            finish(aIpAddress, aName);
+        }
+    }
+
+    private String getText(EditText aEdit) {
+        return aEdit.getText().toString().trim();
+    }
+
+    private EditText getIpAddressEdit() {
+        return (EditText) findViewById(R.id.edit_ip_address);
+    }
+
+    private EditText getNameEdit() {
+        return (EditText) findViewById(R.id.edit_name);
+    }
+
+    private boolean isServerInformationValid(String aIpAddress, String aName) {
+        return isIpAddressValid(aIpAddress) && !TextUtils.isEmpty(aName);
+    }
+
+    private boolean isIpAddressValid(String aIpAddress) {
+        return Patterns.IP_ADDRESS.matcher(aIpAddress).matches();
+    }
+
+    private void finish(String aIpAddress, String aName) {
+        Intent aIntent = Intents.buildComputerCreationResultIntent(aIpAddress, aName);
+        setResult(Activity.RESULT_OK, aIntent);
+
+        finish();
+    }
+}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersActivity.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersActivity.java
index 0a5ea2f..c337c94 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersActivity.java
@@ -75,7 +75,7 @@ public class ComputersActivity extends SherlockFragmentActivity {
     }
 
     private void callLicensesActivity() {
-        Intent aIntent = new Intent(this, LicensesActivity.class);
+        Intent aIntent = Intents.buildLicensesIntent(this);
         startActivity(aIntent);
     }
 }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
index ba17da2..2c294a5 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
@@ -11,6 +11,7 @@ package org.libreoffice.impressremote;
 import java.util.ArrayList;
 import java.util.List;
 
+import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -20,10 +21,14 @@ import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.content.LocalBroadcastManager;
+import android.view.ContextMenu;
 import android.view.View;
+import android.widget.AdapterView;
 import android.widget.ListView;
 
 import com.actionbarsherlock.app.SherlockListFragment;
+import com.actionbarsherlock.internal.view.menu.ActionMenu;
+import com.actionbarsherlock.view.MenuItem;
 import org.libreoffice.impressremote.communication.CommunicationService;
 import org.libreoffice.impressremote.communication.Server;
 
@@ -58,6 +63,12 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
         super.onCreate(savedInstanceState);
 
         mType = (Type) getArguments().getSerializable("TYPE");
+
+        setUpActionBar();
+    }
+
+    private void setUpActionBar() {
+        setHasOptionsMenu(true);
     }
 
     @Override
@@ -227,6 +238,87 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
         Intent aIntent = Intents.buildComputerConnectionIntent(getActivity(), aComputer);
         startActivity(aIntent);
     }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        setUpContextMenu();
+    }
+
+    private void setUpContextMenu() {
+        registerForContextMenu(getListView());
+    }
+
+    @Override
+    public void onCreateContextMenu(ContextMenu aMenu, View aView, ContextMenu.ContextMenuInfo aMenuInfo) {
+        super.onCreateContextMenu(aMenu, aView, aMenuInfo);
+
+        getActivity().getMenuInflater().inflate(R.menu.menu_context_computers, aMenu);
+    }
+
+    @Override
+    public boolean onContextItemSelected(android.view.MenuItem aMenuItem) {
+        int aComputerPosition = getListItemPosition(aMenuItem);
+        Server aComputer = getComputersAdapter().getItem(aComputerPosition);
+
+        removeComputer(aComputer);
+
+        return true;
+    }
+
+    private int getListItemPosition(android.view.MenuItem aMenuItem) {
+        AdapterView.AdapterContextMenuInfo aMenuItemInfo = (AdapterView.AdapterContextMenuInfo) aMenuItem.getMenuInfo();
+
+        return aMenuItemInfo.position;
+    }
+
+    private void removeComputer(Server aComputer) {
+        mCommunicationService.removeServer(aComputer);
+
+        Intent aIntent = Intents.buildServersListChangedIntent();
+        LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(aIntent);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem aMenuItem) {
+        switch (aMenuItem.getItemId()) {
+            case R.id.menu_add_computer:
+                callComputerCreationActivity();
+                return true;
+
+            default:
+                return super.onOptionsItemSelected(aMenuItem);
+        }
+    }
+
+    private void callComputerCreationActivity() {
+        Intent aIntent = new Intent(getActivity(), ComputerCreationActivity.class);
+        startActivityForResult(aIntent, Intents.RequestCodes.CREATE_SERVER);
+    }
+
+    @Override
+    public void onActivityResult(int aRequestCode, int aResultCode, Intent aIntent) {
+        if (aRequestCode != Intents.RequestCodes.CREATE_SERVER) {
+            return;
+        }
+
+        if (aResultCode != Activity.RESULT_OK) {
+            return;
+        }
+
+        String aServerAddress = aIntent.getStringExtra(Intents.Extras.SERVER_ADDRESS);
+        String aServerName = aIntent.getStringExtra(Intents.Extras.SERVER_NAME);
+
+        addServer(aServerAddress, aServerName);
+    }
+
+    private void addServer(String aAddress, String aName) {
+        mCommunicationService.addServer(aAddress, aName);
+
+        Intent aIntent = Intents.buildServersListChangedIntent();
+        LocalBroadcastManager.getInstance(getActivity()).sendBroadcast(aIntent);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/android/sdremote/src/org/libreoffice/impressremote/Intents.java b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
index cbb2b11..93d71cb 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/Intents.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
@@ -36,10 +36,19 @@ public final class Intents {
         public static final String PIN = "PIN";
 
         public static final String SERVER = "SERVER";
+        public static final String SERVER_ADDRESS = "SERVER_ADDRESS";
+        public static final String SERVER_NAME = "SERVER_NAME";
 
         public static final String SLIDE_INDEX = "SLIDE_INDEX";
     }
 
+    public static final class RequestCodes {
+        private RequestCodes() {
+        }
+
+        public static final int CREATE_SERVER = 1;
+    }
+
     public static Intent buildServersListChangedIntent() {
         return new Intent(Actions.SERVERS_LIST_CHANGED);
     }
@@ -94,4 +103,20 @@ public final class Intents {
 
         return aIntent;
     }
+
+    public static Intent buildComputerCreationIntent(Context aContext) {
+        return new Intent(aContext, ComputerCreationActivity.class);
+    }
+
+    public static Intent buildComputerCreationResultIntent(String aAddress, String aName) {
+        Intent aIntent = new Intent();
+        aIntent.putExtra(Extras.SERVER_ADDRESS, aAddress);
+        aIntent.putExtra(Extras.SERVER_NAME, aName);
+
+        return aIntent;
+    }
+
+    public static Intent buildLicensesIntent(Context aContext) {
+        return new Intent(aContext, LicensesActivity.class);
+    }
 }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java
index 22148f7..967ef9d 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java
@@ -86,7 +86,7 @@ public class ServersManager {
     }
 
     public void removeServer(Server aServer) {
-        if (getManualAddedTcpServers().contains(aServer)) {
+        if (getServersAddresses(getManualAddedTcpServers()).contains(aServer.getAddress())) {
             removeManualAddedServer(aServer);
 
             return;
@@ -95,6 +95,16 @@ public class ServersManager {
         blacklistServer(aServer);
     }
 
+    private List<String> getServersAddresses(List<Server> aServers) {
+        List<String> aServersAddresses = new ArrayList<String>();
+
+        for (Server aServer : aServers) {
+            aServersAddresses.add(aServer.getAddress());
+        }
+
+        return aServersAddresses;
+    }
+
     private void removeManualAddedServer(Server aServer) {
         Preferences.remove(mContext, Preferences.Locations.STORED_SERVERS,
             aServer.getAddress());
commit c6d9be41904f52bf2eeb566d4e2faac084dc4117
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Sat Jul 13 01:16:34 2013 +0300

    Remove PAIRING_STARTED intent action.
    
    Replace with PAIRING_VALIDATION. Probably it is better to rely on
    protocol and server.
    
    Change-Id: I5120fe1b2c3a5f48c294fb2c76334c1cd09285a1

diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
index c3df6fe..20d8267 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
@@ -126,8 +126,8 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
         @Override
         public void onReceive(Context aContext, Intent aIntent) {
-            if (Intents.Actions.PAIRING_STARTED.equals(aIntent.getAction())) {
-                String aPin = aIntent.getStringExtra("PIN");
+            if (Intents.Actions.PAIRING_VALIDATION.equals(aIntent.getAction())) {
+                String aPin = aIntent.getStringExtra(Intents.Extras.PIN);
 
                 mComputerConnectionFragment.setUpPinValidationInstructions(aPin);
 
@@ -148,7 +148,7 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
     private IntentFilter buildIntentsReceiverFilter() {
         IntentFilter aIntentFilter = new IntentFilter();
-        aIntentFilter.addAction(Intents.Actions.PAIRING_STARTED);
+        aIntentFilter.addAction(Intents.Actions.PAIRING_VALIDATION);
         aIntentFilter.addAction(Intents.Actions.PAIRING_SUCCESSFUL);
         aIntentFilter.addAction(Intents.Actions.CONNECTION_FAILED);
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/Intents.java b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
index 055af77..cbb2b11 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/Intents.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
@@ -15,7 +15,6 @@ public final class Intents {
 
         public static final String SERVERS_LIST_CHANGED = "SERVERS_LIST_CHANGED";
 
-        public static final String PAIRING_STARTED = "PAIRING_STARTED";
         public static final String PAIRING_SUCCESSFUL = "PAIRING_SUCCESSFUL";
         public static final String PAIRING_VALIDATION = "PAIRING_VALIDATION";
 
@@ -37,7 +36,6 @@ public final class Intents {
         public static final String PIN = "PIN";
 
         public static final String SERVER = "SERVER";
-        public static final String SERVER_NAME = "SERVER_NAME";
 
         public static final String SLIDE_INDEX = "SLIDE_INDEX";
     }
@@ -46,21 +44,13 @@ public final class Intents {
         return new Intent(Actions.SERVERS_LIST_CHANGED);
     }
 
-    public static Intent buildPairingStartedIntent(String aPin) {
-        Intent aIntent = new Intent(Actions.PAIRING_STARTED);
-        aIntent.putExtra(Extras.PIN, aPin);
-
-        return aIntent;
-    }
-
     public static Intent buildPairingSuccessfulIntent() {
         return new Intent(Actions.PAIRING_SUCCESSFUL);
     }
 
-    public static Intent buildPairingValidationIntent(String aPin, String aServerName) {
+    public static Intent buildPairingValidationIntent(String aPin) {
         Intent aIntent = new Intent(Actions.PAIRING_VALIDATION);
         aIntent.putExtra(Extras.PIN, aPin);
-        aIntent.putExtra(Extras.SERVER_NAME, aServerName);
 
         return aIntent;
     }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PairingActivity.java b/android/sdremote/src/org/libreoffice/impressremote/PairingActivity.java
index 45222c0..4e92183 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PairingActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PairingActivity.java
@@ -18,6 +18,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.content.LocalBroadcastManager;
@@ -50,7 +51,7 @@ public class PairingActivity extends SherlockActivity {
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
 
         String aPin = getIntent().getStringExtra("PIN");
-        String aServerName = getIntent().getStringExtra("SERVERNAME");
+        String aServerName = Build.MODEL;
 
         ((TextView) findViewById(R.id.pairing_pin)).setText(aPin);
         ((TextView) findViewById(R.id.pairing_instruction2_deviceName))
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 1a24af5..c819456 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -118,7 +118,9 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         mMessagesReceiver = new MessagesReceiver(mServerConnection, this);
         mCommandsTransmitter = new CommandsTransmitter(mServerConnection);
 
-        pairWithServer();
+        if (isPairingNecessary()) {
+            pair();
+        }
 
         mState = State.CONNECTED;
     }
@@ -136,19 +138,12 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         }
     }
 
-    private void pairWithServer() {
-        if (mServerDesired.getProtocol() == Server.Protocol.BLUETOOTH) {
-            return;
-        }
-
-        mCommandsTransmitter.pair(getDeviceName(), loadPin());
-
-        startPairingActivity();
+    private boolean isPairingNecessary() {
+        return mServerDesired.getProtocol() == Server.Protocol.TCP;
     }
 
-    private void startPairingActivity() {
-        Intent aIntent = Intents.buildPairingStartedIntent(loadPin());
-        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
+    private void pair() {
+        mCommandsTransmitter.pair(getDeviceName(), loadPin());
     }
 
     private String loadPin() {
@@ -268,10 +263,7 @@ public class CommunicationService extends Service implements Runnable, MessagesL
 
     @Override
     public void onPinValidation() {
-        String aPin = loadPin();
-        String aServerName = mServerDesired.getName();
-
-        Intent aIntent = Intents.buildPairingValidationIntent(aPin, aServerName);
+        Intent aIntent = Intents.buildPairingValidationIntent(loadPin());
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
commit 9ff646c936c5499c39b1e7174ad58ec00e5c94f7
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 21:26:18 2013 +0300

    Add static factory for intents.
    
    * Remove intents actions from the CommunicationService.
    * Move all intents extras names to a single place.
    * Move intents creation to a single place.
    
    So we avoid duplications and possible typos.
    
    Change-Id: Ic486727522962763e2fefbf96b65125cf2e3d466

diff --git a/android/sdremote/src/org/libreoffice/impressremote/ActivityChangeBroadcastProcessor.java b/android/sdremote/src/org/libreoffice/impressremote/ActivityChangeBroadcastProcessor.java
index 92003bf..0855423 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ActivityChangeBroadcastProcessor.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ActivityChangeBroadcastProcessor.java
@@ -8,8 +8,6 @@
  */
 package org.libreoffice.impressremote;
 
-import org.libreoffice.impressremote.communication.CommunicationService;
-
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -35,26 +33,26 @@ public class ActivityChangeBroadcastProcessor {
     }
 
     public void addToFilter(IntentFilter aFilter) {
-        aFilter.addAction(CommunicationService.STATUS_CONNECTED_NOSLIDESHOW);
-        aFilter.addAction(CommunicationService.STATUS_CONNECTED_SLIDESHOW_RUNNING);
-        aFilter.addAction(CommunicationService.STATUS_PAIRING_PINVALIDATION);
+        aFilter.addAction(Intents.Actions.SLIDE_SHOW_STOPPED);
+        aFilter.addAction(Intents.Actions.SLIDE_SHOW_RUNNING);
+        aFilter.addAction(Intents.Actions.PAIRING_VALIDATION);
     }
 
     public void onReceive(Context aContext, Intent aIntent) {
         if (aIntent.getAction().equals(
-                        CommunicationService.STATUS_CONNECTED_NOSLIDESHOW)) {
+                        Intents.Actions.SLIDE_SHOW_STOPPED)) {
             Intent nIntent = new Intent(mActivity,
                             StartPresentationActivity.class);
             nIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
             mActivity.startActivity(nIntent);
         } else if (aIntent
                         .getAction()
-                        .equals(CommunicationService.STATUS_CONNECTED_SLIDESHOW_RUNNING)) {
+                        .equals(Intents.Actions.SLIDE_SHOW_RUNNING)) {
             Intent nIntent = new Intent(mActivity, PresentationActivity.class);
             nIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
             mActivity.startActivity(nIntent);
         } else if (aIntent.getAction().equals(
-                        CommunicationService.STATUS_PAIRING_PINVALIDATION)) {
+                Intents.Actions.PAIRING_VALIDATION)) {
             Intent nIntent = new Intent(mActivity, PairingActivity.class);
             nIntent.putExtras(aIntent.getExtras()); // Pass on pin and other info.
             mActivity.startActivity(nIntent);
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
index ac15e2a..aa256bb 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
@@ -30,7 +30,7 @@ public class ComputerConnectionActivity extends SherlockFragmentActivity {
     }
 
     private Server extractReceivedComputer() {
-        return getIntent().getParcelableExtra("COMPUTER");
+        return getIntent().getParcelableExtra(Intents.Extras.SERVER);
     }
 
     @Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
index fd97bed..c3df6fe 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
@@ -126,7 +126,7 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
         @Override
         public void onReceive(Context aContext, Intent aIntent) {
-            if (CommunicationService.MSG_PAIRING_STARTED.equals(aIntent.getAction())) {
+            if (Intents.Actions.PAIRING_STARTED.equals(aIntent.getAction())) {
                 String aPin = aIntent.getStringExtra("PIN");
 
                 mComputerConnectionFragment.setUpPinValidationInstructions(aPin);
@@ -134,13 +134,13 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
                 return;
             }
 
-            if (CommunicationService.MSG_PAIRING_SUCCESSFUL.equals(aIntent.getAction())) {
+            if (Intents.Actions.PAIRING_SUCCESSFUL.equals(aIntent.getAction())) {
                 mComputerConnectionFragment.setUpPresentation();
 
                 return;
             }
 
-            if (CommunicationService.STATUS_CONNECTION_FAILED.equals(aIntent.getAction())) {
+            if (Intents.Actions.CONNECTION_FAILED.equals(aIntent.getAction())) {
                 mComputerConnectionFragment.setUpErrorMessage();
             }
         }
@@ -148,9 +148,9 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
     private IntentFilter buildIntentsReceiverFilter() {
         IntentFilter aIntentFilter = new IntentFilter();
-        aIntentFilter.addAction(CommunicationService.MSG_PAIRING_STARTED);
-        aIntentFilter.addAction(CommunicationService.MSG_PAIRING_SUCCESSFUL);
-        aIntentFilter.addAction(CommunicationService.STATUS_CONNECTION_FAILED);
+        aIntentFilter.addAction(Intents.Actions.PAIRING_STARTED);
+        aIntentFilter.addAction(Intents.Actions.PAIRING_SUCCESSFUL);
+        aIntentFilter.addAction(Intents.Actions.CONNECTION_FAILED);
 
         return aIntentFilter;
     }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
index 5dcb243..ba17da2 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
@@ -131,7 +131,7 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
 
         @Override
         public void onReceive(Context aContext, Intent aIntent) {
-            if (CommunicationService.MSG_SERVERLIST_CHANGED.equals(aIntent.getAction())) {
+            if (Intents.Actions.SERVERS_LIST_CHANGED.equals(aIntent.getAction())) {
                 mComputersFragment.loadComputers();
             }
         }
@@ -139,7 +139,7 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
 
     private IntentFilter buildIntentsReceiverFilter() {
         IntentFilter aIntentFilter = new IntentFilter();
-        aIntentFilter.addAction(CommunicationService.MSG_SERVERLIST_CHANGED);
+        aIntentFilter.addAction(Intents.Actions.SERVERS_LIST_CHANGED);
 
         return aIntentFilter;
     }
@@ -224,8 +224,7 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
     public void onListItemClick(ListView aListView, View aView, int aPosition, long aId) {
         Server aComputer = getComputersAdapter().getItem(aPosition);
 
-        Intent aIntent = new Intent(getActivity(), ComputerConnectionActivity.class);
-        aIntent.putExtra("COMPUTER", aComputer);
+        Intent aIntent = Intents.buildComputerConnectionIntent(getActivity(), aComputer);
         startActivity(aIntent);
     }
 }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/Intents.java b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
new file mode 100644
index 0000000..055af77
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/Intents.java
@@ -0,0 +1,107 @@
+package org.libreoffice.impressremote;
+
+import android.content.Context;
+import android.content.Intent;
+
+import org.libreoffice.impressremote.communication.Server;
+
+public final class Intents {
+    private Intents() {
+    }
+
+    public static final class Actions {
+        private Actions() {
+        }
+
+        public static final String SERVERS_LIST_CHANGED = "SERVERS_LIST_CHANGED";
+
+        public static final String PAIRING_STARTED = "PAIRING_STARTED";
+        public static final String PAIRING_SUCCESSFUL = "PAIRING_SUCCESSFUL";
+        public static final String PAIRING_VALIDATION = "PAIRING_VALIDATION";
+
+        public static final String CONNECTION_FAILED = "CONNECTION_FAILED";
+
+        public static final String SLIDE_SHOW_STARTED = "SLIDE_SHOW_STARTED";
+        public static final String SLIDE_SHOW_RUNNING = "SLIDE_SHOW_RUNNING";
+        public static final String SLIDE_SHOW_STOPPED = "SLIDE_SHOW_STOPPED";
+
+        public static final String SLIDE_CHANGED = "SLIDE_CHANGED";
+        public static final String SLIDE_PREVIEW = "SLIDE_PREVIEW";
+        public static final String SLIDE_NOTES = "SLIDE_NOTES";
+    }
+
+    public static final class Extras {
+        private Extras() {
+        }
+
+        public static final String PIN = "PIN";
+
+        public static final String SERVER = "SERVER";
+        public static final String SERVER_NAME = "SERVER_NAME";
+
+        public static final String SLIDE_INDEX = "SLIDE_INDEX";
+    }
+
+    public static Intent buildServersListChangedIntent() {
+        return new Intent(Actions.SERVERS_LIST_CHANGED);
+    }
+
+    public static Intent buildPairingStartedIntent(String aPin) {
+        Intent aIntent = new Intent(Actions.PAIRING_STARTED);
+        aIntent.putExtra(Extras.PIN, aPin);
+
+        return aIntent;
+    }
+
+    public static Intent buildPairingSuccessfulIntent() {
+        return new Intent(Actions.PAIRING_SUCCESSFUL);
+    }
+
+    public static Intent buildPairingValidationIntent(String aPin, String aServerName) {
+        Intent aIntent = new Intent(Actions.PAIRING_VALIDATION);
+        aIntent.putExtra(Extras.PIN, aPin);
+        aIntent.putExtra(Extras.SERVER_NAME, aServerName);
+
+        return aIntent;
+    }
+
+    public static Intent buildConnectionFailedIntent() {
+        return new Intent(Actions.CONNECTION_FAILED);
+    }
+
+    public static Intent buildSlideShowRunningIntent() {
+        return new Intent(Actions.SLIDE_SHOW_RUNNING);
+    }
+
+    public static Intent buildSlideShowStoppedIntent() {
+        return new Intent(Actions.SLIDE_SHOW_STOPPED);
+    }
+
+    public static Intent buildSlideChangedIntent(int aSlideIndex) {
+        Intent aIntent = new Intent(Actions.SLIDE_CHANGED);
+        aIntent.putExtra(Extras.SLIDE_INDEX, aSlideIndex);
+
+        return aIntent;
+    }
+
+    public static Intent buildSlidePreviewIntent(int aSlideIndex) {
+        Intent aIntent = new Intent(Actions.SLIDE_PREVIEW);
+        aIntent.putExtra(Extras.SLIDE_INDEX, aSlideIndex);
+
+        return aIntent;
+    }
+
+    public static Intent buildSlideNotesIntent(int aSlideIndex) {
+        Intent aIntent = new Intent(Actions.SLIDE_NOTES);
+        aIntent.putExtra(Extras.SLIDE_INDEX, aSlideIndex);
+
+        return aIntent;
+    }
+
+    public static Intent buildComputerConnectionIntent(Context aContext, Server aServer) {
+        Intent aIntent = new Intent(aContext, ComputerConnectionActivity.class);
+        aIntent.putExtra(Extras.SERVER, aServer);
+
+        return aIntent;
+    }
+}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
index 1834c2d..9a3abcb 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/PresentationFragment.java
@@ -127,9 +127,9 @@ public class PresentationFragment extends SherlockFragment {
         }
 
         IntentFilter aFilter = new IntentFilter(
-                        CommunicationService.MSG_SLIDE_CHANGED);
-        aFilter.addAction(CommunicationService.MSG_SLIDE_NOTES);
-        aFilter.addAction(CommunicationService.MSG_SLIDE_PREVIEW);
+                        Intents.Actions.SLIDE_CHANGED);
+        aFilter.addAction(Intents.Actions.SLIDE_NOTES);
+        aFilter.addAction(Intents.Actions.SLIDE_PREVIEW);
         LocalBroadcastManager
                         .getInstance(getActivity().getApplicationContext())
                         .registerReceiver(mListener, aFilter);
@@ -261,7 +261,7 @@ public class PresentationFragment extends SherlockFragment {
             if (mTopView == null || mTopView.getAdapter() == null)
                 return;
             if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SLIDE_CHANGED)) {
+                            Intents.Actions.SLIDE_CHANGED)) {
                 int aSlide = aIntent.getExtras().getInt("slide_number");
 
                 if (aSlide == mTopView.getSelectedItemPosition())
@@ -271,11 +271,11 @@ public class PresentationFragment extends SherlockFragment {
                 }
                 mTopView.setSelection(aSlide, true);
             } else if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SLIDE_PREVIEW)) {
+                            Intents.Actions.SLIDE_PREVIEW)) {
                 ThumbnailAdapter aThumbAdaptor = (ThumbnailAdapter) mTopView.getAdapter();
                 aThumbAdaptor.notifyDataSetChanged();
             } else if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SLIDE_NOTES)) {
+                            Intents.Actions.SLIDE_NOTES)) {
                 int aPosition = aIntent.getExtras().getInt("slide_number");
                 if ( aPosition == mTopView.getSelectedItemPosition() ) {
                     mNotes.loadDataWithBaseURL(null, mCommunicationService.getSlideShow()
diff --git a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
index a3d88da..7f58b85 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/SelectorActivity.java
@@ -66,8 +66,8 @@ public class SelectorActivity extends SherlockActivity {
         if (mCommunicationService != null)
             mCommunicationService.disconnect();
         IntentFilter aFilter = new IntentFilter(
-                        CommunicationService.MSG_SERVERLIST_CHANGED);
-        aFilter.addAction(CommunicationService.STATUS_CONNECTION_FAILED);
+                        Intents.Actions.SERVERS_LIST_CHANGED);
+        aFilter.addAction(Intents.Actions.CONNECTION_FAILED);
 
         mBroadcastProcessor = new ActivityChangeBroadcastProcessor(this);
         mBroadcastProcessor.addToFilter(aFilter);
@@ -217,11 +217,11 @@ public class SelectorActivity extends SherlockActivity {
         @Override
         public void onReceive(Context aContext, Intent aIntent) {
             if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SERVERLIST_CHANGED)) {
+                            Intents.Actions.SERVERS_LIST_CHANGED)) {
                 refreshLists();
                 return;
             } else if (aIntent.getAction().equals(
-                            CommunicationService.STATUS_CONNECTION_FAILED)) {
+                            Intents.Actions.CONNECTION_FAILED)) {
                 if (mProgressDialog != null) {
                     mProgressDialog.dismiss();
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/StartPresentationActivity.java b/android/sdremote/src/org/libreoffice/impressremote/StartPresentationActivity.java
index 163b8fa..5a4af1a 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/StartPresentationActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/StartPresentationActivity.java
@@ -41,7 +41,7 @@ public class StartPresentationActivity extends SherlockActivity {
 
         getSupportActionBar().setDisplayHomeAsUpEnabled(true);
         IntentFilter aFilter = new IntentFilter(
-                        CommunicationService.MSG_SLIDESHOW_STARTED);
+                        Intents.Actions.SLIDE_SHOW_STARTED);
 
         mBroadcastProcessor = new ActivityChangeBroadcastProcessor(this);
         mBroadcastProcessor.addToFilter(aFilter);
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
index 81184df..97948bf 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ThumbnailFragment.java
@@ -61,8 +61,8 @@ public class ThumbnailFragment extends SherlockFragment {
         }
 
         IntentFilter aFilter = new IntentFilter(
-                        CommunicationService.MSG_SLIDE_CHANGED);
-        aFilter.addAction(CommunicationService.MSG_SLIDE_PREVIEW);
+                        Intents.Actions.SLIDE_CHANGED);
+        aFilter.addAction(Intents.Actions.SLIDE_PREVIEW);
         LocalBroadcastManager
                         .getInstance(getActivity().getApplicationContext())
                         .registerReceiver(mListener, aFilter);
@@ -147,11 +147,11 @@ public class ThumbnailFragment extends SherlockFragment {
             if (mGrid == null)
                 return;
             if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SLIDE_CHANGED)) {
+                            Intents.Actions.SLIDE_CHANGED)) {
                 int aSlide = aIntent.getExtras().getInt("slide_number");
                 setSelected(aSlide);
             } else if (aIntent.getAction().equals(
-                            CommunicationService.MSG_SLIDE_PREVIEW)) {
+                            Intents.Actions.SLIDE_PREVIEW)) {
                 mGrid.invalidateViews();
             }
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java
index 93a1f84..7828197 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/BluetoothServersFinder.java
@@ -22,6 +22,7 @@ import android.content.IntentFilter;
 import android.os.Handler;
 import android.support.v4.content.LocalBroadcastManager;
 
+import org.libreoffice.impressremote.Intents;
 import org.libreoffice.impressremote.communication.Server.Protocol;
 
 public class BluetoothServersFinder extends BroadcastReceiver implements ServersFinder, Runnable {
@@ -97,11 +98,8 @@ public class BluetoothServersFinder extends BroadcastReceiver implements Servers
     }
 
     private void callUpdatingServersList() {
-        Intent aServersListUpdatedIntent = new Intent(
-            CommunicationService.MSG_SERVERLIST_CHANGED);
-
-        LocalBroadcastManager.getInstance(mContext)
-            .sendBroadcast(aServersListUpdatedIntent);
+        Intent aIntent = Intents.buildServersListChangedIntent();
+        LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
     }
 
     private void startDiscoveryDelayed() {
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 4309cc5..1a24af5 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -18,6 +18,7 @@ import android.os.Build;
 import android.os.IBinder;
 import android.support.v4.content.LocalBroadcastManager;
 
+import org.libreoffice.impressremote.Intents;
 import org.libreoffice.impressremote.Preferences;
 
 public class CommunicationService extends Service implements Runnable, MessagesListener {
@@ -25,21 +26,6 @@ public class CommunicationService extends Service implements Runnable, MessagesL
         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.
      */
@@ -161,10 +147,8 @@ public class CommunicationService extends Service implements Runnable, MessagesL
     }
 
     private void startPairingActivity() {
-        Intent aPairingIntent = new Intent(MSG_PAIRING_STARTED);
-        aPairingIntent.putExtra("PIN", loadPin());
-
-        LocalBroadcastManager.getInstance(this).sendBroadcast(aPairingIntent);
+        Intent aIntent = Intents.buildPairingStartedIntent(loadPin());
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     private String loadPin() {
@@ -186,8 +170,8 @@ public class CommunicationService extends Service implements Runnable, MessagesL
 
     private void connectionFailed() {
         mState = State.DISCONNECTED;
-        Intent aIntent = new Intent(
-            CommunicationService.STATUS_CONNECTION_FAILED);
+
+        Intent aIntent = Intents.buildConnectionFailedIntent();
         LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
@@ -284,27 +268,17 @@ public class CommunicationService extends Service implements Runnable, MessagesL
 
     @Override
     public void onPinValidation() {
-        startPinValidation();
-    }
-
-    private void startPinValidation() {
-        Intent aPairingIntent = new Intent(STATUS_PAIRING_PINVALIDATION);
-        aPairingIntent.putExtra("PIN", loadPin());
-        aPairingIntent.putExtra("SERVERNAME", mServerDesired.getName());
+        String aPin = loadPin();
+        String aServerName = mServerDesired.getName();
 
-        LocalBroadcastManager.getInstance(this).sendBroadcast(aPairingIntent);
+        Intent aIntent = Intents.buildPairingValidationIntent(aPin, aServerName);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     @Override
     public void onSuccessfulPairing() {
-        callSuccessfulPairing();
-    }
-
-    private void callSuccessfulPairing() {
-        Intent aSuccessfulPairingIntent = new Intent(MSG_PAIRING_SUCCESSFUL);
-
-        LocalBroadcastManager.getInstance(this).sendBroadcast(
-            aSuccessfulPairingIntent);
+        Intent aIntent = Intents.buildPairingSuccessfulIntent();
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     private SlideShow mSlideShow;
@@ -313,61 +287,43 @@ public class CommunicationService extends Service implements Runnable, MessagesL
     public void onSlideShowStart(int aSlidesCount, int aCurrentSlideIndex) {
         mSlideShow = new SlideShow();
         mSlideShow.setSlidesCount(aSlidesCount);
-        mSlideShow.setCurrentSlideIndex(aCurrentSlideIndex);
 
-        Intent aStatusConnectedSlideShowRunningIntent = new Intent(
-            STATUS_CONNECTED_SLIDESHOW_RUNNING);
-        Intent aSlideChangedIntent = new Intent(MSG_SLIDE_CHANGED);
-        aSlideChangedIntent.putExtra("slide_number", aCurrentSlideIndex);
+        Intent aIntent = Intents.buildSlideShowRunningIntent();
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
 
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aStatusConnectedSlideShowRunningIntent);
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aSlideChangedIntent);
+        onSlideChanged(aCurrentSlideIndex);
     }
 
     @Override
     public void onSlideShowFinish() {
         mSlideShow = new SlideShow();
 
-        Intent aStatusConnectedNoSlideShowIntent = new Intent(
-            STATUS_CONNECTED_NOSLIDESHOW);
-
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aStatusConnectedNoSlideShowIntent);
+        Intent aIntent = Intents.buildSlideShowStoppedIntent();
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     @Override
     public void onSlideChanged(int aCurrentSlideIndex) {
         mSlideShow.setCurrentSlideIndex(aCurrentSlideIndex);
 
-        Intent aSlideChangedIntent = new Intent(MSG_SLIDE_CHANGED);
-        aSlideChangedIntent.putExtra("slide_number", aCurrentSlideIndex);
-
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aSlideChangedIntent);
+        Intent aIntent = Intents.buildSlideChangedIntent(aCurrentSlideIndex);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     @Override
     public void onSlidePreview(int aSlideIndex, byte[] aPreview) {
         mSlideShow.setSlidePreview(aSlideIndex, aPreview);
 
-        Intent aSlidePreviewChangedIntent = new Intent(MSG_SLIDE_PREVIEW);
-        aSlidePreviewChangedIntent.putExtra("slide_number", aSlideIndex);
-
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aSlidePreviewChangedIntent);
+        Intent aIntent = Intents.buildSlidePreviewIntent(aSlideIndex);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 
     @Override
     public void onSlideNotes(int aSlideIndex, String aNotes) {
         mSlideShow.setSlideNotes(aSlideIndex, aNotes);
 
-        Intent aSlideNotesChangedIntent = new Intent(MSG_SLIDE_NOTES);
-        aSlideNotesChangedIntent.putExtra("slide_number", aSlideIndex);
-
-        LocalBroadcastManager.getInstance(this)
-            .sendBroadcast(aSlideNotesChangedIntent);
+        Intent aIntent = Intents.buildSlideNotesIntent(aSlideIndex);
+        LocalBroadcastManager.getInstance(this).sendBroadcast(aIntent);
     }
 }
 
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
index bf8f950..ef8f607 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
@@ -29,6 +29,8 @@ import android.content.Intent;
 import android.support.v4.content.LocalBroadcastManager;
 import android.text.TextUtils;
 
+import org.libreoffice.impressremote.Intents;
+
 public class TcpServersFinder implements ServersFinder, Runnable {
     private static final int SEARCH_DELAY_IN_SECONDS = 10;
     private static final int BLOCKING_TIMEOUT_IN_MILLISECONDS = 1000 * 10;
@@ -155,11 +157,8 @@ public class TcpServersFinder implements ServersFinder, Runnable {
     }
 
     private void callUpdatingServersList() {
-        Intent aServersListUpdatedIntent = new Intent(
-            CommunicationService.MSG_SERVERLIST_CHANGED);
-
-        LocalBroadcastManager.getInstance(mContext)
-            .sendBroadcast(aServersListUpdatedIntent);
+        Intent aIntent = Intents.buildServersListChangedIntent();
+        LocalBroadcastManager.getInstance(mContext).sendBroadcast(aIntent);
     }
 
     private void tearDownSearchSocket() {
commit e958e2c27da94affa3e8e3f51731f2437e745acb
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 19:33:10 2013 +0300

    Change TcpServersFinder to handle multiple threads properly.
    
    Change-Id: I6d76e1b25e5d3a38fef0d3702fdb35a11e129946

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
index f5c7492..bf8f950 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
@@ -46,10 +46,14 @@ public class TcpServersFinder implements ServersFinder, Runnable {
         mContext = aContext;
 
         mServers = new HashMap<String, Server>();
+
+        mSearchService = Executors.newSingleThreadScheduledExecutor();
     }
 
     @Override
     public void startSearch() {
+        stopSearch();
+
         mSearchService = Executors.newSingleThreadScheduledExecutor();
         mSearchService.scheduleAtFixedRate(this, 0, SEARCH_DELAY_IN_SECONDS, TimeUnit.SECONDS);
     }
commit 8f8f9edc02b4a85759b0f86fb01896e90e1b1d27
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 19:25:28 2013 +0300

    Add additional loading servers to the UI.
    
    Change-Id: I4866c6398146bd0e83d27c7f2014a0180b0b4540

diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
index 1652e8a..5dcb243 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
@@ -110,6 +110,8 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
     public void onResume() {
         super.onResume();
 
+        loadComputers();
+
         registerIntentsReceiver();
     }
 
commit 5cfd9e0c51dd88c989c52afb6735bce3607faaf1
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 19:24:20 2013 +0300

    Move servers management from the service to a separate class.
    
    Change-Id: I7739bbf961c2783b3699e2bac21fc79eedcf5b26

diff --git a/android/sdremote/src/org/libreoffice/impressremote/Preferences.java b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
index 7bc9e4b..937d706 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/Preferences.java
@@ -8,6 +8,8 @@
  */
 package org.libreoffice.impressremote;
 
+import java.util.Map;
+
 import android.content.Context;
 import android.content.SharedPreferences;
 
@@ -31,6 +33,10 @@ public final class Preferences {
         return aContext.getSharedPreferences(aLocation, Context.MODE_PRIVATE);
     }
 
+    public static Map<String, ?> getAll(Context aContext, String aLocation) {
+        return getPreferences(aContext, aLocation).getAll();
+    }
+
     public static String getString(Context aContext, String aLocation, String aKey) {
         return getPreferences(aContext, aLocation).getString(aKey, null);
     }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index 2c3466e..4309cc5 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -8,20 +8,14 @@
  */
 package org.libreoffice.impressremote.communication;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
 
 import android.app.Service;
 import android.bluetooth.BluetoothAdapter;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
-import android.preference.PreferenceManager;
 import android.support.v4.content.LocalBroadcastManager;
 
 import org.libreoffice.impressremote.Preferences;
@@ -56,23 +50,13 @@ public class CommunicationService extends Service implements Runnable, MessagesL
 
     private Server mServerDesired = null;
 
-    private boolean mBluetoothPreviouslyEnabled;
-
     private final IBinder mBinder = new CBinder();
 
-    private final ServersFinder mTcpServersFinder = new TcpServersFinder(this);
-    private final ServersFinder mBluetoothServersFinder = new BluetoothServersFinder(
-        this);
+    private final ServersManager mServersManager = new ServersManager(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.
      *
@@ -210,36 +194,25 @@ public class CommunicationService extends Service implements Runnable, MessagesL
     public void startSearch() {
         mState = State.SEARCHING;
 
-        mTcpServersFinder.startSearch();
-
-        BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (aAdapter != null) {
-            mBluetoothPreviouslyEnabled = aAdapter.isEnabled();
-
-            if (!mBluetoothPreviouslyEnabled) {
-                aAdapter.enable();
-            }
-
-            mBluetoothServersFinder.startSearch();
+        if (BluetoothAdapter.getDefaultAdapter() != null) {
+            BluetoothAdapter.getDefaultAdapter().enable();
         }
+
+        mServersManager.startServersSearch();
     }
 
     public void stopSearch() {
-        mTcpServersFinder.stopSearch();
-        mBluetoothServersFinder.stopSearch();
-        BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (aAdapter != null) {
-            if (!mBluetoothPreviouslyEnabled) {
-                aAdapter.disable();
-            }
+        mServersManager.stopServersSearch();
+
+        if (BluetoothAdapter.getDefaultAdapter() != null) {
+            BluetoothAdapter.getDefaultAdapter().disable();
         }
     }
 
     public void connectTo(Server aServer) {
         synchronized (mConnectionVariableMutex) {
             if (mState == State.SEARCHING) {
-                mTcpServersFinder.stopSearch();
-                mBluetoothServersFinder.stopSearch();
+                mServersManager.stopServersSearch();
                 mState = State.DISCONNECTED;
             }
             mServerDesired = aServer;
@@ -274,15 +247,13 @@ public class CommunicationService extends Service implements Runnable, MessagesL
 
     @Override
     public void onCreate() {
-        loadServersFromPreferences();
-
         mThread = new Thread(this);
         mThread.start();
     }
 
     @Override
     public void onDestroy() {
-        mManualServers.clear();
+        stopSearch();
 
         mThread.interrupt();
         mThread = null;
@@ -293,58 +264,22 @@ public class CommunicationService extends Service implements Runnable, MessagesL
     }
 
     public List<Server> getServers() {
-        List<Server> aServers = new ArrayList<Server>();
-
-        aServers.addAll(mTcpServersFinder.getServers());
-        aServers.addAll(mBluetoothServersFinder.getServers());
-        aServers.addAll(mManualServers.values());
-
-        return aServers;
+        return mServersManager.getServers();
     }
 
     public SlideShow getSlideShow() {
         return mSlideShow;
     }
 
-    void loadServersFromPreferences() {
-        SharedPreferences aPref = getSharedPreferences(
-            Preferences.Locations.STORED_SERVERS,
-            MODE_PRIVATE);
-
-        @SuppressWarnings("unchecked")
-        Map<String, String> aStoredMap = (Map<String, String>) aPref.getAll();
-
-        for (Entry<String, String> aServerEntry : aStoredMap.entrySet()) {
-            mManualServers.put(aServerEntry.getKey(), new Server(
-                Server.Protocol.TCP, aServerEntry.getKey(),
-                aServerEntry.getValue(), 0));
-        }
-    }
-
     /**
      * Manually add a new (network) server to the list of servers.
      */
     public void addServer(String aAddress, String aName, boolean aRemember) {
-        for (String aServer : mManualServers.keySet()) {
-            if (aServer.equals(aAddress))
-                return;
-        }
-        mManualServers
-            .put(aAddress, new Server(Server.Protocol.TCP, aAddress,
-                aName, 0));
-        if (aRemember) {
-
-            Preferences
-                .set(this, Preferences.Locations.STORED_SERVERS, aAddress,
-                    aName);
-        }
+        mServersManager.addTcpServer(aAddress, aName);
     }
 
     public void removeServer(Server aServer) {
-        mManualServers.remove(aServer.getAddress());
-
-        Preferences.remove(this, Preferences.Locations.STORED_SERVERS,
-            aServer.getAddress());
+        mServersManager.removeServer(aServer);
     }
 
     @Override
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java b/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java
index f51e352..a96ee42 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/Server.java
@@ -43,6 +43,10 @@ public class Server implements Parcelable {
         this.mTimeDiscovered = System.currentTimeMillis();
     }
 
+    public static Server newTcpInstance(String aAddress, String aName) {
+        return new Server(Protocol.TCP, aAddress, aName);
+    }
+
     public Protocol getProtocol() {
         return mProtocol;
     }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java
new file mode 100644
index 0000000..22148f7
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/ServersManager.java
@@ -0,0 +1,106 @@
+package org.libreoffice.impressremote.communication;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import android.content.Context;
+
+import org.libreoffice.impressremote.Preferences;
+
+public class ServersManager {
+    private final Context mContext;
+
+    private final ServersFinder mBluetoothServersFinder;
+    private final ServersFinder mTcpServersFinder;
+
+    private final Set<Server> mBlacklistedServers;
+
+    public ServersManager(Context aContext) {
+        mContext = aContext;
+
+        mBluetoothServersFinder = new BluetoothServersFinder(mContext);
+        mTcpServersFinder = new TcpServersFinder(mContext);
+
+        mBlacklistedServers = new HashSet<Server>();
+    }
+
+    public void startServersSearch() {
+        mBluetoothServersFinder.startSearch();
+        mTcpServersFinder.startSearch();
+    }
+
+    public void stopServersSearch() {
+        mBluetoothServersFinder.stopSearch();
+        mTcpServersFinder.stopSearch();
+    }
+
+    public List<Server> getServers() {
+        List<Server> aServers = new ArrayList<Server>();
+
+        aServers.addAll(mBluetoothServersFinder.getServers());
+        aServers.addAll(mTcpServersFinder.getServers());
+        aServers.addAll(getManualAddedTcpServers());
+
+        return filterBlacklistedServers(aServers);
+    }
+
+    private List<Server> getManualAddedTcpServers() {
+        Map<String, ?> aServersEntries = Preferences
+            .getAll(mContext, Preferences.Locations.STORED_SERVERS);
+
+        return buildTcpServers(aServersEntries);
+    }
+
+    private List<Server> buildTcpServers(Map<String, ?> aServersEntries) {
+        List<Server> aServers = new ArrayList<Server>();
+
+        for (String aServerAddress : aServersEntries.keySet()) {
+            String aServerName = (String) aServersEntries.get(aServerAddress);
+
+            aServers.add(Server.newTcpInstance(aServerAddress, aServerName));
+        }
+
+        return aServers;
+    }
+
+    private List<Server> filterBlacklistedServers(List<Server> aServers) {
+        List<Server> aFilteredServers = new ArrayList<Server>();
+
+        for (Server aServer : aServers) {
+            if (mBlacklistedServers.contains(aServer)) {
+                continue;
+            }
+
+            aFilteredServers.add(aServer);
+        }
+
+        return aFilteredServers;
+    }
+
+    public void addTcpServer(String aAddress, String aName) {
+        Preferences.set(mContext, Preferences.Locations.STORED_SERVERS,
+            aAddress, aName);
+    }
+
+    public void removeServer(Server aServer) {
+        if (getManualAddedTcpServers().contains(aServer)) {
+            removeManualAddedServer(aServer);
+
+            return;
+        }
+
+        blacklistServer(aServer);
+    }
+
+    private void removeManualAddedServer(Server aServer) {
+        Preferences.remove(mContext, Preferences.Locations.STORED_SERVERS,
+            aServer.getAddress());
+    }
+
+    private void blacklistServer(Server aServer) {
+        mBlacklistedServers.add(aServer);
+    }
+}


More information about the Libreoffice-commits mailing list