/*
* AndFHEM - Open Source Android application to control a FHEM home automation
* server.
*
* Copyright (c) 2011, Matthias Klass or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU GENERAL PUBLIC LICENSE, as published by the Free Software Foundation.
*
* 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 distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package li.klass.fhem.service.intent;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import com.google.common.base.Optional;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import javax.inject.Inject;
import li.klass.fhem.AndFHEMApplication;
import li.klass.fhem.service.Command;
import li.klass.fhem.service.CommandExecutionService;
import li.klass.fhem.service.room.RoomListService;
import static com.google.common.collect.Lists.newArrayList;
public class ExternalApiService extends Service {
public static final int ROOM_LIST = 1;
public static final int READINGS_VALUE = 2;
private final Messenger messenger;
@Inject
RoomListService roomListService;
@Inject
CommandExecutionService commandExecutionService;
private Message replyMsg;
public ExternalApiService() {
messenger = new Messenger(new IncomingHandler(new WeakReference<>(this)));
}
private void replyTo(ArrayList<String> outgoing) {
replyTo(replyMsg, outgoing);
}
private void replyTo(Message incoming, ArrayList<String> outgoing) {
try {
if (incoming.replyTo != null) {
Message msg = Message.obtain(null, incoming.what);
Bundle bundle = new Bundle();
if (incoming.getData() != null) {
//if incoming message has data send it back along with the results
bundle = incoming.getData();
}
bundle.putStringArrayList("data", outgoing);
msg.setData(bundle);
incoming.replyTo.send(msg);
} else {
Log.e(ExternalApiService.class.getName(), "cannot send message, no replyTo Messenger set.");
}
} catch (RemoteException e) {
Log.e(ExternalApiService.class.getName(), "cannot send message", e);
}
}
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();
}
@Override
public void onCreate() {
super.onCreate();
((AndFHEMApplication) getApplication()).getDaggerComponent().inject(this);
}
static class IncomingHandler extends Handler {
private final WeakReference<ExternalApiService> externalApiServiceWeakReference;
public IncomingHandler(WeakReference<ExternalApiService> externalApiService) {
this.externalApiServiceWeakReference = externalApiService;
}
@Override
public void handleMessage(Message msg) {
final ExternalApiService externalApiService = externalApiServiceWeakReference.get();
switch (msg.what) {
case ROOM_LIST:
ArrayList<String> deviceNames = externalApiService.roomListService.getAvailableDeviceNames(Optional.<String>absent(), externalApiService);
externalApiService.replyTo(msg, deviceNames);
break;
case READINGS_VALUE:
String deviceName = null;
String readingName = null;
String defaultVal = null;
//FIXME: create a new Message to reply with because we will loose msg somewhere in the AsyncTask below
externalApiService.replyMsg = Message.obtain(null, msg.what);
externalApiService.replyMsg.setData(msg.getData());
externalApiService.replyMsg.replyTo = msg.replyTo;
if (msg.getData() != null) {
if (msg.getData().getString("device") != null) {
deviceName = msg.getData().getString("device");
}
if (msg.getData().getString("reading") != null) {
readingName = msg.getData().getString("reading");
}
if (msg.getData().getString("default") != null) {
defaultVal = msg.getData().getString("default");
}
if (deviceName != null && readingName != null && defaultVal != null) {
final Handler handler = new Handler();
new AsyncTask<String, Void, String>() {
@Override
protected String doInBackground(String... params) {
Command command = new Command(String.format("{ReadingsVal('%s','%s','%s')}", params[0], params[1], params[2]));
return externalApiService.commandExecutionService.executeSync(command, externalApiService);
}
@Override
protected void onPostExecute(final String result) {
// onPostExecute is run from within the UI thread, but Android allows to run multiple UI threads.
// We cannot be sure which one is chosen, so we enforce the right UI thread by using an explicit
// handler.
// see http://stackoverflow.com/questions/10426120/android-got-calledfromwrongthreadexception-in-onpostexecute-how-could-it-be
handler.post(new Runnable() {
@Override
public void run() {
ArrayList<String> readingsVal = newArrayList();
readingsVal.add(result);
externalApiService.replyTo(readingsVal);
}
});
}
}.execute(deviceName, readingName, defaultVal);
}
}
break;
default:
super.handleMessage(msg);
}
}
}
}