Skip to content

varun2264/MNProximityManager-Android-SDK

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Android Proximity Manager SDK 0.1.0

The Android Proximity Manager, APM from now on, is a library dedicated to manage the interaction between an App and Mobiquity's beacons network. The integration of this SDK will enable your App to react based on the proximity to a beacon of yours or Mobiquity's. At the time of this writing the SDK version is 0.1.0, so some deep changes to the api might come up in future versions.

Release notes

  • 0.1.0
    First release (beta).

Environment

Following you will find the requirements to start programming an App which benefits of Mobiquity's proximity network thanks to APM:

  • First, you will need to install Android support for your IDE of choice (Eclipse, Intellij, ..) usually in the form of a plugin.
  • Second, you will need the Android SDK with api level 18 or higher installed on your IDE, usually from the Android SDK Manager.
  • Third, you will need to have installed the Android SDK Tools which let you debug and develop with a real device, usually from the Android SDK Manager as well.
  • Finally, to develop you will also need a device with a Bluetooth Low Energy compatible chipset running Android 4.3 or higher.

Project setup

The following instructions assume you have created an Android project in your IDE. The lines below explain how you must configure the project to start developing. As the SDK depends on some other jars you will also need to include them in your project together with the APM jar file mnapm.jar.

You can go through this process by manually downloading the jars from the Internet or by using a dependency control manager like Maven or Gradle. No matter how but you must end up with all these jars on your project's build path:

  • mnapm-0.1.0.jar
  • retrofit-1.4.1.jar
  • guava-17.0.jar
  • gson-2.2.4.jar
  • google play services jar

The next thing to do is to set up the AndroidManifest.xml file with some mandatory information that the APM needs in order to work properly:

  • Permissions required by the App:
<permission 
	android:name="mobiquitynetworks.permission.SERVICE" 
	android:label="mobiquity service permission" 
	android:protectionLevel="signature" />
<permission 
	android:name="mobiquitynetworks.permission.BROADCAST" 
	android:label="mobiquity broadcast permission" 
	android:protectionLevel="signature" />
     
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="mobiquitynetworks.permission.SERVICE"/>
<uses-permission android:name="mobiquitynetworks.permission.BROADCAST"/>

  • Receiver responsible of booting the underlying service up on several system conditions:
<receiver 
	android:name="com.mobiquitynetworks.receivers.MobiquityReceiver"
	android:exported="true">
	<intent-filter>
		<action android:name="android.intent.action.BOOT_COMPLETED"/>
		<action android:name="android.bluetooth.adapter.action.STATE_CHANGED"/>
	</intent-filter>
</receiver>

  • Services to add:
<service 
	android:name="com.mobiquitynetworks.service.MobiquityService" 
	android:exported="false" />
         
<service 
	android:name="com.mobiquitynetworks.service.MonitoringService" 
	android:exported="false" />

To understand why you have to add all these components to your Manifest you should know that APM's heavy duty is based on an underlying service capable of monitoring the environment on background, ranging on foreground, sendind statistics and downloading relevant content when a beacon is found. So, all these components assist the APM's forementioned service to get the job done: booting, staying awake and scanning the environment with a minimal footprint on the device battery life.

The final step of the setup is to create a properties file in assets/properties/mobiquity.properties where you will place your App key and secret that you got from the Mobiquity Networks Management Panel.

	mobiquity.apikey=a90a26bab9868d071c1e4325a9623df284efd384
	mobiquity.secret=e6c9d0f81fc25d4f11950153d37b44e39d0ba6b9
	mobiquity.cache.eviction_time=3
	mobiquity.monitoring.on_period=5000
	mobiquity.monitoring.off_period=25000
	mobiquity.boot.retry_period=1800000

As you can see in this file you are not only setting which is your App key and secret, you can set also many other optional parameters that configure how APM behaves.


Api usage

The key principle that has driven the api design has been that the integration required the minimum code possible on the App's side, making the integration a painless process. In order to accomplish this goal, a lot of hard work is done by APM under the hood. Focusing on the visible side of the api, there exists a first-class citizen in the SDK which internally forwards to other components api requests and orchestrates their outputs, the MobiquityManager facade class. This is the class you will be dealing with most of the time and next sections show off it's main responsabilities and method calls.

###Connecting to the underlying service

The very first thing to do when developing with APM is to connect to the underlying running service. A suitable place to make this happen is the Activity's onCreate method. Depending on your application flow and internal states you may decide to make the connection somewhere else and it's fine. Moreover, your business flow could force your App to connect from several entry points, you can accomplish that with no further effort since APM is able to handle the situation transparently.

@Override
protected void onCreate(Bundle savedInstanceState) {
	
	...

	MobiquityManager.connect(this, new On.ServiceReady() {
			
		@Override
		public void onReady() {
				
			MobiquityManager.startRanging();
			...
		}
			
		@Override
		public void onError(State errorState) {
				
			Toast errorToast = Toast.makeText(MainActivity.this, "Cannot start proximity service.", Toast.LENGTH_LONG);
			errorToast.show();
		}
	});
}

