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

Artur Dryomov artur.dryomov at gmail.com
Thu Jul 11 16:31:14 PDT 2013


 android/sdremote/AndroidManifest.xml                                                       |    5 
 android/sdremote/res/drawable-hdpi/ic_action_reconnect.png                                 |binary
 android/sdremote/res/drawable-mdpi/ic_action_reconnect.png                                 |binary
 android/sdremote/res/drawable-xhdpi/ic_action_reconnect.png                                |binary
 android/sdremote/res/layout/fragment_computer_connection.xml                               |   76 ++
 android/sdremote/res/menu/menu_action_bar_computer_connection.xml                          |   10 
 android/sdremote/res/values/dimens.xml                                                     |    6 
 android/sdremote/res/values/strings.xml                                                    |    8 
 android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java         |   51 +
 android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java         |  264 ++++++++++
 android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java                  |   21 
 android/sdremote/src/org/libreoffice/impressremote/LicensesActivity.java                   |    7 
 android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java |    9 
 android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java     |    6 
 android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java     |   42 -
 15 files changed, 461 insertions(+), 44 deletions(-)

New commits:
commit e78ede74c20fb45a79ed29e19972d3d509ac2617
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 02:01:40 2013 +0300

    Add action bar button for reconnection.
    
    Change-Id: I8729dcd2b179b7301ae85528a615195e907cf443

diff --git a/android/sdremote/res/drawable-hdpi/ic_action_reconnect.png b/android/sdremote/res/drawable-hdpi/ic_action_reconnect.png
new file mode 100755
index 0000000..bb9d855
Binary files /dev/null and b/android/sdremote/res/drawable-hdpi/ic_action_reconnect.png differ
diff --git a/android/sdremote/res/drawable-mdpi/ic_action_reconnect.png b/android/sdremote/res/drawable-mdpi/ic_action_reconnect.png
new file mode 100755
index 0000000..bd611e8
Binary files /dev/null and b/android/sdremote/res/drawable-mdpi/ic_action_reconnect.png differ
diff --git a/android/sdremote/res/drawable-xhdpi/ic_action_reconnect.png b/android/sdremote/res/drawable-xhdpi/ic_action_reconnect.png
new file mode 100755
index 0000000..a7fdc0d
Binary files /dev/null and b/android/sdremote/res/drawable-xhdpi/ic_action_reconnect.png differ
diff --git a/android/sdremote/res/layout/fragment_computer_connection.xml b/android/sdremote/res/layout/fragment_computer_connection.xml
index 7b00456..6ad1290 100644
--- a/android/sdremote/res/layout/fragment_computer_connection.xml
+++ b/android/sdremote/res/layout/fragment_computer_connection.xml
@@ -7,7 +7,7 @@
               android:layout_height="match_parent">
 
     <ProgressBar
-        android:id="@android:id/progress"
+        android:id="@+id/progress_bar"
         style="?android:progressBarStyleLarge"
         android:layout_gravity="center"
         android:layout_width="wrap_content"
diff --git a/android/sdremote/res/menu/menu_action_bar_computer_connection.xml b/android/sdremote/res/menu/menu_action_bar_computer_connection.xml
new file mode 100644
index 0000000..ca8714d
--- /dev/null
+++ b/android/sdremote/res/menu/menu_action_bar_computer_connection.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item
+        android:id="@+id/menu_reconnect"
+        android:title="@string/menu_reconnect"
+        android:icon="@drawable/ic_action_reconnect"
+        android:showAsAction="always"/>
+
+</menu>
\ No newline at end of file
diff --git a/android/sdremote/res/values/strings.xml b/android/sdremote/res/values/strings.xml
index ceffa3e..ab3a73b 100644
--- a/android/sdremote/res/values/strings.xml
+++ b/android/sdremote/res/values/strings.xml
@@ -72,6 +72,7 @@
     <string name="title_connection">Connection</string>
 
     <string name="menu_licenses">Open source licenses</string>
+    <string name="menu_reconnect">Reconnect</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>
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
index 186e20e..fd97bed 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
@@ -13,10 +13,14 @@ import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
+import android.widget.ProgressBar;
 import android.widget.TextView;
 import android.widget.ViewAnimator;
 
 import com.actionbarsherlock.app.SherlockFragment;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
 import org.libreoffice.impressremote.communication.CommunicationService;
 import org.libreoffice.impressremote.communication.Server;
 
