package com.sound.ampache.net;
/* Copyright (c) 2014 David Hrdina Nemecek <dejvino@gmail.com>
*
* +------------------------------------------------------------------------+
* | This program is free software; you can redistribute it and/or |
* | modify it under the terms of the GNU General Public License |
* | as published by the Free Software Foundation; either version 2 |
* | of the License, or (at your option) any later version. |
* | |
* | This program is distributed in the hope that it will be useful, |
* | but WITHOUT ANY WARRANTY; without even the implied warranty of |
* | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
* | GNU General Public License for more details. |
* | |
* | You should have received a copy of the GNU General Public License |
* | along with this program; if not, write to the Free Software |
* | Foundation, Inc., 59 Temple Place - Suite 330, |
* | Boston, MA 02111-1307, USA. |
* +------------------------------------------------------------------------+
*/
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.util.Log;
import com.sound.ampache.R;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.LinkedBlockingDeque;
/**
* Description: Worker (thread) responsible for handling network communications.
*
* @author Dejvino
* @since 2014-08-31
*/
public class NetworkWorker
{
private static final String LOG_TAG = "Ampache_Android_NetworkService";
public static final String KEY_OPERATION = "operation";
public static final String KEY_MESSAGE = "message";
public static final String KEY_AUTH_TOKEN = "auth_token";
public static final String KEY_REQUEST_URL = "request_url";
public static final String KEY_RESPONSE_IMAGE = "response_image";
public static final String KEY_REQUEST = "original_request_message";
public static final String KEY_TERMINATE = "network_worker_terminate";
public enum Operation
{
PING,
AUTH,
SEND,
DOWNLOAD_IMAGE,
}
private final Context ctx;
private SharedPreferences prefs;
private AmpacheApiClient comm;
private AmpacheApiClient.ampacheRequestHandler requestHandler;
private BlockingDeque<Message> messageQueue = new LinkedBlockingDeque<Message>();
private WorkerThread workerThread;
public NetworkWorker(Context ctx)
{
this.ctx = ctx;
PreferenceManager.setDefaultValues(ctx, R.xml.preferences, false);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
try {
comm = new AmpacheApiClient(prefs, ctx);
requestHandler = comm.new ampacheRequestHandler();
requestHandler.start();
} catch (Exception e) {
Log.d(LOG_TAG, "Network service failed to init.", e);
}
}
/**
* Starts the networking worker.
* <p/>
* This internally forks a new thread to do the actual work in the background.
*/
public void start()
{
if (workerThread == null || !workerThread.isAlive()) {
workerThread = new WorkerThread();
workerThread.start();
}
}
/**
* Adds a message to be processed by the worker.
*
* @param msg
*/
public void postMessage(Message msg)
{
messageQueue.offer(msg);
}
/**
* Worker thread for handling all the networking.
*/
private class WorkerThread extends Thread
{
private WorkerThread()
{
super(NetworkWorker.class.getSimpleName() + "." + WorkerThread.class.getSimpleName());
}
@Override
public void run()
{
try {
do {
Message message = messageQueue.takeFirst();
if (message == null || KEY_TERMINATE.equals(message.obj)) {
Log.e(LOG_TAG, "Networking worker thread exiting as commanded.");
break;
}
onHandleMessage(message);
} while (true);
} catch (Exception e) {
Log.e(LOG_TAG, "Networking worker thread died unexpectedly.", e);
}
}
private void onHandleMessage(Message message)
{
// determine if we pass the message on or handle it here
Operation op = Operation.SEND;
if (message.getData().containsKey(KEY_OPERATION)) {
op = (Operation) message.getData().getSerializable(KEY_OPERATION);
}
Log.d(LOG_TAG, "Network thread processing: " + op.toString() + " (" + message.toString() + ")");
Message reply = new Message();
reply.getData().putParcelable(KEY_REQUEST, message);
switch (op) {
case AUTH:
onAuth(message, reply);
break;
case DOWNLOAD_IMAGE:
onDownloadImage(message, reply);
break;
case SEND:
onSend(message);
break;
default:
throw new RuntimeException("Unhandled operation type: " + op.toString());
}
if (message.replyTo != null) {
try {
message.replyTo.send(reply);
} catch (RemoteException e) {
Log.d(LOG_TAG, "Failed sending response message.", e);
}
}
Log.d(LOG_TAG, "Network thread finished: " + op.toString());
}
private void onAuth(Message request, Message reply)
{
// Check if we have a valid session, if not we try to establish one and then check again.
if (!comm.isAuthenticated()) {
comm.ping();
}
if (!comm.isAuthenticated()) {
Log.e(LOG_TAG, "Connection problems: " + comm.lastErr);
} else {
Log.d(LOG_TAG, "Authentication is set.");
}
reply.getData().putString(KEY_AUTH_TOKEN, comm.getAuthToken());
}
private void onDownloadImage(Message message, Message reply)
{
Bitmap bitmap = ImageDownloader.getImageBitmap(message.getData().getString(KEY_REQUEST_URL));
reply.getData().putParcelable(KEY_RESPONSE_IMAGE, bitmap);
}
private void onSend(Message message)
{
requestHandler.incomingRequestHandler.sendMessage(message);
}
}
}