package eu.musesproject.client.contextmonitoring.sensors; /* * #%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.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.os.Looper; import android.util.Log; import eu.musesproject.client.contextmonitoring.ContextListener; import eu.musesproject.client.db.entity.SensorConfiguration; import eu.musesproject.client.model.contextmonitoring.Zone; import eu.musesproject.contextmodel.ContextEvent; import java.util.ArrayList; import java.util.List; public class LocationSensor implements ISensor, LocationListener { private static final String TAG = LocationSensor.class.getSimpleName(); // sensor identifier public static final String TYPE = "CONTEXT_SENSOR_LOCATION"; // time in milliseconds when the sensor polls information private static int OBSERVATION_INTERVAL = 600000; // context property keys public static final String PROPERTY_KEY_ID = "hashid"; public static final String PROPERTY_KEY_IS_WITHIN_ZONE = "isWithinZone"; // config keys public static final String CONFIG_KEY_ZONE = "zone"; public static final int CONFIG_KEY_DESCRIPTION_POS = 0; public static final int CONFIG_KEY_ZONE_ID_POS = 1; public static final int CONFIG_KEY_RADIUS_POS = 2; public static final int CONFIG_KEY_LATITUDE_POS = 3; public static final int CONFIG_KEY_LONGITUDE_POS = 4; // default values public static final String DEFAULT_USER_IS_IN_NO_ZONE = "no_zone"; private Context context; private ContextListener listener; // history of fired context events List<ContextEvent> contextEventHistory; // holds a value that indicates if the sensor is enabled or disabled private boolean sensorEnabled; private LocationManager locationManager; private Location currentLocation; private List<Zone> zones; private boolean isNetworkEnabled = false; // configuration private static final long MIN_TIME_CHANGE_FOR_UPDATES = OBSERVATION_INTERVAL; // in milliseconds private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 0; // in meter public LocationSensor(Context context) { this.context = context; init(); } private void init() { sensorEnabled = false; contextEventHistory = new ArrayList<ContextEvent>(CONTEXT_EVENT_HISTORY_SIZE); zones = new ArrayList<Zone>(); } public Location getCurrentLocation() { Log.d(TAG, "getCurrentLocation called"); // Get the location manager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); if(isNetworkEnabled) { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_CHANGE_FOR_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, this, Looper.getMainLooper()); currentLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } // Initialize the location fields if (currentLocation != null) { createContextEvent(); } return currentLocation; } @Override public void addContextListener(ContextListener listener) { this.listener = listener; } @Override public void removeContextListener(ContextListener listener) { this.listener = listener; } @Override public void enable() { if (!sensorEnabled) { sensorEnabled = true; Log.d(TAG, "ENABLE"); getCurrentLocation(); } } @Override public void disable() { Log.d(TAG, "DISABLE"); if (sensorEnabled) { sensorEnabled = false; locationManager.removeUpdates(this); } } @Override public ContextEvent getLastFiredContextEvent() { if(contextEventHistory.size() > 0) { return contextEventHistory.get(contextEventHistory.size() - 1); } else { return null; } } @Override public void configure(List<SensorConfiguration> config) { for (SensorConfiguration sensorConfiguration : config) { if(sensorConfiguration.getKey().equals(CONFIG_KEY_ZONE)) { try { String[] configItems = sensorConfiguration.getValue().split(";"); Zone zone = new Zone(); zone.setDescription(configItems[CONFIG_KEY_DESCRIPTION_POS]); zone.setZoneId(Integer.parseInt(configItems[CONFIG_KEY_ZONE_ID_POS])); zone.setRadius(Float.parseFloat(configItems[CONFIG_KEY_RADIUS_POS])); zone.setLatitude(Double.parseDouble(configItems[CONFIG_KEY_LATITUDE_POS])); zone.setLongitude(Double.parseDouble(configItems[CONFIG_KEY_LONGITUDE_POS])); Log.d(TAG, configItems[CONFIG_KEY_DESCRIPTION_POS] + " lat=" + configItems[CONFIG_KEY_LATITUDE_POS] + " long=" + configItems[CONFIG_KEY_LONGITUDE_POS] + " radius=" +configItems[CONFIG_KEY_RADIUS_POS]); zones.add(zone); } catch (Exception e) { Log.w(TAG, e.getMessage()); } } } } @Override public void onLocationChanged(Location location) { Log.d(TAG, "onLocationChanged"); currentLocation = location; createContextEvent(); } private void createContextEvent() { if(currentLocation != null) { String isInZones = ""; for (Zone zone : zones) { Location location = new Location("zone_center"); location.setLongitude(zone.getLongitude()); location.setLatitude(zone.getLatitude()); Log.d(TAG, "distance to " + zone.getDescription() + " is " + currentLocation.distanceTo(location) + "m"); if(currentLocation.distanceTo(location) <= zone.getRadius()) { isInZones += zone.getZoneId() + ","; } } if(isInZones.isEmpty()) { isInZones = DEFAULT_USER_IS_IN_NO_ZONE; } else { if(isInZones.contains(",")) { isInZones = isInZones.substring(0, isInZones.length() - 1); // remove ',' as the last char } } Log.d(TAG, "is in zones: " + isInZones); ContextEvent contextEvent = new ContextEvent(); contextEvent.setType(TYPE); contextEvent.setTimestamp(System.currentTimeMillis()); contextEvent.addProperty(PROPERTY_KEY_IS_WITHIN_ZONE, isInZones); contextEvent.generateId(); if (listener != null) { listener.onEvent(contextEvent); } } } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } @Override public void onProviderEnabled(String provider) { } @Override public void onProviderDisabled(String provider) { } @Override public String getSensorType() { return TYPE; } }