###Scanning the environment

When the service has finished booting with no errors, it will be ready to accept requests and at that time the onReady callback will be called, otherwise the error callback will be called. Once the internal connection is stablished you may start ranging the environment. As you can see in the example above, this is the first action we take when the service is connected as the App is in foreground and it's fine to start ranging at this Activity's lifecycle point.

When the App goes to background you can change the scanning mode to monitoring to minimize the battery drain of the BLE (Bluetooth Low Energy) scanning operation. A perfect point to perform this change is onPause or onStop since at this time the App is about to go to background:

@Override
protected void onPause(){
	
	super.onPause();		
	MobiquityManager.startMonitoring();
	...	
}

And the other way around when the App comes into foreground:

@Override
protected void onResume(){
		
	super.onResume();
	if( MobiquityManager.isConnected() )
		MobiquityManager.startRanging();
	...	
}

When you change between scanning modes don't need to stop ( stopMonitoring, stopRanging ) the current mode before starting the other ( startRanging, startMonitoring ) because this is handled internally. In addition, if your App's flow needs to stop scanning the environment at some point just call stopMonitoring or stopRanging.

Last but not least, you can set up via the properties config file the ON and OFF cycle durations of the monitoring background operation. The default values are 5 and 15 seconds respectively.

Handling beacon events

One of the design principles of APM's api has been the seamless integration with Android. Unlike other beacon frameworks that make your Activities implement an interface, all events will get into your Activity as Intents, by doing so, APM moves out of the way from your class hierarchy. These are the different Broadcast Intents that APM will broadcast:

  • MobiquityManager.ACTION_BEACON_DISCOVERY
  • MobiquityManager.ACTION_BEACON_UPDATE
  • MobiquityManager.ACTION_BEACON_DROPPING_PACKETS
  • MobiquityManager.ACTION_BEACON_DROPPING_PACKETS2
  • MobiquityManager.ACTION_BEACON_TIMEOUT

The meaning is very straightforward,

Below this line you have a simple example of how to create a Broadcast Receiver to deal with beacon events.


private BroadcastReceiver beaconReceiver = new BroadcastReceiver(){

	@Override
	public void onReceive(Context context, Intent intent) {
		
		final Beacon beacon = (Beacon)intent.getSerializableExtra(MobiquityManager.EXTRAS_BEACON_KEY);
		
		if( intent.getAction().equals( MobiquityManager.ACTION_BEACON_DISCOVERY ) ){
			
			...
			
		}else if( intent.getAction().equals( MobiquityManager.ACTION_BEACON_ANNOUNCEMENT_TIMEOUT )){
			
			...
		}
	}
};

Some event types are delivered as Broadcast Intent while others are delivered as both Local Broadcast Intent and Broadcast Intent. Below you can check out several examples of the registration process.

  • Dynamically registering and unregistering from the Local Broadcast Manager:
@Override
public void onResume(){
			
	super.onResume();		
	IntentFilter filterDiscovery = new IntentFilter(MobiquityManager.ACTION_BEACON_DISCOVERY);
	IntentFilter filterTimeout = new IntentFilter(MobiquityManager.ACTION_BEACON_TIMEOUT);
	IntentFilter filterUpdate = new IntentFilter(MobiquityManager.ACTION_BEACON_UPDATE);
	LocalBroadcastManager.getInstance(getActivity()).registerReceiver(beaconReceiver, filterDiscovery);
	LocalBroadcastManager.getInstance(getActivity()).registerReceiver(beaconReceiver, filterTimeout);
	LocalBroadcastManager.getInstance(getActivity()).registerReceiver(beaconReceiver, filterUpdate);
	...
}

@Override
public void onPause(){
			
	super.onPause();
	LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(beaconReceiver);
	...	
}

  • Dynamically registering and unregistering a Broadcast Receiver:
@Override
public void onResume(){
			
	super.onResume();		
	IntentFilter filter = new IntentFilter();
	filter.addAction(MobiquityManager.ACTION_BEACON_DISCOVERY);
	filter.addAction(MobiquityManager.ACTION_BEACON_TIMEOUT);
	registerReceiver(beaconReceiver, filter);
	...
}

@Override
public void onPause(){
			
	super.onPause();
	unregisterReceiver(beaconReceiver);
	...	
}

  • Statically registering a Broadcast Receiver:
<receiver
	android:name=".receivers.BeaconsReceiver"
	android:exported="false">
	<intent-filter>
		<action android:name="com.mobiquitynetworks.action.BEACON_DISCOVERY"/>
		<action android:name="com.mobiquitynetworks.action.BEACON_TIMEOUT"/>
	</intent-filter>
