added RemoteControl class

This commit is contained in:
badaix 2016-01-13 22:51:08 +01:00
parent 02db46f987
commit 94fe037f52
7 changed files with 245 additions and 97 deletions

View file

@ -29,10 +29,6 @@ import com.google.android.gms.appindexing.Action;
import com.google.android.gms.appindexing.AppIndex; import com.google.android.gms.appindexing.AppIndex;
import com.google.android.gms.common.api.GoogleApiClient; 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.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@ -40,9 +36,10 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import de.badaix.snapcast.control.ClientInfo; import de.badaix.snapcast.control.ClientInfo;
import de.badaix.snapcast.control.RemoteControl;
import de.badaix.snapcast.control.ServerInfo; 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"; private static final String TAG = "Main";
@ -56,9 +53,8 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
private NsdManager mNsdManager = null; private NsdManager mNsdManager = null;
private String host = ""; private String host = "";
private int port = 1704; private int port = 1704;
private TcpClient tcpClient; private RemoteControl remoteControl = null;
private ClientInfoAdapter clientInfoAdapter; private ClientInfoAdapter clientInfoAdapter;
private ServerInfo serverInfo;
/** /**
* ATTENTION: This was auto-generated to implement the App Indexing API. * 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); tvInfo.setText("Sample rate: " + rate + ", buffer size: " + size);
} }
serverInfo = new ServerInfo(); clientInfoAdapter = new ClientInfoAdapter(this, this);
clientInfoAdapter = new ClientInfoAdapter(this, serverInfo, this);
lvClient.setAdapter(clientInfoAdapter); lvClient.setAdapter(clientInfoAdapter);
getSupportActionBar().setSubtitle("Host: no Snapserver found"); getSupportActionBar().setSubtitle("Host: no Snapserver found");
@ -144,6 +139,9 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
editor.apply(); editor.apply();
clientInfoAdapter.setHideOffline(item.isChecked()); clientInfoAdapter.setHideOffline(item.isChecked());
return true; return true;
} else if (id == R.id.action_refresh) {
if ((remoteControl != null) && remoteControl.isConnected())
remoteControl.getServerStatus();
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
@ -221,26 +219,21 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} else if (view == buttonStop) { } else if (view == buttonStop) {
stop(); stop();
} else if (view == button) { } else if (view == button) {
startTcpClient(); // startTcpClient();
} }
} }
private void startTcpClient() { private void startRemoteControl() {
if ((tcpClient == null) || !tcpClient.isConnected()) { if (remoteControl == null)
if (tcpClient != null) remoteControl = new RemoteControl(this);
tcpClient.stop(); if (!host.isEmpty())
// Toast.makeText(this, "Connecting", Toast.LENGTH_SHORT).show(); remoteControl.connect(host, port + 1);
tcpClient = new TcpClient(this);
tcpClient.start(host, port + 1);
} else {
tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"System.GetStatus\", \"id\": 1}");
}
} }
private void stopTcpClient() { private void stopRemoteControl() {
if ((tcpClient != null) && (tcpClient.isConnected())) if ((remoteControl != null) && (remoteControl.isConnected()))
tcpClient.stop(); remoteControl.disconnect();
tcpClient = null; remoteControl = null;
} }
public void initializeDiscoveryListener() { public void initializeDiscoveryListener() {
@ -281,7 +274,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
host = nsdServiceInfo.getHost().getCanonicalHostName(); host = nsdServiceInfo.getHost().getCanonicalHostName();
port = nsdServiceInfo.getPort(); port = nsdServiceInfo.getPort();
setStatus(host + ":" + port); setStatus(host + ":" + port);
startTcpClient(); startRemoteControl();
mNsdManager.stopServiceDiscovery(mDiscoveryListener); mNsdManager.stopServiceDiscovery(mDiscoveryListener);
} }
}); });
@ -319,7 +312,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
startTcpClient(); startRemoteControl();
} }
@Override @Override
@ -343,7 +336,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
@Override @Override
public void onDestroy() { public void onDestroy() {
stopTcpClient(); stopRemoteControl();
super.onDestroy(); super.onDestroy();
} }
@ -367,58 +360,16 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
client.disconnect(); 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 @Override
public void onVolumeChanged(ClientInfoItem clientInfoItem, int percent) { public void onVolumeChanged(ClientInfoItem clientInfoItem, int percent) {
ClientInfo client = clientInfoItem.getClientInfo(); 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) { public void onMute(ClientInfoItem clientInfoItem, boolean mute) {
ClientInfo client = clientInfoItem.getClientInfo(); 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 @Override
@ -437,22 +388,53 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
} }
if (requestCode == 1) { if (requestCode == 1) {
ClientInfo clientInfo = data.getParcelableExtra("clientInfo"); ClientInfo clientInfo = data.getParcelableExtra("clientInfo");
tcpClient.sendMessage("{\"jsonrpc\": \"2.0\", \"method\": \"Client.SetName\", \"params\": {\"client\": \"" + clientInfo.getMac() + "\", \"name\": \"" + clientInfo.getName() + "\"}, \"id\": 3}"); remoteControl.setName(clientInfo, clientInfo.getName());
if (serverInfo.addClient(clientInfo)) clientInfoAdapter.updateClient(clientInfo);
clientInfoAdapter.update();
} }
} }
@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<ClientInfo> { private class ClientInfoAdapter extends ArrayAdapter<ClientInfo> {
private Context context; private Context context;
private ClientInfoItem.ClientInfoItemListener listener; private ClientInfoItem.ClientInfoItemListener listener;
private boolean hideOffline = false; 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); super(context, 0);
this.context = context; this.context = context;
this.serverInfo = serverInfo;
this.listener = listener; this.listener = listener;
} }
@ -472,27 +454,20 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
return clientInfoItem; return clientInfoItem;
} }
/* public void addClient(ClientInfo clientInfo) { public void updateClient(final ClientInfo clientInfo) {
if (clientInfo == null) if (serverInfo.addClient(clientInfo))
return; 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() { MainActivity.this.runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
clear(); clear();
for (ClientInfo clientInfo : serverInfo.getClientInfos()) { for (ClientInfo clientInfo : ClientInfoAdapter.this.serverInfo.getClientInfos()) {
if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected())) if ((clientInfo != null) && (!hideOffline || clientInfo.isConnected()))
add(clientInfo); add(clientInfo);
} }
@ -509,7 +484,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
if (this.hideOffline == hideOffline) if (this.hideOffline == hideOffline)
return; return;
this.hideOffline = hideOffline; this.hideOffline = hideOffline;
update(); update(null);
} }
} }
} }

View file

@ -111,6 +111,7 @@ public class TcpClient {
mBufferIn = new BufferedReader(new InputStreamReader( mBufferIn = new BufferedReader(new InputStreamReader(
socket.getInputStream())); socket.getInputStream()));
if (mMessageListener != null)
mMessageListener.onConnected(TcpClient.this); mMessageListener.onConnected(TcpClient.this);
// in this while the client listens for the messages sent by the // in this while the client listens for the messages sent by the
@ -137,6 +138,7 @@ public class TcpClient {
// after it is closed, which means a new socket instance has to // after it is closed, which means a new socket instance has to
// be created. // be created.
socket.close(); socket.close();
if (mMessageListener != null)
mMessageListener.onDisconnected(TcpClient.this); mMessageListener.onDisconnected(TcpClient.this);
} }

View file

@ -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();
}
}
}

View file

@ -12,6 +12,10 @@ public class ServerInfo {
} }
public void clear() {
clientInfos.clear();
}
public boolean addClient(ClientInfo client) { public boolean addClient(ClientInfo client) {
if (client == null) if (client == null)
return false; return false;

View file

@ -12,6 +12,11 @@
android:orderInCategory="100" android:orderInCategory="100"
android:title="@string/action_scan" android:title="@string/action_scan"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_refresh"
android:orderInCategory="100"
android:title="@string/action_refresh"
app:showAsAction="never" />
<item <item
android:id="@+id/action_hide_offline" android:id="@+id/action_hide_offline"
android:orderInCategory="100" android:orderInCategory="100"

View file

@ -19,7 +19,8 @@
<string name="client_last_seen">Last seen</string> <string name="client_last_seen">Last seen</string>
<string name="client_latency">Latency</string> <string name="client_latency">Latency</string>
<string name="title_activity_client_settings">Client settings</string> <string name="title_activity_client_settings">Client settings</string>
<string name="action_hide_offline">Hide offline</string> <string name="action_hide_offline">Hide offline clients</string>
<string name="online">online</string> <string name="online">online</string>
<string name="action_refresh">refresh</string>
</resources> </resources>

View file

@ -45,3 +45,5 @@ git submodule update --init --recursive
http://s.evemarket.info/images/gnome/256x256/devices/speaker.png 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