From 94fe037f52bb49b0835ed7bedb587a8409f65a4a Mon Sep 17 00:00:00 2001 From: badaix Date: Wed, 13 Jan 2016 22:51:08 +0100 Subject: [PATCH] added RemoteControl class --- .../java/de/badaix/snapcast/MainActivity.java | 163 ++++++++---------- .../java/de/badaix/snapcast/TcpClient.java | 6 +- .../snapcast/control/RemoteControl.java | 159 +++++++++++++++++ .../badaix/snapcast/control/ServerInfo.java | 4 + .../src/main/res/menu/menu_snapcast.xml | 5 + .../Snapcast/src/main/res/values/strings.xml | 3 +- notes.txt | 2 + 7 files changed, 245 insertions(+), 97 deletions(-) create mode 100644 android/Snapcast/src/main/java/de/badaix/snapcast/control/RemoteControl.java diff --git a/android/Snapcast/src/main/java/de/badaix/snapcast/MainActivity.java b/android/Snapcast/src/main/java/de/badaix/snapcast/MainActivity.java index 42b8bbd2..7d0cba0a 100644 --- a/android/Snapcast/src/main/java/de/badaix/snapcast/MainActivity.java +++ b/android/Snapcast/src/main/java/de/badaix/snapcast/MainActivity.java @@ -29,10 +29,6 @@ import com.google.android.gms.appindexing.Action; import com.google.android.gms.appindexing.AppIndex; import com.google.android.gms.common.api.GoogleApiClient; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -40,9 +36,10 @@ import java.io.InputStream; import java.io.OutputStream; import de.badaix.snapcast.control.ClientInfo; +import de.badaix.snapcast.control.RemoteControl; import de.badaix.snapcast.control.ServerInfo; -public class MainActivity extends AppCompatActivity implements View.OnClickListener, TcpClient.TcpClientListener, ClientInfoItem.ClientInfoItemListener { +public class MainActivity extends AppCompatActivity implements View.OnClickListener, ClientInfoItem.ClientInfoItemListener, RemoteControl.RemoteControlListener { private static final String TAG = "Main"; @@ -56,9 +53,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private NsdManager mNsdManager = null; private String host = ""; private int port = 1704; - private TcpClient tcpClient; + private RemoteControl remoteControl = null; private ClientInfoAdapter clientInfoAdapter; - private ServerInfo serverInfo; /** * ATTENTION: This was auto-generated to implement the App Indexing API. @@ -98,8 +94,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe tvInfo.setText("Sample rate: " + rate + ", buffer size: " + size); } - serverInfo = new ServerInfo(); - clientInfoAdapter = new ClientInfoAdapter(this, serverInfo, this); + clientInfoAdapter = new ClientInfoAdapter(this, this); lvClient.setAdapter(clientInfoAdapter); getSupportActionBar().setSubtitle("Host: no Snapserver found"); @@ -144,6 +139,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe editor.apply(); clientInfoAdapter.setHideOffline(item.isChecked()); return true; + } else if (id == R.id.action_refresh) { + if ((remoteControl != null) && remoteControl.isConnected()) + remoteControl.getServerStatus(); } return super.onOptionsItemSelected(item); @@ -221,26 +219,21 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } else if (view == buttonStop) { stop(); } else if (view == button) { - startTcpClient(); +// startTcpClient(); } } - private void startTcpClient() { - if ((tcpClient == null) || !tcpClient.isConnected()) { - if (tcpClient != null) - tcpClient.stop(); -// Toast.makeText(this, "Connecting", Toast.LENGTH_SHORT).show(); - tcpClient = new TcpClient(this); - tcpClient.start(host, port + 1); - } else { - tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"System.GetStatus\", \"id\": 1}"); - } + private void startRemoteControl() { + if (remoteControl == null) + remoteControl = new RemoteControl(this); + if (!host.isEmpty()) + remoteControl.connect(host, port + 1); } - private void stopTcpClient() { - if ((tcpClient != null) && (tcpClient.isConnected())) - tcpClient.stop(); - tcpClient = null; + private void stopRemoteControl() { + if ((remoteControl != null) && (remoteControl.isConnected())) + remoteControl.disconnect(); + remoteControl = null; } public void initializeDiscoveryListener() { @@ -281,7 +274,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe host = nsdServiceInfo.getHost().getCanonicalHostName(); port = nsdServiceInfo.getPort(); setStatus(host + ":" + port); - startTcpClient(); + startRemoteControl(); mNsdManager.stopServiceDiscovery(mDiscoveryListener); } }); @@ -319,7 +312,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe @Override public void onResume() { super.onResume(); - startTcpClient(); + startRemoteControl(); } @Override @@ -343,7 +336,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe @Override public void onDestroy() { - stopTcpClient(); + stopRemoteControl(); super.onDestroy(); } @@ -367,58 +360,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe client.disconnect(); } - @Override - public void onMessageReceived(TcpClient tcpClient, String message) { - Log.d(TAG, "Msg received: " + message); - try { - boolean needsUpdate = false; - JSONObject json = new JSONObject(message); - if (json.has("id")) { - Log.d(TAG, "ID: " + json.getString("id")); - if ((json.get("result") instanceof JSONObject) && json.getJSONObject("result").has("clients")) { - JSONArray clients = json.getJSONObject("result").getJSONArray("clients"); - for (int i = 0; i < clients.length(); i++) { - final ClientInfo clientInfo = new ClientInfo(clients.getJSONObject(i)); - needsUpdate = serverInfo.addClient(clientInfo) || needsUpdate; - } - } - } else { - Log.d(TAG, "Notification: " + json.getString("method")); - if (json.getString("method").equals("Client.OnUpdate") || - json.getString("method").equals("Client.OnConnect") || - json.getString("method").equals("Client.OnDisconnect")) { - final ClientInfo clientInfo = new ClientInfo(json.getJSONObject("params").getJSONObject("data")); - needsUpdate = serverInfo.addClient(clientInfo); - } - } - if (needsUpdate) - clientInfoAdapter.update(); - - } catch (JSONException e) { - e.printStackTrace(); - } - } - - @Override - public void onConnected(TcpClient tcpClient) { - Log.d(TAG, "onConnected"); - tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"System.GetStatus\", \"id\": 1}"); - } - - @Override - public void onDisconnected(TcpClient tcpClient) { - Log.d(TAG, "onDisconnected"); - } @Override public void onVolumeChanged(ClientInfoItem clientInfoItem, int percent) { ClientInfo client = clientInfoItem.getClientInfo(); - tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"Client.SetVolume\", \"params\": {\"client\": \"" + client.getMac() + "\", \"volume\": " + percent + "}, \"id\": 3}"); + remoteControl.setVolume(client, percent); } public void onMute(ClientInfoItem clientInfoItem, boolean mute) { ClientInfo client = clientInfoItem.getClientInfo(); - tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"Client.SetMute\", \"params\": {\"client\": \"" + client.getMac() + "\", \"mute\": " + mute + "}, \"id\": 3}"); + remoteControl.setMute(client, mute); } @Override @@ -437,22 +388,53 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } if (requestCode == 1) { ClientInfo clientInfo = data.getParcelableExtra("clientInfo"); - tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"Client.SetName\", \"params\": {\"client\": \"" + clientInfo.getMac() + "\", \"name\": \"" + clientInfo.getName() + "\"}, \"id\": 3}"); - if (serverInfo.addClient(clientInfo)) - clientInfoAdapter.update(); + remoteControl.setName(clientInfo, clientInfo.getName()); + clientInfoAdapter.updateClient(clientInfo); } } + @Override + public void onConnected(RemoteControl remoteControl) { + remoteControl.getServerStatus(); + } + + @Override + public void onDisconnected(RemoteControl remoteControl) { + Log.d(TAG, "onDisconnected"); + } + + @Override + public void onClientConnected(RemoteControl remoteControl, ClientInfo clientInfo) { + Log.d(TAG, "onClientConnected"); + clientInfoAdapter.updateClient(clientInfo); + } + + @Override + public void onClientDisconnected(RemoteControl remoteControl, ClientInfo clientInfo) { + Log.d(TAG, "onClientDisconnected"); + clientInfoAdapter.updateClient(clientInfo); + } + + @Override + public void onClientUpdated(RemoteControl remoteControl, ClientInfo clientInfo) { + Log.d(TAG, "onClientUpdated"); + clientInfoAdapter.updateClient(clientInfo); + } + + @Override + public void onServerInfo(RemoteControl remoteControl, ServerInfo serverInfo) { + clientInfoAdapter.update(serverInfo); + } + private class ClientInfoAdapter extends ArrayAdapter { private Context context; private ClientInfoItem.ClientInfoItemListener listener; private boolean hideOffline = false; - private ServerInfo serverInfo; + private ServerInfo serverInfo = new ServerInfo(); - public ClientInfoAdapter(Context context, ServerInfo serverInfo, ClientInfoItem.ClientInfoItemListener listener) { + public ClientInfoAdapter(Context context, ClientInfoItem.ClientInfoItemListener listener) { super(context, 0); this.context = context; - this.serverInfo = serverInfo; this.listener = listener; } @@ -472,27 +454,20 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe return clientInfoItem; } - /* public void addClient(ClientInfo clientInfo) { - if (clientInfo == null) - return; + public void updateClient(final ClientInfo clientInfo) { + if (serverInfo.addClient(clientInfo)) + update(null); + } + + public void update(final ServerInfo serverInfo) { + if (serverInfo != null) + ClientInfoAdapter.this.serverInfo = serverInfo; - for (int i = 0; i < getCount(); i++) { - ClientInfo client = getItem(i); - if (client.getMac().equals(clientInfo.getMac())) { - insert(clientInfo, i); - remove(client); - return; - } - } - add(clientInfo); - } - */ - public void update() { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { clear(); - for (ClientInfo clientInfo : serverInfo.getClientInfos()) { + for (ClientInfo clientInfo : ClientInfoAdapter.this.serverInfo.getClientInfos()) { if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected())) add(clientInfo); } @@ -509,7 +484,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe if (this.hideOffline == hideOffline) return; this.hideOffline = hideOffline; - update(); + update(null); } } } diff --git a/android/Snapcast/src/main/java/de/badaix/snapcast/TcpClient.java b/android/Snapcast/src/main/java/de/badaix/snapcast/TcpClient.java index 003c5383..0b8d2f97 100644 --- a/android/Snapcast/src/main/java/de/badaix/snapcast/TcpClient.java +++ b/android/Snapcast/src/main/java/de/badaix/snapcast/TcpClient.java @@ -111,7 +111,8 @@ public class TcpClient { mBufferIn = new BufferedReader(new InputStreamReader( socket.getInputStream())); - mMessageListener.onConnected(TcpClient.this); + if (mMessageListener != null) + mMessageListener.onConnected(TcpClient.this); // in this while the client listens for the messages sent by the // server @@ -137,7 +138,8 @@ public class TcpClient { // after it is closed, which means a new socket instance has to // be created. socket.close(); - mMessageListener.onDisconnected(TcpClient.this); + if (mMessageListener != null) + mMessageListener.onDisconnected(TcpClient.this); } } catch (Exception e) { diff --git a/android/Snapcast/src/main/java/de/badaix/snapcast/control/RemoteControl.java b/android/Snapcast/src/main/java/de/badaix/snapcast/control/RemoteControl.java new file mode 100644 index 00000000..1c4cb8b8 --- /dev/null +++ b/android/Snapcast/src/main/java/de/badaix/snapcast/control/RemoteControl.java @@ -0,0 +1,159 @@ +package de.badaix.snapcast.control; + +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import de.badaix.snapcast.ClientInfoItem; +import de.badaix.snapcast.TcpClient; + +/** + * Created by johannes on 13.01.16. + */ +public class RemoteControl implements TcpClient.TcpClientListener { + + private static final String TAG = "RC"; + + private TcpClient tcpClient; + private long msgId; + private RemoteControlListener listener; + private ServerInfo serverInfo; + + public interface RemoteControlListener { + void onConnected(RemoteControl remoteControl); + void onDisconnected(RemoteControl remoteControl); + + void onClientConnected(RemoteControl remoteControl, ClientInfo clientInfo); + void onClientDisconnected(RemoteControl remoteControl, ClientInfo clientInfo); + void onClientUpdated(RemoteControl remoteControl, ClientInfo clientInfo); + + void onServerInfo(RemoteControl remoteControl, ServerInfo serverInfo); + } + + + public RemoteControl(RemoteControlListener listener) { + this.listener = listener; + serverInfo = new ServerInfo(); + msgId = 0; + } + + public void connect(final String host, final int port) { + if ((tcpClient != null) && tcpClient.isConnected()) + return; + + tcpClient = new TcpClient(this); + tcpClient.start(host, port); + } + + public void disconnect() { + if ((tcpClient != null) && (tcpClient.isConnected())) + tcpClient.stop(); + tcpClient = null; + } + + public boolean isConnected() { + return ((tcpClient != null) && tcpClient.isConnected()); + } + + @Override + public void onMessageReceived(TcpClient tcpClient, String message) { + Log.d(TAG, "Msg received: " + message); + try { + JSONObject json = new JSONObject(message); + if (json.has("id")) { + Log.d(TAG, "ID: " + json.getString("id")); + if ((json.get("result") instanceof JSONObject) && json.getJSONObject("result").has("clients")) { + serverInfo.clear(); + JSONArray clients = json.getJSONObject("result").getJSONArray("clients"); + for (int i = 0; i < clients.length(); i++) { + final ClientInfo clientInfo = new ClientInfo(clients.getJSONObject(i)); + serverInfo.addClient(clientInfo); + } + if (listener != null) + listener.onServerInfo(this, serverInfo); + } + } else { + String method = json.getString("method"); + Log.d(TAG, "Notification: " + method); + if (method.contains("Client.On")) { + final ClientInfo clientInfo = new ClientInfo(json.getJSONObject("params").getJSONObject("data")); +// serverInfo.addClient(clientInfo); + if (listener != null) { + if (method.equals("Client.OnUpdate")) + listener.onClientUpdated(this, clientInfo); + else if (method.equals("Client.OnConnect")) + listener.onClientConnected(this, clientInfo); + else if (method.equals("Client.OnDisconnect")) + listener.onClientDisconnected(this, clientInfo); + } + } + } + + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @Override + public void onConnected(TcpClient tcpClient) { + Log.d(TAG, "onConnected"); + if (listener != null) + listener.onConnected(this); + } + + @Override + public void onDisconnected(TcpClient tcpClient) { + Log.d(TAG, "onDisconnected"); + if (listener != null) + listener.onDisconnected(this); + } + + private JSONObject jsonRequest(String method, JSONObject params) { + JSONObject request = new JSONObject(); + try { + request.put("jsonrpc", "2.0"); + request.put("method", method); + request.put("id", msgId); + if (params != null) + request.put("params", params); + msgId++; + } catch (JSONException e) { + e.printStackTrace(); + } + return request; + } + + public void getServerStatus() { + JSONObject request = jsonRequest("System.GetStatus", null); + tcpClient.sendMessage(request.toString()); + } + + public void setName(ClientInfo clientInfo, String name) { + try { + JSONObject request = jsonRequest("Client.SetName", new JSONObject("{\"client\": \"" + clientInfo.getMac() + "\", \"name\": " + name + "}")); + tcpClient.sendMessage(request.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public void setVolume(ClientInfo clientInfo, int percent) { + try { + JSONObject request = jsonRequest("Client.SetVolume", new JSONObject("{\"client\": \"" + clientInfo.getMac() + "\", \"volume\": " + percent + "}")); + tcpClient.sendMessage(request.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public void setMute(ClientInfo clientInfo, boolean mute) { + try { + JSONObject request = jsonRequest("Client.SetMute", new JSONObject("{\"client\": \"" + clientInfo.getMac() + "\", \"mute\": " + mute + "}")); + tcpClient.sendMessage(request.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + } +} diff --git a/android/Snapcast/src/main/java/de/badaix/snapcast/control/ServerInfo.java b/android/Snapcast/src/main/java/de/badaix/snapcast/control/ServerInfo.java index a25f225c..c955dae0 100644 --- a/android/Snapcast/src/main/java/de/badaix/snapcast/control/ServerInfo.java +++ b/android/Snapcast/src/main/java/de/badaix/snapcast/control/ServerInfo.java @@ -12,6 +12,10 @@ public class ServerInfo { } + public void clear() { + clientInfos.clear(); + } + public boolean addClient(ClientInfo client) { if (client == null) return false; diff --git a/android/Snapcast/src/main/res/menu/menu_snapcast.xml b/android/Snapcast/src/main/res/menu/menu_snapcast.xml index 06636ca6..6b962f75 100644 --- a/android/Snapcast/src/main/res/menu/menu_snapcast.xml +++ b/android/Snapcast/src/main/res/menu/menu_snapcast.xml @@ -12,6 +12,11 @@ android:orderInCategory="100" android:title="@string/action_scan" app:showAsAction="never" /> + Last seen Latency Client settings - Hide offline + Hide offline clients online + refresh diff --git a/notes.txt b/notes.txt index 698e00e0..27d0bd01 100644 --- a/notes.txt +++ b/notes.txt @@ -45,3 +45,5 @@ git submodule update --init --recursive http://s.evemarket.info/images/gnome/256x256/devices/speaker.png +https://upload.wikimedia.org/wikipedia/commons/3/3f/Mute_Icon.svg +https://upload.wikimedia.org/wikipedia/commons/2/21/Speaker_Icon.svg