</receiver>

###Getting proximity content

Once you get a beacon event and unwrap the beacon object from the Intent, you may want to request the deployed data for this beacon by calling the asynchronous method requestBeaconData. Below you can find a Broadcast Receiver snippet with a content request:

@Override
public void onReceive(Context context, Intent intent) {
	
	...
	final Beacon beacon = (Beacon)intent.getSerializableExtra(MobiquityManager.EXTRAS_BEACON_KEY);
	MobiquityManager.requestBeaconData(beacon, new On.RequestResolution<BeaconData>() {
						
		@Override
		public void onRequestSuccess(BeaconData data) 
			
			...
			mAdapter.notifyDataSetChanged();
			
		}
	
		@Override
		public void onRequestError( RequestError err ) {
			
		}
	
		@Override
		public void onRequestOngoing() {
			
		}
	});
	...

}

The BeaconData object that is returned from the success callback exposes a set of methods that lets you get the campaigns, resources and notifications deployed on the beacon. A thing to highlight is that all callback methods are called within the main UI thread.

###Getting Beacon information

When you catch an APM triggered Broadcast Intent and unwrap the Beacon object from the latter, can get a lot of intrinsic information about the emitting device by enquirying this Beacon object. The following list points out a few features you have access to about a beacon sensor:

  • Name
  • Mac address
  • Minor, major and UUID
  • Distance
  • Distance Type
  • Last rssi measure
  • Creation timestamp
  • Update timestamp
  • Idle time
  • Elapsed time
  • Estimated announcement period
  • Announcements counter

This information is extremely useful because lets you trigger business logic based on richer condition sets than just a mere presence switch.

###Tracking the user

As the user walks around a venue surrounded by beacons, APM will automatically send tracking information (device information and user information if available) under different conditions: when a beacon is first discovered, when announcement packets are being dropped by connectivity issues or when a beacon becomes out of range. Besides these internally generated events, as a developer you can track other stuff like campaigns viewed, resources viewed and so on. You will be able to manually track by calling some methods exposed by the facade component MobiquityManager class.

Following you have some examples of explicit tracking to get insight into how to do it:

@Override
public void onListItemClick(ListView l, View v, int position, long id ){
	
	//get campaign from in memory datastore
	Campaign campaign = DataManager.getAllCampaigns().get(position);
	MobiquityManager.sendCampaignViewedEvent(campaign);
	...
}	
@Override
public void onListItemClick(ListView l, View v, int position, long id ){
			
	//get resource from in memory datastore
	Resource resource = mCampaign.getResources().get(position);
	MobiquityManager.sendResourceViewedEvent(resource);
	...
}	

If you want to append some user information on every tracking request you can do so by informing the SDK about the user:

@Override
protected void onCreate(Bundle savedInstanceState) {
	
	...

	MobiquityManager.connect(this, new On.ServiceReady() {
			
		@Override
		public void onReady() {
			
			//BUILDING USER TRACKING INFORMATION
			TrackingUser trackingUser = new TrackingUser.Builder("developer")
				.provider("facebook.com")
				.username("enric@mobiquitynetworks.com")
				.audience(new TrackingAudience.Builder()
					.education(Education.GRAD_SCHOOL)
					.gender(Gender.MALE)
					.maritalStatus(MaritalStatus.SINGLE)
					.build())
				.build();						
			
			//INFORMING APM ABOUT THE USER	
			MobiquityManager.setTrackingUserInformation(trackingUser);
			...
			MobiquityManager.startRanging();
			
		}
			
		...
	});
}	

The above piece of code appends some user information to the overall tracking information, so when beacon events show up the user structure will be sent together with the device and event structures. The JSON representation for an exit beacon event might look like this:

{ device: 
   { idDev: '70c1dc255de67868',
     idFA: '2de252cf-566e-4292-a9d3-532255dfa520',
     type: 'samsung GT-I9505',
     os: 'Android',
     osVersion: '4.4.2' },
  event: 
   { timestamp: '2014-07-14T15:19:02.809Z',
     type: 'EXBC',
     value: 
      { minor: 210,
        major: 1,
        uuid: '03BBAC2B-46ED-8B5A-51D5-79AB39DE6526' } },
  sdk: { version: '0.1.0' },
  user: 
   { audience: { education: 'GS', gender: 'M', maritalStatus: 'SG', kids: 0 },
     provider: 'facebook.com',
     role: 'developer',
     username: 'enric@mobiquitynetworks.com' } 
}

At any moment the user tracking info can be removed by calling MobiquityManager.removeTrackingUserInformation, from that point onwards no user info will be appended to the requests.


##License

Mobiquity Technologies, Inc. All rights reserved. See the LICENSE file for more info.

About

An Android SDK to interact with the Mobiquity Networks Proximity Network (iBeacons & Geofences)

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published