package eu.musesproject.client.contextmonitoring; /* * #%L * musesclient * %% * Copyright (C) 2013 - 2014 HITEC * %% * 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. * #L% */ import android.content.Context; import android.util.Log; import eu.musesproject.client.contextmonitoring.sensors.*; import eu.musesproject.client.db.entity.SensorConfiguration; import eu.musesproject.client.db.handler.DBManager; import eu.musesproject.client.model.contextmonitoring.InteractionObservedApps; import eu.musesproject.client.model.contextmonitoring.UISource; import eu.musesproject.client.model.decisiontable.Action; import eu.musesproject.client.ui.DebugFileLog; import eu.musesproject.client.utils.MusesUtils; import eu.musesproject.contextmodel.ContextEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Christoph * @version 28 feb 2014 * * Class to control the lifecycle of all implemented sensors */ public class SensorController { private static final String TAG = SensorController.class.getSimpleName(); private static SensorController sensorController = null; private final ContextEventBus contextEventBus = new ContextEventBus(); private static boolean isCollectingData = false; private Context context; private Map<String, ISensor> activeSensors; // stores the latest fired ContextEvent of every sensor private Map<String, ContextEvent> lastFiredContextEvents; private DBManager dbManager; private SensorController(Context context) { this.context = context; activeSensors = new HashMap<String, ISensor>(); lastFiredContextEvents = new HashMap<String, ContextEvent>(); dbManager = new DBManager(context); } public static SensorController getInstance(Context context) { if (sensorController == null) { sensorController = new SensorController(context); } return sensorController; } public void startSensors() { DebugFileLog.write(TAG+"| 1/3 check if sensors can be started"); Log.d(MusesUtils.TEST_TAG, "SC - 1. start sensors"); // just start the sensors if they are not already collecting data if(!isCollectingData) { Log.d(MusesUtils.TEST_TAG, "SC - 2. data collection in enabled"); List<String> enabledSensor; boolean sensorConfigExists; dbManager.openDB(); sensorConfigExists = dbManager.hasSensorConfig(); dbManager.closeDB(); DebugFileLog.write(TAG+"| 2/3 sensor config exists : " + sensorConfigExists); // just start the sensors if there is a configuration for them if(sensorConfigExists) { Log.d(MusesUtils.TEST_TAG, "SC - 3. config exists"); dbManager.openDB(); enabledSensor = dbManager.getAllEnabledSensorTypes(); dbManager.closeDB(); startAndConfigureSensors(enabledSensor); DebugFileLog.write(TAG + "| 3/3 start sensors"); isCollectingData = true; } } } private void startAndConfigureSensors(List<String> enabledSensor) { Log.d(MusesUtils.TEST_TAG, "SC - startAndConfigureSensors"); for (String sensorType : enabledSensor) { ISensor sensor; dbManager.openDB(); List<SensorConfiguration> configItems = dbManager.getAllSensorConfigItemsBySensorType(sensorType); dbManager.closeDB(); sensor = createSensor(sensorType); if(sensor == null) { continue; } Log.d(MusesUtils.TEST_TAG, "SC - config test: sensor type="+sensor.getClass().getSimpleName() + ", no. config items="+configItems.size()); sensor.configure(configItems); activeSensors.put(sensorType, sensor); } for (ISensor sensor : activeSensors.values()) { sensor.addContextListener(contextEventBus); sensor.enable(); } } /** * Method to create a new instance of a sensor based on the sensorType * @param sensorType, variable to determine which concrete sensor should be created * @return ISensor */ private ISensor createSensor(String sensorType) { ISensor sensor = null; if(sensorType.equals(AppSensor.TYPE)) { sensor = new AppSensor(context); } else if(sensorType.equals(ConnectivitySensor.TYPE)) { sensor = new ConnectivitySensor(context); } else if(sensorType.equals(SettingsSensor.TYPE)) { sensor = new SettingsSensor(context); } else if(sensorType.equals(RecursiveFileSensor.TYPE)) { sensor = new RecursiveFileSensor(); } else if(sensorType.equals(PackageSensor.TYPE)) { sensor = new PackageSensor(context); } else if(sensorType.equals(DeviceProtectionSensor.TYPE)) { sensor = new DeviceProtectionSensor(context); } else if(sensorType.equals(LocationSensor.TYPE)) { sensor = new LocationSensor(context); } else if(sensorType.equals(InteractionSensor.TYPE)) { sensor = new InteractionSensor(); } else if(sensorType.equals(PeripheralSensor.TYPE)) { sensor = new PeripheralSensor(context); } return sensor; } /** * stops every enabled sensor */ public void stopAllSensors() { Log.d(MusesUtils.TEST_TAG, "SC - stopAllSensors()"); for (ISensor sensor : activeSensors.values()) { sensor.removeContextListener(null); sensor.disable(); } activeSensors.clear(); } /** * Method that updates the configuration of the sensors * 1. stop sensors * 2. update configuration * 3. re-enable sensors */ public void onSensorConfigurationChanged() { Log.d(MusesUtils.TEST_TAG, "SC - onSensorConfigurationChanged()"); // 1. stop sensors if (activeSensors != null) { Log.d(MusesUtils.TEST_TAG, "SC - onSensorConfigurationChanged(); activeSensors!=null"); for (ISensor sensor : activeSensors.values()) { sensor.disable(); activeSensors.remove(sensor.getSensorType()); sensor = null; isCollectingData = false; } } /* * 2. update configuration * 3. re-enable sensors */ startSensors(); } /** * Method that returns the last fired events of all enabled sensors * @return {@link List} of {@link ContextEvent} */ public List<ContextEvent> getLastFiredEvents() { List<ContextEvent> contextEvents = new ArrayList<ContextEvent>(); if (activeSensors != null) { for (ISensor sensor : activeSensors.values()) { ContextEvent contextEvent = sensor.getLastFiredContextEvent(); if(contextEvent != null) { // just add the context event if there is already one fired contextEvents.add(contextEvent); } } } return contextEvents; } public Map<String, ISensor> getActiveSensors() { return activeSensors; } /** * Inner class that gets notified when a new {@link ContextEvent} * is fired by a {@link ISensor} * * @author christophstanik */ class ContextEventBus implements ContextListener { @Override public void onEvent(ContextEvent contextEvent) { Log.d(MusesUtils.TEST_TAG, "SC - onEvent(ContextEvent contextEvent)"); // if an app is active that should be observed inform the interaction sensor if(contextEvent != null && contextEvent.getType().equals(AppSensor.TYPE)) { // if the app is gmail in this case //TODO must be configurable Log.d(TAG, contextEvent.getProperties().get(AppSensor.PROPERTY_KEY_APP_NAME)); if(contextEvent.getProperties().get(AppSensor.PROPERTY_KEY_APP_NAME).equals(InteractionObservedApps.OBSERVED_GMAIL)) { if (activeSensors != null && activeSensors.containsKey(InteractionSensor.TYPE)) { ((InteractionSensor) activeSensors.get(InteractionSensor.TYPE)).setAppName(InteractionObservedApps.OBSERVED_GMAIL); } } } /* * Workflow of creating an action and sending it to the server * * If a context event is fired: * 1. check if there are already enough context events to create an user action * 2. create an user action based on the current and the previous context events * 3. update the lastFiredContextEvent list * 4. send the action via the {@link eu.musesproject.client.contextmonitoring.UserContextMonitoringController} * to the server */ Action userAction = null; Map<String, String> properties = null; // 1. if lastFiredContextEvents.size() is 0 than it is the initial context event and no further processing // have to be done if(lastFiredContextEvents.size() > 0) { // 2. create an user action userAction = UserActionGenerator.createUserAction(contextEvent); properties = UserActionGenerator.createUserActionProperties(contextEvent); } // 3. update Map with the new context event if(lastFiredContextEvents.containsKey(contextEvent.getType())) { lastFiredContextEvents.remove(contextEvent.getType()); } lastFiredContextEvents.put(contextEvent.getType(), contextEvent); // 4. send action to the UserContextMonitoringController if(userAction != null && properties!= null) { UserContextMonitoringController.getInstance(context).sendUserAction(UISource.INTERNAL, userAction, properties); } } } }