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