/**
* Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET
* (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije
* informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE
* COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp.,
* INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM
* ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC))
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.societies.android.platform.useragent.feedback;
import android.app.Notification;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.*;
import android.util.Log;
import org.societies.android.api.comms.IMethodCallback;
import org.societies.android.api.events.IAndroidSocietiesEvents;
import org.societies.android.api.events.IPlatformEventsCallback;
import org.societies.android.api.events.PlatformEventsHelperNotConnectedException;
import org.societies.android.platform.androidutils.AndroidNotifier;
import org.societies.android.platform.useragent.feedback.constants.UserFeedbackActivityIntentExtra;
import org.societies.android.platform.useragent.feedback.guis.*;
import org.societies.android.remote.helper.EventsHelper;
import org.societies.api.internal.schema.useragent.feedback.UserFeedbackAccessControlEvent;
import org.societies.api.internal.schema.useragent.feedback.UserFeedbackPrivacyNegotiationEvent;
import org.societies.api.schema.useragent.feedback.FeedbackMethodType;
import org.societies.api.schema.useragent.feedback.UserFeedbackBean;
import java.util.HashSet;
import java.util.Set;
/**
* Describe your class here...
*
* @author aleckey
*/
public class EventListener extends Service {
private static final String LOG_TAG = EventListener.class.getName();
//TRACKING CONNECTION TO EVENTS MANAGER
private boolean boundToEventMgrService = false;
private BroadcastReceiver receiver;
@SuppressWarnings("FieldCanBeLocal")
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
private EventsHelper eventsHelper;
private final Set<String> processedIncomingEvents = new HashSet<String>();
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
Log.d(this.getClass().getName(), "Message received in Userfeedback event thread");
if (!boundToEventMgrService) {
setupBroadcastReceiver();
subscribeToEvents();
}
}
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>UserFeedback SERVICE LIFECYCLE METHODS>>>>>>>>>>>>>>>>>>>>>>>>>>>>
@Override
public IBinder onBind(Intent intent) {
return null; //NO-ONE ALLOWED TO BIND TO THIS SERVICE
}
@Override
public void onCreate() {
Log.d(this.getClass().getName(), "UserFeedback Service creating...");
// START BACKGROUND THREAD FOR SERVICE
HandlerThread thread = new HandlerThread("UserFeedbackStartArguments", android.os.Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
// Timed abort processor needs a context to run in
TimedAbortProcessor.getInstance().setContext(this);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// For each start request, send a message to start a job and deliver the
//start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
//If we get killed, after returning from here, restart
return START_STICKY;
}
@Override
public void onDestroy() {
Log.d(LOG_TAG, "UserFeedback service terminating");
boundToEventMgrService = false;
this.unregisterReceiver(receiver);
this.eventsHelper.tearDownService(new IMethodCallback() {
@Override
public void returnAction(String result) {
}
@Override
public void returnAction(boolean resultFlag) {
}
@Override
public void returnException(String result) {
}
});
TimedAbortProcessor.getInstance().stop();
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>REGISTER FOR EVENTS>>>>>>>>>>>>>>>>>>>>>>>>>>>>
/**
* Create a broadcast receiver
*/
private void setupBroadcastReceiver() {
Log.d(LOG_TAG, "Setting up broadcast receiver...");
receiver = new MainReceiver();
this.registerReceiver(receiver, createIntentFilter());
}
/**
* Broadcast receiver to receive intent return values from EventManager service
*/
private class MainReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "Received action: " + intent.getAction());
//EVENT MANAGER INTENTS
if (intent.getAction().equals(IAndroidSocietiesEvents.SUBSCRIBE_TO_EVENT)) {
Log.d(LOG_TAG, "Subscribed to event: " + intent.getBooleanExtra(IAndroidSocietiesEvents.INTENT_RETURN_VALUE_KEY, false));
} else if (intent.getAction().equals(IAndroidSocietiesEvents.SUBSCRIBE_TO_EVENTS)) {
Log.d(LOG_TAG, "Subscribed to multiple events: " + intent.getBooleanExtra(IAndroidSocietiesEvents.INTENT_RETURN_VALUE_KEY, false));
} else if (intent.getAction().equals(IAndroidSocietiesEvents.UNSUBSCRIBE_FROM_EVENTS)) {
Log.d(LOG_TAG, "Un-subscribed to events: " + intent.getBooleanExtra(IAndroidSocietiesEvents.INTENT_RETURN_VALUE_KEY, false));
}
//PRIVACY NEGOTIATION EVENT - payload is UserFeedbackPrivacyNegotiatioEvent
else if (intent.getAction().equals(IAndroidSocietiesEvents.UF_PRIVACY_NEGOTIATION_REQUEST_INTENT)) {
UserFeedbackPrivacyNegotiationEvent eventPayload = intent.getParcelableExtra(IAndroidSocietiesEvents.GENERIC_INTENT_PAYLOAD_KEY);
String id = String.valueOf(eventPayload.getRequestId());
synchronized (processedIncomingEvents) {
if (processedIncomingEvents.contains(id)) {
Log.w(LOG_TAG, "Ignoring duplicate PPN event received: id=" + id);
return;
}
processedIncomingEvents.add(id);
}
Log.d(LOG_TAG, "Privacy Negotiation event received: id=" + id);
displayPrivacyNegotiationNotification(EventListener.this.getApplicationContext(), eventPayload);
}
//ACCESS CONTROL EVENT - payload is UserFeedbackAccessControlEvent
else if (intent.getAction().equals(IAndroidSocietiesEvents.UF_ACCESS_CONTROL_REQUEST_INTENT)) {
UserFeedbackAccessControlEvent eventPayload = intent.getParcelableExtra(IAndroidSocietiesEvents.GENERIC_INTENT_PAYLOAD_KEY);
String id = String.valueOf(eventPayload.getRequestId());
synchronized (processedIncomingEvents) {
if (processedIncomingEvents.contains(id)) {
Log.w(LOG_TAG, "Ignoring duplicate AC event received: id=" + id);
return;
}
processedIncomingEvents.add(id);
}
Log.d(LOG_TAG, "Privacy Negotiation event received: id=" + id);
displayAccessControlNotification(EventListener.this.getApplicationContext(), eventPayload);
}
//PERMISSION REQUEST EVENT - payload is UserFeedbackBean
else if (intent.getAction().equals(IAndroidSocietiesEvents.UF_REQUEST_INTENT)) {
UserFeedbackBean eventPayload = intent.getParcelableExtra(IAndroidSocietiesEvents.GENERIC_INTENT_PAYLOAD_KEY);
String id = eventPayload.getRequestId();
synchronized (processedIncomingEvents) {
if (processedIncomingEvents.contains(id)) {
Log.w(LOG_TAG, "Ignoring duplicate UF event received: id=" + id);
return;
}
processedIncomingEvents.add(id);
}
Log.d(LOG_TAG, "General Permission request event received: id=" + id);
displayUserFeedbackNotification(EventListener.this.getApplicationContext(), eventPayload);
}
}
}
/**
* Create a suitable intent filter
*
* @return IntentFilter
*/
private static IntentFilter createIntentFilter() {
//register broadcast receiver to receive SocietiesEvents return values
IntentFilter intentFilter = new IntentFilter();
//EVENT MANAGER INTENTS
intentFilter.addAction(IAndroidSocietiesEvents.SUBSCRIBE_TO_EVENT);
intentFilter.addAction(IAndroidSocietiesEvents.SUBSCRIBE_TO_EVENTS);
intentFilter.addAction(IAndroidSocietiesEvents.UNSUBSCRIBE_FROM_EVENTS);
//PUBSUB INTENTS
intentFilter.addAction(IAndroidSocietiesEvents.UF_ACCESS_CONTROL_REQUEST_INTENT);
intentFilter.addAction(IAndroidSocietiesEvents.UF_PRIVACY_NEGOTIATION_REQUEST_INTENT);
intentFilter.addAction(IAndroidSocietiesEvents.UF_REQUEST_INTENT);
return intentFilter;
}
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>SUBSCRIBE TO PUBSUB EVENTS>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
private void subscribeToEvents() {
eventsHelper = new EventsHelper(EventListener.this.getApplicationContext());
Log.d(LOG_TAG, "new EventService");
eventsHelper.setUpService(new IMethodCallback() {
@Override
public void returnAction(String result) {
}
@Override
public void returnAction(boolean resultFlag) {
Log.d(LOG_TAG, "eventMgr callback: resultFlag: " + resultFlag);
if (resultFlag) {
try {
//subscribing to all user feedback events.
EventListener.this.eventsHelper.subscribeToEvents(UserFeedbackActivityIntentExtra.USERFEEDBACK_NODES, new IPlatformEventsCallback() {
@Override
public void returnAction(int result) {
Log.d(LOG_TAG, "eventMgr callback: ReturnAction(int) called. ??");
}
@Override
public void returnAction(boolean resultFlag) {
Log.d(LOG_TAG, "eventMgr.subscribeToEvents resultFlag: " + resultFlag);
if (resultFlag)
boundToEventMgrService = true;
}
@Override
public void returnException(int exception) {
Log.d(LOG_TAG, "eventMgr.returnException code: " + exception);
}
});
} catch (PlatformEventsHelperNotConnectedException e) {
e.printStackTrace();
}
}
}
@Override
public void returnException(String result) {
}
});
}
private static void displayAccessControlNotification(Context context, UserFeedbackAccessControlEvent event) {
// CREATE INTENT FOR LAUNCHING ACTIVITY
Intent intent = new Intent(context, AccessControlActivity.class);
intent.putExtra(UserFeedbackActivityIntentExtra.EXTRA_PRIVACY_POLICY, (Parcelable) event);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//CREATE ANDROID NOTIFICATION
int notifierFlags[] = new int[1];
notifierFlags[0] = Notification.FLAG_AUTO_CANCEL;
AndroidNotifier notifier = new AndroidNotifier(context, Notification.DEFAULT_SOUND, notifierFlags);
notifier.notifyMessage("Access control request",
"Access Control Request",
AccessControlActivity.class,
intent,
"SOCIETIES");
}
private static void displayPrivacyNegotiationNotification(Context context, UserFeedbackPrivacyNegotiationEvent policy) {
//CREATE INTENT FOR LAUNCHING ACTIVITY
Intent intent = new Intent(context, NegotiationActivity.class);
intent.putExtra(UserFeedbackActivityIntentExtra.EXTRA_PRIVACY_POLICY, (Parcelable) policy);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//CREATE ANDROID NOTIFICATION
int notifierFlags[] = new int[1];
notifierFlags[0] = Notification.FLAG_AUTO_CANCEL;
AndroidNotifier notifier = new AndroidNotifier(context, Notification.DEFAULT_SOUND, notifierFlags);
notifier.notifyMessage("Privacy policy negotiation",
"Privacy Policy Negotiation",
NegotiationActivity.class,
intent,
"SOCIETIES");
}
private static void displayUserFeedbackNotification(Context context, UserFeedbackBean ufBean) {
//DETERMINE WHICH ACTIVITY TO LAUNCH
Class activityClass;
if (ufBean.getMethod() == FeedbackMethodType.GET_EXPLICIT_FB) {
// select type of explicit feedback
if (ufBean.getType() == 0)
activityClass = RadioPopup.class;
else if (ufBean.getType() == 1)
activityClass = CheckboxPopup.class;
else
activityClass = AcknackPopup.class;
} else if (ufBean.getMethod() == FeedbackMethodType.GET_IMPLICIT_FB) {
// only one type of implicit feedback
activityClass = TimedAbortPopup.class;
// Add to the background watcher
TimedAbortProcessor.getInstance().addTimedAbort(ufBean);
} else {
// only one left is "SHOW_NOTIFICATION"
activityClass = SimpleNotificationPopup.class;
}
//CREATE INTENT FOR LAUNCHING ACTIVITY
Intent intent = new Intent(context, activityClass);
intent.putExtra(UserFeedbackActivityIntentExtra.USERFEEDBACK_NODES, (Parcelable) ufBean);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//CREATE ANDROID NOTIFICATION
int notifierFlags[] = new int[1];
notifierFlags[0] = Notification.FLAG_AUTO_CANCEL;
AndroidNotifier notifier = new AndroidNotifier(context, Notification.DEFAULT_SOUND, notifierFlags);
notifier.notifyMessage(ufBean.getProposalText(),
"Input required",
activityClass,
intent,
"SOCIETIES");
}
}