2015-01-14 12:12:47 +01:00
|
|
|
/*
|
|
|
|
* Copyright 2015 Synced Synapse. All rights reserved.
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
2015-03-09 22:35:18 +01:00
|
|
|
package org.xbmc.kore.host;
|
2015-01-14 12:12:47 +01:00
|
|
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
import android.content.Context;
|
|
|
|
import android.database.Cursor;
|
|
|
|
import android.net.Uri;
|
|
|
|
|
|
|
|
import com.squareup.picasso.Picasso;
|
2015-03-09 22:35:18 +01:00
|
|
|
import org.xbmc.kore.Settings;
|
|
|
|
import org.xbmc.kore.jsonrpc.HostConnection;
|
|
|
|
import org.xbmc.kore.provider.MediaContract;
|
|
|
|
import org.xbmc.kore.utils.BasicAuthPicassoDownloader;
|
|
|
|
import org.xbmc.kore.utils.LogUtils;
|
2015-01-14 12:12:47 +01:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Manages XBMC Hosts
|
|
|
|
* Singleton that loads the list of registered hosts, keeps a
|
|
|
|
* {@link HostConnection} to the active host
|
|
|
|
* and allows for creation and removal of hosts
|
|
|
|
*/
|
|
|
|
public class HostManager {
|
|
|
|
private static final String TAG = LogUtils.makeLogTag(HostManager.class);
|
|
|
|
|
|
|
|
// Singleton instance
|
|
|
|
private static volatile HostManager instance = null;
|
|
|
|
|
|
|
|
private Context context;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Arraylist that will hold all the hosts in the database
|
|
|
|
*/
|
|
|
|
private ArrayList<HostInfo> hosts = new ArrayList<HostInfo>();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current host
|
|
|
|
*/
|
|
|
|
private HostInfo currentHostInfo = null;
|
|
|
|
/**
|
|
|
|
* Current host connection
|
|
|
|
*/
|
|
|
|
private HostConnection currentHostConnection = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Picasso to download images from current XBMC
|
|
|
|
*/
|
|
|
|
private Picasso currentPicasso = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Current connection observer
|
|
|
|
*/
|
|
|
|
private HostConnectionObserver currentHostConnectionObserver = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Singleton constructor
|
|
|
|
* @param context Context (can pass Activity context, will get App Context)
|
|
|
|
*/
|
|
|
|
protected HostManager(Context context) {
|
|
|
|
this.context = context.getApplicationContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Singleton access method
|
|
|
|
* @param context Android app context
|
|
|
|
* @return HostManager singleton
|
|
|
|
*/
|
|
|
|
public static HostManager getInstance(Context context) {
|
|
|
|
if (instance == null) {
|
|
|
|
synchronized (HostManager.class) {
|
|
|
|
if (instance == null) {
|
|
|
|
instance = new HostManager(context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current host list
|
|
|
|
* @return Host list
|
|
|
|
*/
|
|
|
|
public ArrayList<HostInfo> getHosts() {
|
|
|
|
return getHosts(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current host list, maybe forcing a reload from the database
|
|
|
|
* @param forcedReload Whether to force a reload from the database
|
|
|
|
* @return Host list
|
|
|
|
*/
|
|
|
|
public ArrayList<HostInfo> getHosts(boolean forcedReload) {
|
|
|
|
if (forcedReload || (hosts.size() == 0)) {
|
|
|
|
hosts.clear();
|
|
|
|
|
|
|
|
Cursor cursor = context.getContentResolver()
|
|
|
|
.query(MediaContract.Hosts.CONTENT_URI,
|
|
|
|
MediaContract.Hosts.ALL_COLUMNS,
|
|
|
|
null, null, null);
|
|
|
|
|
|
|
|
if (cursor.getCount() > 0) {
|
|
|
|
while (cursor.moveToNext()) {
|
|
|
|
int idx = 0;
|
|
|
|
int id = cursor.getInt(idx++);
|
|
|
|
long updated = cursor.getLong(idx++);
|
|
|
|
String name = cursor.getString(idx++);
|
|
|
|
String address = cursor.getString(idx++);
|
|
|
|
int protocol = cursor.getInt(idx++);
|
|
|
|
int httpPort = cursor.getInt(idx++);
|
|
|
|
int tcpPort = cursor.getInt(idx++);
|
|
|
|
String username = cursor.getString(idx++);
|
|
|
|
String password = cursor.getString(idx++);
|
|
|
|
String macAddress = cursor.getString(idx++);
|
|
|
|
int wolPort = cursor.getInt(idx++);
|
|
|
|
|
|
|
|
hosts.add(new HostInfo(id, name, address, protocol, httpPort, tcpPort,
|
|
|
|
username, password, macAddress, wolPort));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cursor.close();
|
|
|
|
}
|
|
|
|
return hosts;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current active host info
|
|
|
|
* @return Active host info
|
|
|
|
*/
|
|
|
|
public HostInfo getHostInfo() {
|
|
|
|
if (currentHostInfo == null) {
|
|
|
|
Settings settings = Settings.getInstance(context);
|
|
|
|
ArrayList<HostInfo> hosts = getHosts();
|
|
|
|
|
|
|
|
// No host selected. Check if there are hosts configured and default to the first one
|
|
|
|
if (settings.currentHostId == -1) {
|
|
|
|
if (hosts.size() > 0) {
|
|
|
|
currentHostInfo = hosts.get(0);
|
|
|
|
settings.currentHostId = currentHostInfo.getId();
|
|
|
|
settings.save();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (HostInfo host : hosts) {
|
|
|
|
if (host.getId() == settings.currentHostId) {
|
|
|
|
currentHostInfo = host;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentHostInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current active host connection
|
|
|
|
* @return Active host connection
|
|
|
|
*/
|
|
|
|
public HostConnection getConnection() {
|
|
|
|
if (currentHostConnection == null) {
|
|
|
|
currentHostInfo = getHostInfo();
|
|
|
|
|
|
|
|
if (currentHostInfo != null) {
|
|
|
|
currentHostConnection = new HostConnection(currentHostInfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentHostConnection;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current host {@link Picasso} image downloader
|
|
|
|
* @return {@link Picasso} instance suitable to download images from the current xbmc
|
|
|
|
*/
|
|
|
|
public Picasso getPicasso() {
|
|
|
|
if (currentPicasso == null) {
|
|
|
|
currentHostInfo = getHostInfo();
|
|
|
|
if (currentHostInfo != null) {
|
|
|
|
currentPicasso = new Picasso.Builder(context)
|
|
|
|
.downloader(new BasicAuthPicassoDownloader(context,
|
|
|
|
currentHostInfo.getUsername(), currentHostInfo.getPassword()))
|
|
|
|
.build();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentPicasso;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the current {@link HostConnectionObserver} for the current connection
|
|
|
|
* @return The {@link HostConnectionObserver} for the current connection
|
|
|
|
*/
|
|
|
|
public HostConnectionObserver getHostConnectionObserver() {
|
|
|
|
if (currentHostConnectionObserver == null) {
|
|
|
|
currentHostConnection = getConnection();
|
|
|
|
if (currentHostConnection != null) {
|
|
|
|
currentHostConnectionObserver = new HostConnectionObserver(currentHostConnection);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return currentHostConnectionObserver;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the current host.
|
|
|
|
* @param hostInfo Host info
|
|
|
|
*/
|
|
|
|
public void switchHost(HostInfo hostInfo) {
|
|
|
|
releaseCurrentHost();
|
|
|
|
|
|
|
|
currentHostInfo = hostInfo;
|
|
|
|
if (currentHostInfo != null) {
|
|
|
|
Settings settings = Settings.getInstance(context);
|
|
|
|
settings.currentHostId = currentHostInfo.getId();
|
|
|
|
settings.save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// /**
|
|
|
|
// * Sets the current host.
|
|
|
|
// * Throws {@link java.lang.IllegalArgumentException} if the host doesn't exist
|
|
|
|
// * @param hostId Host id
|
|
|
|
// */
|
|
|
|
// public void switchHost(int hostId) {
|
|
|
|
// ArrayList<HostInfo> hosts = getHosts();
|
|
|
|
// HostInfo newHostInfo = null;
|
|
|
|
//
|
|
|
|
// for (HostInfo host : hosts) {
|
|
|
|
// if (host.getId() == hostId) {
|
|
|
|
// newHostInfo = host;
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// if (newHostInfo == null) {
|
|
|
|
// throw new IllegalArgumentException("Host doesn't exist!");
|
|
|
|
// }
|
|
|
|
// switchHost(newHostInfo);
|
|
|
|
// }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a new XBMC host to the database
|
|
|
|
* @param hostInfo Host to add
|
2015-03-09 22:35:18 +01:00
|
|
|
* @return Newly created {@link org.xbmc.kore.host.HostInfo}
|
2015-01-14 12:12:47 +01:00
|
|
|
*/
|
|
|
|
public HostInfo addHost(HostInfo hostInfo) {
|
|
|
|
return addHost(hostInfo.getName(), hostInfo.getAddress(), hostInfo.getProtocol(),
|
|
|
|
hostInfo.getHttpPort(), hostInfo.getTcpPort(),
|
|
|
|
hostInfo.getUsername(), hostInfo.getPassword(),
|
|
|
|
hostInfo.getMacAddress(), hostInfo.getWolPort());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a new XBMC host to the database
|
|
|
|
* @param name Name of this instance
|
|
|
|
* @param address Hostname or IP Address
|
|
|
|
* @param protocol Protocol to use
|
|
|
|
* @param httpPort HTTP port
|
|
|
|
* @param tcpPort TCP port
|
|
|
|
* @param username Username for HTTP
|
|
|
|
* @param password Password for HTTP
|
2015-03-09 22:35:18 +01:00
|
|
|
* @return Newly created {@link org.xbmc.kore.host.HostInfo}
|
2015-01-14 12:12:47 +01:00
|
|
|
*/
|
|
|
|
public HostInfo addHost(String name, String address, int protocol, int httpPort, int tcpPort,
|
|
|
|
String username, String password, String macAddress, int wolPort) {
|
|
|
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
values.put(MediaContract.HostsColumns.NAME, name);
|
|
|
|
values.put(MediaContract.HostsColumns.ADDRESS, address);
|
|
|
|
values.put(MediaContract.HostsColumns.PROTOCOL, protocol);
|
|
|
|
values.put(MediaContract.HostsColumns.HTTP_PORT, httpPort);
|
|
|
|
values.put(MediaContract.HostsColumns.TCP_PORT, tcpPort);
|
|
|
|
values.put(MediaContract.HostsColumns.USERNAME, username);
|
|
|
|
values.put(MediaContract.HostsColumns.PASSWORD, password);
|
|
|
|
values.put(MediaContract.HostsColumns.MAC_ADDRESS, macAddress);
|
|
|
|
values.put(MediaContract.HostsColumns.WOL_PORT, wolPort);
|
|
|
|
|
|
|
|
Uri newUri = context.getContentResolver()
|
|
|
|
.insert(MediaContract.Hosts.CONTENT_URI, values);
|
|
|
|
long newId = Long.valueOf(MediaContract.Hosts.getHostId(newUri));
|
|
|
|
|
|
|
|
// Refresh the list and return the created host
|
|
|
|
hosts = getHosts(true);
|
|
|
|
HostInfo newHost = null;
|
|
|
|
for (HostInfo host : hosts) {
|
|
|
|
if (host.getId() == newId) {
|
|
|
|
newHost = host;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newHost;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Edits a host on the database
|
|
|
|
* @param hostId Id of the host to edit
|
|
|
|
* @param newHostInfo New values to update
|
|
|
|
* @return New {@link HostInfo} object
|
|
|
|
*/
|
|
|
|
public HostInfo editHost(int hostId, HostInfo newHostInfo) {
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
values.put(MediaContract.HostsColumns.NAME, newHostInfo.getName());
|
|
|
|
values.put(MediaContract.HostsColumns.ADDRESS, newHostInfo.getAddress());
|
|
|
|
values.put(MediaContract.HostsColumns.PROTOCOL, newHostInfo.getProtocol());
|
|
|
|
values.put(MediaContract.HostsColumns.HTTP_PORT, newHostInfo.getHttpPort());
|
|
|
|
values.put(MediaContract.HostsColumns.TCP_PORT, newHostInfo.getTcpPort());
|
|
|
|
values.put(MediaContract.HostsColumns.USERNAME, newHostInfo.getUsername());
|
|
|
|
values.put(MediaContract.HostsColumns.PASSWORD, newHostInfo.getPassword());
|
|
|
|
values.put(MediaContract.HostsColumns.MAC_ADDRESS, newHostInfo.getMacAddress());
|
|
|
|
values.put(MediaContract.HostsColumns.WOL_PORT, newHostInfo.getWolPort());
|
|
|
|
|
|
|
|
context.getContentResolver()
|
|
|
|
.update(MediaContract.Hosts.buildHostUri(hostId), values, null, null);
|
|
|
|
|
|
|
|
// Refresh the list and return the created host
|
|
|
|
hosts = getHosts(true);
|
|
|
|
HostInfo newHost = null;
|
|
|
|
for (HostInfo host : hosts) {
|
|
|
|
if (host.getId() == hostId) {
|
|
|
|
newHost = host;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newHost;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Deletes a host from the database.
|
|
|
|
* If the delete host is the current one, we will try too change the current one to another
|
|
|
|
* or set it to null if there's no other
|
|
|
|
* @param hostId Id of the host to delete
|
|
|
|
*/
|
|
|
|
public void deleteHost(final int hostId) {
|
|
|
|
// Async call delete. The triggers to delete all host information can take some time
|
|
|
|
new Thread(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
context.getContentResolver()
|
|
|
|
.delete(MediaContract.Hosts.buildHostUri(hostId), null, null);
|
|
|
|
}
|
|
|
|
}).start();
|
|
|
|
|
|
|
|
// Refresh information
|
|
|
|
int index = -1;
|
|
|
|
for (int i = 0; i < hosts.size(); i++) {
|
|
|
|
if (hosts.get(i).getId() == hostId) {
|
|
|
|
index = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (index != -1)
|
|
|
|
hosts.remove(index);
|
|
|
|
// If we just deleted the current connection, switch to another
|
|
|
|
if ((currentHostInfo != null) && (currentHostInfo.getId() == hostId)) {
|
|
|
|
releaseCurrentHost();
|
|
|
|
if (hosts.size() > 0)
|
|
|
|
switchHost(hosts.get(0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Releases all state related to the current connection
|
|
|
|
*/
|
|
|
|
private void releaseCurrentHost() {
|
|
|
|
if (currentHostConnectionObserver != null) {
|
2015-02-15 20:11:32 +01:00
|
|
|
currentHostConnectionObserver.stopObserving();
|
2015-01-14 12:12:47 +01:00
|
|
|
currentHostConnectionObserver = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentHostConnection != null) {
|
|
|
|
currentHostConnection.disconnect();
|
|
|
|
currentHostConnection = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentPicasso != null) {
|
|
|
|
// Calling shutdown here causes a picasso error:
|
|
|
|
// Handler (com.squareup.picasso.Stats$StatsHandler) {41b13d40} sending message to a Handler on a dead thread
|
|
|
|
// Check: https://github.com/square/picasso/issues/445
|
|
|
|
// So, for now, just let it be...
|
|
|
|
// currentPicasso.shutdown();
|
|
|
|
currentPicasso = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|