@@ -47,6 +51,12 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
         super.onCreate(aSavedInstance);
 
         mComputer = getArguments().getParcelable("COMPUTER");
+
+        setUpActionBarMenu();
+    }
+
+    private void setUpActionBarMenu() {
+        setHasOptionsMenu(true);
     }
 
     @Override
@@ -73,6 +83,14 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
         mCommunicationService = aServiceBinder.getService();
 
+        connectToComputer();
+    }
+
+    private void connectToComputer() {
+        if (!isServiceBound()) {
+            return;
+        }
+
         mCommunicationService.connectTo(mComputer);
     }
 
@@ -189,6 +207,31 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
     }
 
     @Override
+    public void onCreateOptionsMenu(Menu aMenu, MenuInflater aMenuInflater) {
+        aMenuInflater.inflate(R.menu.menu_action_bar_computer_connection, aMenu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem aMenuItem) {
+        switch (aMenuItem.getItemId()) {
+            case R.id.menu_reconnect:
+                showProgressBar();
+                connectToComputer();
+                return true;
+
+            default:
+                return super.onOptionsItemSelected(aMenuItem);
+        }
+    }
+
+    private void showProgressBar() {
+        ViewAnimator aViewAnimator = (ViewAnimator) getView().findViewById(R.id.view_animator);
+        ProgressBar aProgressBar = (ProgressBar) getView().findViewById(R.id.progress_bar);
+
+        aViewAnimator.setDisplayedChild(aViewAnimator.indexOfChild(aProgressBar));
+    }
+
+    @Override
     public void onPause() {
         super.onPause();
 
commit 002229d203979bcd2328d1044892815234398262
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 01:26:58 2013 +0300

    Fix search state declaration at the CommunicationService.
    
    Change-Id: Ib60b68cc9bad42207333738fa238e0dd1ec63588

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
index d85661d..2c3466e 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -208,6 +208,8 @@ public class CommunicationService extends Service implements Runnable, MessagesL
     }
 
     public void startSearch() {
+        mState = State.SEARCHING;
+
         mTcpServersFinder.startSearch();
 
         BluetoothAdapter aAdapter = BluetoothAdapter.getDefaultAdapter();
commit fff0d527e7835bff816118dd5e5005e4c5ef7690
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 01:25:51 2013 +0300

    Change thread usage at TcpServersFinder.
    
    It seems like Executor is a much better solution.
    
    Change-Id: Icbc5ef4fbdc73c159e51acad0e37bf895a5e4a70

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
index ea5e0b5..f5c7492 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/TcpServersFinder.java
@@ -20,6 +20,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Scanner;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 import android.content.Context;
 import android.content.Intent;
@@ -27,7 +30,7 @@ import android.support.v4.content.LocalBroadcastManager;
 import android.text.TextUtils;
 
 public class TcpServersFinder implements ServersFinder, Runnable {
-    private static final int SEARCH_DELAY_IN_MILLISECONDS = 1000 * 10;
+    private static final int SEARCH_DELAY_IN_SECONDS = 10;
     private static final int BLOCKING_TIMEOUT_IN_MILLISECONDS = 1000 * 10;
 
     private static final int SEARCH_RESULT_BUFFER_SIZE = 1024;
@@ -37,8 +40,7 @@ public class TcpServersFinder implements ServersFinder, Runnable {
     private final Map<String, Server> mServers;
 
     private DatagramSocket mSearchSocket;
-    private Thread mSearchResultsListenerThread;
-    private boolean mSearchStopRequested;
+    private ScheduledExecutorService mSearchService;
 
     public TcpServersFinder(Context aContext) {
         mContext = aContext;
@@ -48,27 +50,17 @@ public class TcpServersFinder implements ServersFinder, Runnable {
 
     @Override
     public void startSearch() {
-        if (mSearchResultsListenerThread != null) {
-            return;
-        }
-
-        mSearchStopRequested = false;
-
-        mSearchResultsListenerThread = new Thread(this);
-        mSearchResultsListenerThread.start();
+        mSearchService = Executors.newSingleThreadScheduledExecutor();
+        mSearchService.scheduleAtFixedRate(this, 0, SEARCH_DELAY_IN_SECONDS, TimeUnit.SECONDS);
     }
 
     @Override
     public void run() {
         setUpSearchSocket();
 
-        while (!mSearchStopRequested) {
-            sendSearchCommand();
+        sendSearchCommand();
 
-            listenForSearchResults();
-
-            setUpSearchDelay();
-        }
+        listenForSearchResults();
 
         tearDownSearchSocket();
     }
@@ -166,27 +158,13 @@ public class TcpServersFinder implements ServersFinder, Runnable {
             .sendBroadcast(aServersListUpdatedIntent);
     }
 
-    private void setUpSearchDelay() {
-        try {
-            Thread.sleep(SEARCH_DELAY_IN_MILLISECONDS);
-        } catch (InterruptedException e) {
-            mSearchStopRequested = true;
-        }
-    }
-
     private void tearDownSearchSocket() {
         mSearchSocket.close();
     }
 
     @Override
     public void stopSearch() {
-        if (mSearchResultsListenerThread == null) {
-            return;
-        }
-
-        mSearchStopRequested = true;
-
-        mSearchResultsListenerThread = null;
+        mSearchService.shutdown();
     }
 
     @Override
commit 85a754730c1bf454998360daa49462013ec2a456
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 01:22:18 2013 +0300

    Fix messages receiver possible errors related to thread usage.
    
    Change-Id: I403cee3815a4e2cd70468032dd9c50742262bee3

diff --git a/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java b/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
index b187e24..ab65dd4 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/MessagesReceiver.java
@@ -24,14 +24,12 @@ public class MessagesReceiver implements Runnable {
 
     private final MessagesListener mMessagesListener;
 
-    private final Thread mMessagesListenerThread;
-
     public MessagesReceiver(ServerConnection aServerConnection, MessagesListener aMessagesListener) {
         mMessagesReader = buildMessagesReader(aServerConnection);
 
         mMessagesListener = aMessagesListener;
 
-        mMessagesListenerThread = new Thread(this);
+        Thread mMessagesListenerThread = new Thread(this);
         mMessagesListenerThread.start();
     }
 
@@ -89,7 +87,7 @@ public class MessagesReceiver implements Runnable {
         try {
             return mMessagesReader.readLine();
         } catch (IOException e) {
-            throw new RuntimeException("Unable to read message parameter.");
+            return null;
         }
     }
 
commit 02fca6f45df375f0374f05a25aa3c55be12d4dce
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 01:21:30 2013 +0300

    Fix broadcast manager usage.
    
    Change-Id: Ifa4b461b537e40a65753c49f848dd8e4357e82f7

diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
index 2ed0fab..186e20e 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
@@ -96,7 +96,7 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
         mIntentsReceiver = new IntentsReceiver(this);
         IntentFilter aIntentFilter = buildIntentsReceiverFilter();
 
-        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mIntentsReceiver, aIntentFilter);
+        getBroadcastManager().registerReceiver(mIntentsReceiver, aIntentFilter);
     }
 
     private static class IntentsReceiver extends BroadcastReceiver {
@@ -137,6 +137,12 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
         return aIntentFilter;
     }
 
+    private LocalBroadcastManager getBroadcastManager() {
+        Context aContext = getActivity().getApplicationContext();
+
+        return LocalBroadcastManager.getInstance(aContext);
+    }
+
     public void setUpPinValidationInstructions(String aPin) {
         TextView aPinTextView = (TextView) getView().findViewById(R.id.text_pin);
         aPinTextView.setText(aPin);
@@ -152,8 +158,6 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
     }
 
     public void setUpPresentation() {
-        // TODO: implement
-
         getActivity().finish();
     }
 
@@ -193,7 +197,7 @@ public class ComputerConnectionFragment extends SherlockFragment implements Serv
 
     private void unregisterIntentsReceiver() {
         try {
-            getActivity().unregisterReceiver(mIntentsReceiver);
+            getBroadcastManager().unregisterReceiver(mIntentsReceiver);
         } catch (IllegalArgumentException e) {
             // Receiver not registered.
             // Fixed in Honeycomb: Android’s issue #6191.
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
index 80cf4c0..1652e8a 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
@@ -117,7 +117,7 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
         mIntentsReceiver = new IntentsReceiver(this);
         IntentFilter aIntentFilter = buildIntentsReceiverFilter();
 
-        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mIntentsReceiver, aIntentFilter);
+        getBroadcastManager().registerReceiver(mIntentsReceiver, aIntentFilter);
     }
 
     private static final class IntentsReceiver extends BroadcastReceiver {
@@ -142,6 +142,12 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
         return aIntentFilter;
     }
 
+    private LocalBroadcastManager getBroadcastManager() {
+        Context aContext = getActivity().getApplicationContext();
+
+        return LocalBroadcastManager.getInstance(aContext);
+    }
+
     public void loadComputers() {
         if (!isServiceBound()) {
             return;
@@ -205,7 +211,7 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
 
     private void unregisterIntentsReceiver() {
         try {
-            getActivity().unregisterReceiver(mIntentsReceiver);
+            getBroadcastManager().unregisterReceiver(mIntentsReceiver);
         } catch (IllegalArgumentException e) {
             // Receiver not registered.
             // Fixed in Honeycomb: Android’s issue #6191.
commit 9315c418ea1677f67919f71e7c45264cc1217fcd
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Fri Jul 12 01:18:58 2013 +0300

    Modify up navigation.
    
    * Add such type of navigation to the ComputerConnectionActivity.
    * Remove NavUtils usage. It is not a really clean solution but it keeps
      activities state just right.
    
    Change-Id: I9be70a530c180745fdfb35490b025a683aab6cf5

diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
index e773f51..ac15e2a 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
@@ -4,6 +4,7 @@ import android.os.Bundle;
 import android.support.v4.app.FragmentTransaction;
 
 import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.view.MenuItem;
 import org.libreoffice.impressremote.communication.Server;
 
 public class ComputerConnectionActivity extends SherlockFragmentActivity {
@@ -11,9 +12,15 @@ public class ComputerConnectionActivity extends SherlockFragmentActivity {
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        setUpHomeButton();
+
         setUpComputerConnectionFragment(extractReceivedComputer());
     }
 
+    private void setUpHomeButton() {
+        getSupportActionBar().setHomeButtonEnabled(true);
+    }
+
     private void setUpComputerConnectionFragment(Server aComputer) {
         FragmentTransaction aTransaction = getSupportFragmentManager().beginTransaction();
 
@@ -25,4 +32,20 @@ public class ComputerConnectionActivity extends SherlockFragmentActivity {
     private Server extractReceivedComputer() {
         return getIntent().getParcelableExtra("COMPUTER");
     }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem aMenuItem) {
+        switch (aMenuItem.getItemId()) {
+            case android.R.id.home:
+                navigateUp();
+                return true;
+
+            default:
+                return super.onOptionsItemSelected(aMenuItem);
+        }
+    }
+
+    private void navigateUp() {
+        finish();
+    }
 }
diff --git a/android/sdremote/src/org/libreoffice/impressremote/LicensesActivity.java b/android/sdremote/src/org/libreoffice/impressremote/LicensesActivity.java
index ae97c2f..c4511e1 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/LicensesActivity.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/LicensesActivity.java
@@ -1,9 +1,7 @@
 package org.libreoffice.impressremote;
 
 import android.content.ContentResolver;
-import android.content.Intent;
 import android.os.Bundle;
-import android.support.v4.app.NavUtils;
 import android.webkit.WebView;
 
 import com.actionbarsherlock.app.SherlockActivity;
@@ -50,10 +48,9 @@ public class LicensesActivity extends SherlockActivity {
             default:
                 return super.onOptionsItemSelected(aMenuItem);
         }
-        }
+    }
 
     private void navigateUp() {
-        Intent aIntent = new Intent(this, ComputersActivity.class);
-        NavUtils.navigateUpTo(this, aIntent);
+        finish();
     }
 }
commit 379325fd3a71c2a1a6478cd7b36effb5a67c0f77
Author: Artur Dryomov <artur.dryomov at gmail.com>
Date:   Thu Jul 11 19:56:30 2013 +0300

    Add the computer connection activity.
    
    It shows proper instructions for Bluetooth and WiFi at moment, it should
    be helpful for solving possible issues with the connection process.
    
    Change-Id: Ie81bd211fa2b47e3392e1ef83a52a15ea54fe370

diff --git a/android/sdremote/AndroidManifest.xml b/android/sdremote/AndroidManifest.xml
index 36064da..e8225a3 100644
--- a/android/sdremote/AndroidManifest.xml
+++ b/android/sdremote/AndroidManifest.xml
@@ -32,6 +32,11 @@
         </activity>
 
         <activity
+            android:name=".ComputerConnectionActivity"
+            android:label="@string/title_connection">
+        </activity>
+
+        <activity
             android:name=".SelectorActivity"
             android:label="@string/selector_choose_a_computer"
             android:uiOptions="splitActionBarWhenNarrow">
diff --git a/android/sdremote/res/layout/fragment_computer_connection.xml b/android/sdremote/res/layout/fragment_computer_connection.xml
new file mode 100644
index 0000000..7b00456
--- /dev/null
+++ b/android/sdremote/res/layout/fragment_computer_connection.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ViewAnimator xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/view_animator"
+              android:inAnimation="@android:anim/fade_in"
+              android:outAnimation="@android:anim/fade_out"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <ProgressBar
+        android:id="@android:id/progress"
+        style="?android:progressBarStyleLarge"
+        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <LinearLayout
+        android:id="@+id/layout_pin_validation"
+        android:orientation="vertical"
+        android:paddingLeft="@dimen/padding_horizontal_connection_layout"
+        android:paddingRight="@dimen/padding_horizontal_connection_layout"
+        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:text="@string/message_impress_pin_validation"
+            android:gravity="center_horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+        <TextView
+            android:id="@+id/text_pin"
+            android:textSize="@dimen/text_size_pin"
+            android:gravity="center_horizontal"
+            android:paddingTop="@dimen/padding_vertical_pin"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:id="@+id/layout_error_message"
+        android:orientation="vertical"
+        android:paddingLeft="@dimen/padding_horizontal_connection_layout"
+        android:paddingRight="@dimen/padding_horizontal_connection_layout"
+        android:layout_gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <TextView
+            android:id="@+id/text_error_title"
+            android:text="@string/message_connection_failed_title"
+            android:textStyle="bold"
+            android:textSize="@dimen/text_size_error_title"
+            android:gravity="center_horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+        <TextView
+            android:id="@+id/text_primary_error_message"
+            android:text="@string/message_impress_remote_enabling"
+            android:gravity="center_horizontal"
+            android:paddingTop="@dimen/padding_vertical_error_message"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+        <TextView
+            android:id="@+id/text_secondary_error_message"
+            android:gravity="center_horizontal"
+            android:paddingTop="@dimen/padding_vertical_error_message"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+
+     </LinearLayout>
+
+</ViewAnimator>
\ No newline at end of file
diff --git a/android/sdremote/res/values/dimens.xml b/android/sdremote/res/values/dimens.xml
index 61f9ded..4af0408 100644
--- a/android/sdremote/res/values/dimens.xml
+++ b/android/sdremote/res/values/dimens.xml
@@ -2,7 +2,13 @@
 <resources>
 
     <dimen name="padding_horizontal_list_item">8dp</dimen>
+    <dimen name="padding_horizontal_connection_layout">40dp</dimen>
+
+    <dimen name="padding_vertical_pin">10dp</dimen>
+    <dimen name="padding_vertical_error_message">10dp</dimen>
 
     <dimen name="text_size_list_item">18sp</dimen>
+    <dimen name="text_size_pin">35sp</dimen>
+    <dimen name="text_size_error_title">20sp</dimen>
 
 </resources>
\ No newline at end of file
diff --git a/android/sdremote/res/values/strings.xml b/android/sdremote/res/values/strings.xml
index 865067d..ceffa3e 100644
--- a/android/sdremote/res/values/strings.xml
+++ b/android/sdremote/res/values/strings.xml
@@ -69,7 +69,14 @@
     <string name="title_bluetooth" translatable="false">Bluetooth</string>
     <string name="title_wifi" translatable="false">WiFi</string>
     <string name="title_licenses">Open source licenses</string>
+    <string name="title_connection">Connection</string>
 
     <string name="menu_licenses">Open source licenses</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>
+
 </resources>
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
new file mode 100644
index 0000000..e773f51
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionActivity.java
@@ -0,0 +1,28 @@
+package org.libreoffice.impressremote;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentTransaction;
+
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import org.libreoffice.impressremote.communication.Server;
+
+public class ComputerConnectionActivity extends SherlockFragmentActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setUpComputerConnectionFragment(extractReceivedComputer());
+    }
+
+    private void setUpComputerConnectionFragment(Server aComputer) {
+        FragmentTransaction aTransaction = getSupportFragmentManager().beginTransaction();
+
+        aTransaction.replace(android.R.id.content, ComputerConnectionFragment.newInstance(aComputer));
+
+        aTransaction.commit();
+    }
+
+    private Server extractReceivedComputer() {
+        return getIntent().getParcelableExtra("COMPUTER");
+    }
+}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
new file mode 100644
index 0000000..2ed0fab
--- /dev/null
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputerConnectionFragment.java
@@ -0,0 +1,217 @@
+package org.libreoffice.impressremote;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.v4.content.LocalBroadcastManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.ViewAnimator;
+
+import com.actionbarsherlock.app.SherlockFragment;
+import org.libreoffice.impressremote.communication.CommunicationService;
+import org.libreoffice.impressremote.communication.Server;
+
+public class ComputerConnectionFragment extends SherlockFragment implements ServiceConnection {
+    private Server mComputer;
+
+    private CommunicationService mCommunicationService;
+    private BroadcastReceiver mIntentsReceiver;
+
+    public static ComputerConnectionFragment newInstance(Server aComputer) {
+        ComputerConnectionFragment aFragment = new ComputerConnectionFragment();
+
+        aFragment.setArguments(buildArguments(aComputer));
+
+        return aFragment;
+    }
+
+    private static Bundle buildArguments(Server aComputer) {
+        Bundle aArguments = new Bundle();
+
+        aArguments.putParcelable("COMPUTER", aComputer);
+
+        return aArguments;
+    }
+
+    @Override
+    public void onCreate(Bundle aSavedInstance) {
+        super.onCreate(aSavedInstance);
+
+        mComputer = getArguments().getParcelable("COMPUTER");
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater aInflater, ViewGroup aContainer, Bundle aSavedInstance) {
+        return aInflater.inflate(R.layout.fragment_computer_connection, aContainer, false);
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+
+        bindService();
+    }
+
+    private void bindService() {
+        Intent aServiceIntent = new Intent(getActivity(), CommunicationService.class);
+
+        getActivity().bindService(aServiceIntent, this, Context.BIND_AUTO_CREATE);
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName aComponentName, IBinder aBinder) {
+        CommunicationService.CBinder aServiceBinder = (CommunicationService.CBinder) aBinder;
+
+        mCommunicationService = aServiceBinder.getService();
+
+        mCommunicationService.connectTo(mComputer);
+    }
+
+    private boolean isServiceBound() {
+        return mCommunicationService != null;
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName aComponentName) {
+        mCommunicationService = null;
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        registerIntentsReceiver();
+    }
+
+    private void registerIntentsReceiver() {
+        mIntentsReceiver = new IntentsReceiver(this);
+        IntentFilter aIntentFilter = buildIntentsReceiverFilter();
+
+        LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mIntentsReceiver, aIntentFilter);
+    }
+
+    private static class IntentsReceiver extends BroadcastReceiver {
+        private final ComputerConnectionFragment mComputerConnectionFragment;
+
+        public IntentsReceiver(ComputerConnectionFragment aComputerConnectionFragment) {
+            mComputerConnectionFragment = aComputerConnectionFragment;
+        }
+
+        @Override
+        public void onReceive(Context aContext, Intent aIntent) {
+            if (CommunicationService.MSG_PAIRING_STARTED.equals(aIntent.getAction())) {
+                String aPin = aIntent.getStringExtra("PIN");
+
+                mComputerConnectionFragment.setUpPinValidationInstructions(aPin);
+
+                return;
+            }
+
+            if (CommunicationService.MSG_PAIRING_SUCCESSFUL.equals(aIntent.getAction())) {
+                mComputerConnectionFragment.setUpPresentation();
+
+                return;
+            }
+
+            if (CommunicationService.STATUS_CONNECTION_FAILED.equals(aIntent.getAction())) {
+                mComputerConnectionFragment.setUpErrorMessage();
+            }
+        }
+    }
+
+    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);
+
+        return aIntentFilter;
+    }
+
+    public void setUpPinValidationInstructions(String aPin) {
+        TextView aPinTextView = (TextView) getView().findViewById(R.id.text_pin);
+        aPinTextView.setText(aPin);
+
+        showPinValidationLayout();
+    }
+
+    private void showPinValidationLayout() {
+        ViewAnimator aViewAnimator = (ViewAnimator) getView().findViewById(R.id.view_animator);
+        LinearLayout aValidationLayout = (LinearLayout) getView().findViewById(R.id.layout_pin_validation);
+
+        aViewAnimator.setDisplayedChild(aViewAnimator.indexOfChild(aValidationLayout));
+    }
+
+    public void setUpPresentation() {
+        // TODO: implement
+
+        getActivity().finish();
+    }
+
+    public void setUpErrorMessage() {
+        TextView aSecondaryMessageTextView = (TextView) getView().findViewById(R.id.text_secondary_error_message);
+        aSecondaryMessageTextView.setText(buildSecondaryErrorMessage());
+
+        showErrorMessageLayout();
+    }
+
+    private String buildSecondaryErrorMessage() {
+        switch (mComputer.getProtocol()) {
+            case BLUETOOTH:
+                return getString(R.string.message_impress_pairing_check);
+
+            case TCP:
+                return getString(R.string.message_impress_wifi_enabling);
+
+            default:
+                return "";
+        }
+    }
+
+    private void showErrorMessageLayout() {
+        ViewAnimator aViewAnimator = (ViewAnimator) getView().findViewById(R.id.view_animator);
+        LinearLayout aMessageLayout = (LinearLayout) getView().findViewById(R.id.layout_error_message);
+
+        aViewAnimator.setDisplayedChild(aViewAnimator.indexOfChild(aMessageLayout));
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        unregisterIntentsReceiver();
+    }
+
+    private void unregisterIntentsReceiver() {
+        try {
+            getActivity().unregisterReceiver(mIntentsReceiver);
+        } catch (IllegalArgumentException e) {
+            // Receiver not registered.
+            // Fixed in Honeycomb: Android’s issue #6191.
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+
+        unbindService();
+    }
+
+    private void unbindService() {
+        if (!isServiceBound()) {
+            return;
+        }
+
+        getActivity().unbindService(this);
+    }
+}
diff --git a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
index b776af5..80cf4c0 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/ComputersFragment.java
@@ -20,6 +20,8 @@ import android.content.ServiceConnection;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.support.v4.content.LocalBroadcastManager;
+import android.view.View;
+import android.widget.ListView;
 
 import com.actionbarsherlock.app.SherlockListFragment;
 import org.libreoffice.impressremote.communication.CommunicationService;
@@ -209,6 +211,15 @@ public class ComputersFragment extends SherlockListFragment implements ServiceCo
             // Fixed in Honeycomb: Android’s issue #6191.
         }
     }
+
+    @Override
+    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);
+        startActivity(aIntent);
+    }
 }
 
 /* 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 7718d39..d85661d 100644
--- a/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
+++ b/android/sdremote/src/org/libreoffice/impressremote/communication/CommunicationService.java
@@ -119,7 +119,12 @@ public class CommunicationService extends Service implements Runnable, MessagesL
                     if (mStateDesired == State.CONNECTED) {
                         mState = State.CONNECTING;
 
-                        openConnection();
+                        try {
+                            openConnection();
+                        }
+                        catch (RuntimeException e) {
+                            connectionFailed();
+                        }
                     }
                 }
             }


More information about the Libreoffice-commits mailing list