Back to project page blekit-android.
The source code is released under:
Copyright (C) 2014 Upnext Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software wi...
If you think the Android project blekit-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* * Copyright (c) 2014 UP-NEXT. All rights reserved. * http://www.up-next.com/*from www .j a v a 2s. c om*/ * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package com.upnext.blekit; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; import android.os.AsyncTask; import android.os.Bundle; import com.fasterxml.jackson.databind.JsonNode; import com.upnext.blekit.actions.BLEAction; import com.upnext.blekit.conditions.BLECondition; import com.upnext.blekit.conditions.OccurenceCondition; import com.upnext.blekit.listeners.BLEKitStateListener; import com.upnext.blekit.listeners.BeaconEventListener; import com.upnext.blekit.listeners.ZoneUpdateListener; import com.upnext.blekit.model.Beacon; import com.upnext.blekit.model.Condition; import com.upnext.blekit.model.CurrentBeaconProximity; import com.upnext.blekit.model.Trigger; import com.upnext.blekit.model.Zone; import com.upnext.blekit.util.BeaconPreferences; import com.upnext.blekit.util.BeaconsDB; import com.upnext.blekit.util.JsonParser; import com.upnext.blekit.util.L; import com.upnext.blekit.util.http.HttpClient; import com.upnext.blekit.util.http.Response; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Basic class used for BLEKit lifecycle management and configuration. * * Basic usage (in Activity): * <pre> * {@code * BLEKit * .create(this) * .setJsonUrl("http://your.server.com/zone.json") * .start(this); * } * </pre> * * Advanced configuration (in Activity): * <pre> * {@code * BLEKit * .create(this) * .setJsonUrl("http://your.server.com/zone.json") * .addAction(new CustomAction()) * .addCondition(new CustomCondition()) * .removeActionByType(FacebookCheckinAction.TYPE) * .setStateListener(this) * .start(this); * } * </pre> * * It is the responsibility of the developer to stop BLEKit service with {@link #stop(android.content.Context)}. * * @author Roman Wozniak (roman@up-next.com) * * @see com.upnext.blekit.actions.BLEAction * @see com.upnext.blekit.conditions.BLECondition */ public class BLEKit { private static BLEKit _bleKit; private static ConditionsFactory mConditionsFactory; private static ActionsFactory mActionsFactory; private static String jsonUrl; private static String jsonContent; private static BackgroundMode mBackgroundMode = new BackgroundMode(null, true); private static BeaconEventListener mBeaconEventListener; private static ZoneUpdateListener mZoneUpdateListener; private static BLEKitStateListener mStateListener; private static Map<String, Proximity> mCurrentBeaconsStates = new HashMap<String, Proximity>(); private static JsonParser jsonParser = new JsonParser(); private static Intent mEventToProcess; private static Zone mCurrentZone = null; private BeaconsDB beaconsDB; private Class targetActivityForNotifications; private boolean mBound; private Context mContext; private BLEKit(Context context) { mContext = context; String zoneJson = BeaconPreferences.getLastZoneJson(context); if( zoneJson!=null ) { mCurrentZone = jsonParser.parse(zoneJson); } beaconsDB = new BeaconsDB(context); mConditionsFactory = new ConditionsFactory(); mActionsFactory = new ActionsFactory(); } /** * Creates BLEKit service with default configuration. * If the service was runnig, it will be stopped first. * * Also creates new factories for conditions and actions. * * @param context context (either from activity or service) * @return BLEKit instance */ public static BLEKit create( Context context ) { L.d( "create" ); _bleKit = new BLEKit(context); return _bleKit; } /** * Starts BLEKit service. * * Fetches JSON configuration from given URL if provided. * * @param context context (either from activity or service) * @throws IllegalArgumentException thrown if configuration JSON was not provided (jsonUrl or jsonContent) or create() was not called before. */ public void start( Context context ) throws IllegalArgumentException { checkInitialized(); L.d( "start" ); if( jsonContent==null && jsonUrl==null ) { throw new IllegalArgumentException( "You have to provide either jsonUrl or jsonContent" ); } if( jsonUrl!=null ) { fetchJson(); } else { _bleKit.updateZone(jsonContent); } mBound = true; if( mStateListener!=null ) { mStateListener.onBLEKitStarted(); } if( mEventToProcess!=null ) { processServiceEvent(mEventToProcess, context); } } /** * Provide url with JSON configuration. * BLEKit should be created previously (#see BLEKit.create) * * If BLEKit is already started, then it fetches the JSON from given url and reloads the configuration. * * @param url url pointing to JSON configuration * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. * @throws java.net.MalformedURLException thrown if given url is malformed. */ public static BLEKit setJsonUrl( String url ) throws IllegalStateException, MalformedURLException { checkInitialized(); //validate URL new URL(url); jsonUrl = url; if( _bleKit.mBound ) { _bleKit.fetchJson(); } return _bleKit; } /** * Provide content with JSON configuration. * BLEKit should be created previously (#see BLEKit.create) * * If BLEKit is already started, then it fetches the JSON from given url and reloads the configuration. * * @param content String containing JSON configuration * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized */ public static BLEKit setJsonContent( String content ) throws IllegalStateException { checkInitialized(); jsonContent = content; if( _bleKit.mBound ) { _bleKit.updateZone(jsonContent); } return _bleKit; } /** * If a JSON url was provided previously (and was valid), then it is fetched again and all actions are triggered. * * @param ctx context * @throws IllegalStateException thrown if BLEKit was not initialized */ public static void reloadJson( Context ctx ) throws IllegalStateException { if( _bleKit==null ) { restartBlekit(ctx); return; } if(jsonUrl==null) return; try { new URL(jsonUrl); } catch (Exception e) { //if url is malformed, cosume error silently return; } if( _bleKit.mBound ) { _bleKit.fetchJson(); } else { fetchJsonLocal(); } } /** * Stops BLEKit service if it is running. * * @param context context (either from activity or service) */ public static void stop( Context context ) { L.d("stop"); mCurrentBeaconsStates = new HashMap<String, Proximity>(); if( _bleKit!=null && _bleKit.mBound ) { _bleKit.sendStop(); _bleKit.mBound = false; if( mStateListener!=null ) { mStateListener.onBLEKitStopped(); } } } /** * Add a custom condition implementation. * Should only be used before starting (in the config phase) the BLEKit. * * @param condition instance of new condition * @return BLEKit instance * @throws java.lang.IllegalStateException thrown when BLEKit is already started */ public BLEKit addCondition( BLECondition condition ) throws IllegalStateException { checkStarted(); mConditionsFactory.addCondition(condition); return _bleKit; } /** * Add a custom action implementation. * Should only be used before starting (in the config phase) the BLEKit. * * @param action instance of new action * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public BLEKit addAction( BLEAction action ) throws IllegalStateException { checkStarted(); mActionsFactory.addAction(action); return _bleKit; } /** * Set background mode. * If action supports foreground mode then for example in case of AlertAction and <code>background==false</code> an alert dialog will be shown. * Otherwise action will be processed in background (eg. a notification will be shown). * * @param background true for background, false for foreground * @param activity for a foreground state an Activity has to be provided; otherwise provide <code>null</code> * @throws java.lang.IllegalStateException thrown when <code>background==false</code> and <code>activity is null</code> */ public static void setBackgroundMode( boolean background, Activity activity ) throws IllegalStateException { L.d("setBackgroundMode " + background); if( !background && activity==null ) { throw new IllegalArgumentException( "Activity is null for foreground" ); } mBackgroundMode = new BackgroundMode( activity, background ); if( _bleKit!=null && _bleKit.mBound ) { _bleKit.sendSetBackgroundMode(mBackgroundMode); } } /** * Sets listener for beacon events {@link com.upnext.blekit.BeaconEvent} * Events will arrive despite the current configuration (so you might have only a 'leave' condition with action defined in configuration and at the same time receive notifications of proximity events through this listener). * * @param listener beacon events listener * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public static BLEKit setEventListener( BeaconEventListener listener ) throws IllegalStateException { mBeaconEventListener = listener; return _bleKit; } /** * Sets listener for configuration (zone) changes - eg. when a new configuration is fetched (after BLEKit start or after manual call to {@link #reloadJson(android.content.Context)}) * * @param listener zone update listener * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public static BLEKit setZoneUpdateListener( ZoneUpdateListener listener ) throws IllegalStateException { mZoneUpdateListener = listener; return _bleKit; } /** * Sets listener for BLEKit states - when in starts, stops and gets current beacon proximities after start. * * @param listener state listener * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public static BLEKit setStateListener( BLEKitStateListener listener ) throws IllegalStateException { mStateListener = listener; return _bleKit; } /** * Returns conditions factory. * Useful when you want to remove any conditions provided by default or get an implementation by type. * * @return conditions factory */ public static ConditionsFactory getConditionsFactory() { return mConditionsFactory; } /** * Returns actions factory. * Useful when you want to remove any actions provided by default or get an implementation by type. * * @return actions factory */ public static ActionsFactory getActionsFactory() { return mActionsFactory; } /** * Removes action of given type from the actions factory. * This is required in order to provide custom implementation of actions for default actions. * * * @param actionType type of action you want to be removed (eg. alert) * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public static BLEKit removeActionByType( String actionType ) throws IllegalStateException { checkInitialized(); mActionsFactory.remove(actionType); return _bleKit; } /** * Removes condition of given type from the conditions factory. * This is required in order to provide custom implementation of conditions for default actions. * * * @param conditionType type of condition you want to be removed (eg. enter) * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized. */ public static BLEKit removeConditionByType( String conditionType ) throws IllegalStateException { checkInitialized(); mConditionsFactory.remove(conditionType); return _bleKit; } /** * Checks whether Bluetooth LE is available on the device and Bluetooth turned on. * * If BLE is not supported, then a dialog with appropriate message is shown. * If BLE is supported, but Bluetooth is not turned on then a dialog with message is shown and an option to go directly to settings and turn Bluetooth on. * * A good place to invoke this method would be onResume() in your Activity. * * @param activity Activity * @return false if BLE is not supported or Bluetooth not turned on; otherwise true */ public static boolean checkAvailability(Activity activity) { if (!activity.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { showErrorDialog( activity.getString(R.string.blekit_ble_unsupported), activity, true); } else { if (((BluetoothManager) activity.getSystemService(Context.BLUETOOTH_SERVICE)).getAdapter().isEnabled()){ return true; } showErrorDialog( activity.getString(R.string.blekit_bt_not_on), activity, false ); } return false; } /** * Set target Activity to launch after clicking on notification. * For the notification to be handled successfully add the following line to the <code>onNewIntent</code> method of this activity: * <pre> * {@code * protected void onNewIntent(Intent intent) { * super.onNewIntent(intent); * BLEKit.processIntent(intent, this); //add this line * } * } * </pre> * * @param cls target Activity class * @return BLEKit instance * @throws IllegalStateException thrown if BLEKit was not initialized * @see #processIntent(android.content.Intent, android.app.Activity) */ public static BLEKit setTargetActivityForNotifications( Class cls ) throws IllegalStateException { checkInitialized(); _bleKit.targetActivityForNotifications = cls; BeaconPreferences.setTargetActivityForNotifications(_bleKit.mContext, cls.getName()); return _bleKit; } /** * Return the class for activity that handles notifications. * * @return Activity class handling notifications */ public static Class getTargetActivityForNotifications() { return _bleKit.targetActivityForNotifications; } /** * Should be called from Activity that handles notifications. * For the notification to be handled successfully add the following line to the <code>onNewIntent</code> method of this activity: * <pre> * {@code * protected void onNewIntent(Intent intent) { * super.onNewIntent(intent); * BLEKit.processIntent(intent, this); //add this line * } * } * </pre> * * @param intent Android Intent * @param activity Android Activity */ public static void processIntent( Intent intent, Activity activity ) { if( intent==null ) return; String type = intent.getStringExtra("type"); if( type==null ) return; BLEAction action = mActionsFactory.get(type); if( action!=null ) { action.processIntent( intent, activity ); } } /** * Checks the BLEKit states whether it is already started. * * @return <code>true</code> if BLEKit is started, <code>false</code> otherwise */ public static boolean isStarted() { return _bleKit!=null && _bleKit.mBound; } /** * Returns a map of monitored beacons with their current proximity value. * * @return map of beacons */ public static Map<String, Proximity> getCurrentBeaconStates() { return mCurrentBeaconsStates; } /** * Returns current zone configuration. * * @return current zone */ public static Zone getZone() { return mCurrentZone; } /** * Starts an async task to fetch JSON. */ private void fetchJson() { L.d("."); FetchJsonAsyncTask task = new FetchJsonAsyncTask(); task.execute( jsonUrl ); } private static void fetchJsonLocal() { L.d("."); AsyncTask<String, Void, JsonNode> task = new AsyncTask<String, Void, JsonNode>() { @Override protected JsonNode doInBackground(String... params) { L.d( "fetching from " + params[0] ); HttpClient client = new HttpClient( params[0] ); Response<JsonNode> response = client.get( JsonNode.class, null ); return response.getBody(); } @Override protected void onPostExecute(JsonNode s) { L.d( "fetched " + s ); if( s!=null ) { mCurrentZone = jsonParser.parse(s+""); } } }; task.execute( jsonUrl ); } private static void showErrorDialog(String msg, Activity activity, boolean bleUnavailable) { ErrorDialogFragment dlg = new ErrorDialogFragment(msg, bleUnavailable); dlg.show( activity.getFragmentManager(), null ); } private static class ErrorDialogFragment extends DialogFragment { private String msg; private boolean bleUnavailable; public ErrorDialogFragment(String msg, boolean bleUnavailable) { this.msg = msg; this.bleUnavailable = bleUnavailable; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder .setMessage(msg) .setNegativeButton(R.string.blekit_exit, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { getActivity().finish(); } }); if( !bleUnavailable ) { builder.setPositiveButton(R.string.blekit_turn_bt_on, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intentOpenBluetoothSettings = new Intent(); intentOpenBluetoothSettings.setAction(android.provider.Settings.ACTION_BLUETOOTH_SETTINGS); startActivity(intentOpenBluetoothSettings); } }); } setCancelable(false); return builder.create(); } } private void checkStarted() { if( mBound ) { throw new IllegalStateException( "BLEKit is already started, stop it first" ); } } private static void checkInitialized() { if( _bleKit==null ) { throw new IllegalStateException( "BLEKit is not initialized, call create() first." ); } } private void updateZone(String zoneJson) { if( zoneJson==null ) return; final Zone newZone = jsonParser.parse(zoneJson); BeaconPreferences.setLastZoneJson(mContext, zoneJson); L.d( "updateZone: " + newZone ); if( mCurrentZone!=null ) { if( newZone!=null ) { sendUpdateBeacons( newZone.beacons ); } mCurrentZone = newZone; } else { mCurrentZone = newZone; sendStart( mCurrentZone.beacons ); } if( mZoneUpdateListener!=null ) { mZoneUpdateListener.onZoneUpdated(newZone); } } private void sendUpdateBeacons( List<Beacon> beacons ) { Intent intent = getServiceIntent(); intent.putExtra(BLEKitService.Extra.EXTRA_COMMAND, BLEKitService.Extra.COMMAND_UPDATE_BEACONS); intent.putStringArrayListExtra(BLEKitService.Extra.EXTRA_BEACONS_LIST, beaconsToIds(beacons)); sendCommandToService(intent); } private void sendStart( List<Beacon> beacons ) { Intent intent = getServiceIntent(); intent.putExtra(BLEKitService.Extra.EXTRA_COMMAND, BLEKitService.Extra.COMMAND_START_SCAN); intent.putExtra(BLEKitService.Extra.EXTRA_BACKGROUND_MODE, mBackgroundMode.inBackground); intent.putStringArrayListExtra(BLEKitService.Extra.EXTRA_BEACONS_LIST, beaconsToIds(beacons)); sendCommandToService(intent); } private void sendSetBackgroundMode( BackgroundMode backgroundMode ) { Intent intent = getServiceIntent(); intent.putExtra(BLEKitService.Extra.EXTRA_COMMAND, BLEKitService.Extra.COMMAND_SET_BACKGROUND_MODE); intent.putExtra(BLEKitService.Extra.EXTRA_BACKGROUND_MODE, backgroundMode.inBackground); sendCommandToService(intent); } private void sendStop() { Intent intent = getServiceIntent(); intent.putExtra(BLEKitService.Extra.EXTRA_COMMAND, BLEKitService.Extra.COMMAND_STOP_SCAN); sendCommandToService(intent); } private Intent getServiceIntent() { return new Intent( BLEKitService.ACTION ); } private void sendCommandToService(Intent intent) { intent.putExtra(BLEKitService.Extra.EXTRA_CLIENT_APP_PACKAGE, mContext.getPackageName()); mContext.startService(intent); } private ArrayList<String> beaconsToIds( List<Beacon> beacons ) { ArrayList<String> ids = new ArrayList<String>(); for( Beacon beacon : beacons ) { ids.add(beacon.id.toLowerCase()); } return ids; } private class FetchJsonAsyncTask extends AsyncTask<String, Void, JsonNode> { @Override protected JsonNode doInBackground(String... params) { L.d( "fetching from " + params[0] ); HttpClient client = new HttpClient( params[0] ); Response<JsonNode> response = client.get( JsonNode.class, null ); return response.getBody(); } @Override protected void onPostExecute(JsonNode s) { L.d( "fetched " + s ); if( s!=null ) { updateZone(s+""); } } } protected interface Extra { public static final String EXTRA_BEACON_EVENT = "com.upnext.blekit.extra.BEACON_EVENT"; public static final String EXTRA_BEACON_ID = "com.upnext.blekit.extra.BEACON_ID"; public static final String EXTRA_CLIENT_ADD = "com.upnext.blekit.extra.CLIENT_ADD"; public static final String EXTRA_CLIENT_REMOVE = "com.upnext.blekit.extra.CLIENT_REMOVE"; public static final String EXTRA_CURRENT_BEACON_PROXIMITY = "com.upnext.blekit.extra.CURRENT_BEACON_PROXIMITY"; } /** * Processes intent sent by BLEKitService. * * @param intent intent containing data * @param ctx context */ protected static void processServiceEvent(Intent intent, Context ctx) { L.d("."); BLEKitClient clientAdd = intent.getParcelableExtra(Extra.EXTRA_CLIENT_ADD); if( clientAdd!=null ) { L.d(". add " + clientAdd.getPackageName() ); BeaconPreferences.addClient( ctx, clientAdd ); return; } BLEKitClient clientRemove = intent.getParcelableExtra(Extra.EXTRA_CLIENT_REMOVE); if( clientRemove!=null ) { L.d(". remove " + clientRemove.getPackageName() ); BeaconPreferences.removeClient(ctx, clientRemove.getPackageName()); return; } CurrentBeaconProximity currentBeaconProximity = intent.getParcelableExtra(Extra.EXTRA_CURRENT_BEACON_PROXIMITY); if( currentBeaconProximity!=null ) { L.d(". update proximity"); mCurrentBeaconsStates.put( currentBeaconProximity.getBeaconId(), currentBeaconProximity.getProximity() ); if( mStateListener!=null ) { mStateListener.onCurrentBeaconProximityReceived( currentBeaconProximity.getBeaconId(), currentBeaconProximity.getProximity() ); } return; } //fresh start, we do not have instance - app brought from the dead if( _bleKit==null ) { L.d(". restart"); restartBlekit(ctx); mEventToProcess = intent; return; } String event = intent.getStringExtra(Extra.EXTRA_BEACON_EVENT); if( event!=null ) { L.d(". event " + event ); BeaconEvent beaconEvent = BeaconEvent.valueOf( event ); String beaconId = intent.getStringExtra(Extra.EXTRA_BEACON_ID); mCurrentBeaconsStates.put( beaconId, Proximity.fromBeaconEvent(beaconEvent) ); for( Beacon beacon : getBeaconsFromZone(beaconId) ) { _bleKit.processTriggersForBeacon( beacon, beaconEvent, ctx ); } } mEventToProcess = null; } private static void restartBlekit(Context context) { Intent intnt = new Intent("com.upnext.blekit.service.RESTARTER"); intnt.setPackage(context.getPackageName()); if( context.getPackageManager().resolveService( intnt, 0 ) !=null ) { context.startService(intnt); } } private static List<Beacon> getBeaconsFromZone( String beaconId ) { List<Beacon> beacons = new ArrayList<Beacon>(); if( mCurrentZone==null || mCurrentZone.beacons==null ) { return beacons; } for( Beacon beacon : mCurrentZone.beacons ) { if( beacon.id.equalsIgnoreCase(beaconId) ) { beacons.add(beacon); } } return beacons; } private void processTriggersForBeacon(Beacon beacon, BeaconEvent beaconEvent, Context ctx) { L.d( "Processing for beacon '" + beacon.name + "' " + beaconEvent ); if( mBeaconEventListener!=null ) { mBeaconEventListener.onEvent(beaconEvent, beacon); } final ConditionsFactory conditionsFactory = BLEKit.getConditionsFactory(); final ActionsFactory actionsFactory = BLEKit.getActionsFactory(); for(Trigger trigger : beacon.triggers) { L.d( "Processing trigger '" + trigger.name + "'" ); boolean conditionsMet = allConditionsMet( trigger, conditionsFactory, beaconEvent, beacon, ctx ); if( !conditionsMet ) continue; //all conditions met performAction(actionsFactory, trigger, ctx); } } private void performAction(final ActionsFactory actionsFactory, Trigger trigger, Context ctx) { BLEAction bleAction = actionsFactory.get( trigger.action.type, trigger.action.parameters ); if( bleAction==null ) { L.d("Did not find action implementation for type '" + trigger.action.type + "'"); return; } L.d("." + mBackgroundMode.inBackground); bleAction.performAction(ctx, mBackgroundMode); } private boolean allConditionsMet(Trigger trigger, final ConditionsFactory conditionsFactory, BeaconEvent beaconEvent, Beacon beacon, Context ctx) { boolean conditionsMet = true; for (Condition condition : trigger.conditions) { BLECondition bleCondition = conditionsFactory.get(condition.type, beaconEvent, condition.parameters, condition.expression, ctx); if( bleCondition==null ) { L.d( "Did not find condition implementation for type '" + condition.type + "' and event '" + beaconEvent + "'" ); conditionsMet = false; break; } else { bleCondition.setZone(mCurrentZone); bleCondition.setBeacon(beacon); bleCondition.setTrigger(trigger); increaseOccurence(bleCondition, beacon.id); } if( !bleCondition.conditionMet() ) { L.d( "Condition not met: '" + condition.type + "'" ); conditionsMet = false; break; } } return conditionsMet; } private void increaseOccurence(BLECondition bleCondition, String beaconId) { if( !(bleCondition instanceof OccurenceCondition) ) return; OccurenceCondition condition = (OccurenceCondition) bleCondition; beaconsDB.addBeaconEvent( condition.getBeaconEvent(), beaconId ); condition.setBeaconsDB(beaconsDB); condition.setBeaconId(beaconId); } }