How do I implement background service for kontakt.io sdk? - android

If I enter a region of a beacon with my Android device I like to show a notification. Thats well documented at Android SDK Quickstart
This is just working as long as the app is active. How do I get notifications when the app is closed?

I build a service by myself:
BeaconRangingService.java
public class BeaconRangingService extends Service {
private static final String TAG = BeaconRangingService.class.getSimpleName();
private BeaconManager beaconManager;
#Override
public void onCreate() {
super.onCreate();
beaconManager = BeaconManager.newInstance(getApplicationContext());
beaconManager.setMonitorPeriod(MonitorPeriod.MINIMAL);
beaconManager.setForceScanConfiguration(ForceScanConfiguration.DEFAULT);
beaconManager.registerMonitoringListener(new BeaconManager.MonitoringListener() {
#Override
public void onMonitorStart() {
Log.v(TAG, "start monitoring beacons");
}
#Override
public void onMonitorStop() {
Log.wtf(TAG, "stop monitoring beacons");
}
#Override
public void onBeaconsUpdated(Region region, List<Beacon> list) {
}
#Override
public void onBeaconAppeared(Region region, Beacon beacon) {
Toast.makeText(getApplicationContext(), "Beacon appeared\n BEACON ID: " + beacon.getBeaconUniqueId(), Toast.LENGTH_SHORT).show();
}
#Override
public void onRegionEntered(Region region) {
}
#Override
public void onRegionAbandoned(Region region) {
}
});
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v(TAG, "service started");
if (!beaconManager.isBluetoothEnabled()) {
Log.w(TAG, "bluetooth disabled, stop service");
stopSelf();
} else {
connect();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.v(TAG, "service destroyed");
beaconManager.stopMonitoring();
beaconManager.disconnect();
beaconManager = null;
super.onDestroy();
}
private void connectBeaconManager() {
try {
beaconManager.connect(new OnServiceBoundListener() {
#Override
public void onServiceBound() {
try {
HashSet<Region> regions = new HashSet<>();
regions.add(Region.EVERYWHERE);
beaconManager.startMonitoring(regions);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
}
AndroidManifest.xml
<service
android:name="com.your.package.BeaconRangingService"
android:exported="false"/>
start service
Intent intent = new Intent(this, BeaconRangingService.class);
startService(intent);

I know nothing regarding kontakt.io but there is a library and reference app for AltBeacon which provides this functionality. https://github.com/AltBeacon
I believe this is generic Android functionality, and not anything magic to their implementation.

#erdna have you tested the sample kontakt admin app? There is an approach in which Toasts appear when the application is in foreground and standard notifications appear when the app is working in background.
https://github.com/kontaktio/kontakt-beacon-admin-sample-app

#erdna I guess that it should be IntentService for long running services, that monitors incoming beacon events as intents in a onHandleIntent(Intent intent) method. #dawid-gdanski I'm not sure what class do you refer to.

Related

Could not found any beacon with altbeacon android

I am using altbeacon for android and i cant't detect my beacon. I have tried https://github.com/AltBeacon/android-beacon-library-reference sample code also but can't detect beacon. Here is my code:
public class BeaconApplication extends Application implements BootstrapNotifier {
private Region region;
private RegionBootstrap regionBootstrap;
private BeaconManager beaconManager;
#Override
public void onCreate() {
super.onCreate();
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));
beaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setBackgroundScanPeriod(5000);
beaconManager.setBackgroundBetweenScanPeriod(10000);
region = new Region("backgroundRegion",
Identifier.parse("EBEFD083-70A2-47C8-9837-E7B5634DF524"), null, null);
regionBootstrap = new RegionBootstrap(this, region);
Log.i("selfBeacon", "Bootstrap created");
}
#Override
public void didEnterRegion(Region region) {
Log.i("selfBeacon", "Bootstrap didEnterRegion");
regionBootstrap.disable();
Intent intent = new Intent(this, SelfBeaconService.class);
if (Build.VERSION.SDK_INT >= 26) {
startForegroundService(intent);
} else {
startService(intent);
}
Log.i("selfBeacon", "Service start commanded");
}
#Override
public void didExitRegion(Region region) {
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
public void resumeScanning () {
beaconManager.setBackgroundScanPeriod(5000);
beaconManager.setBackgroundBetweenScanPeriod(10000);
regionBootstrap = new RegionBootstrap(this, region);
Log.i("selfBeacon", "scanning resumed");
}
}
public class SelfBeaconService extends Service implements BeaconConsumer {
private BeaconManager beaconManager;
private Region region;
private int noBeaconDetectedCount = 0;
#Override
public void onCreate() {
super.onCreate();
Log.i("selfBeaconService", "onCreate");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("selfBeaconService", "onStartCommand");
broadcastSystemLog("Beacon Service onCreate triggered.");
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.setEnableScheduledScanJobs(false); //Stop scanning
beaconManager.setForegroundScanPeriod(2000);
beaconManager.setForegroundBetweenScanPeriod(2000);
beaconManager.bind(this);
region = new Region("foreground region",
Identifier.parse("EBEFD083-70A2-47C8-9837-E7B5634DF524"), null, null);
startForeground();
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onBeaconServiceConnect() {
Log.i("selfBeaconService", "onBeaconServiceConnect");
broadcastSystemLog("onBeaconServiceConnect triggered.");
beaconManager.addRangeNotifier(new RangeNotifier() {
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
if (collection.size() > 0) {
noBeaconDetectedCount = 0;
double closestDistance = -1;
for (Beacon each : collection) {
if (closestDistance == -1) {
closestDistance = each.getDistance();
} else if (each.getDistance() < closestDistance) {
closestDistance = each.getDistance();
}
}
Log.i("selfBeaconService", "didRangeBeaconsInRegion, the closest beacon is about " +
closestDistance + " meters away.");
broadcastToActivity("The closest beacon is about " +
closestDistance + " meters away.");
} else {
noBeaconDetectedCount++;
broadcastToActivity("No beacon has been detected for " + noBeaconDetectedCount + " times");
if (noBeaconDetectedCount > 10) { //10*(2000ms+2000ms) = 40 seconds
stopForeground(true);
terminate();
}
}
}
});
try {
beaconManager.startRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
Log.i("selfBeacon", "onDestroy");
broadcastSystemLog("BeaconService onDestroy triggered.");
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void broadcastToActivity (String message) {
Intent intent = new Intent();
intent.setAction("beaconBroadcast");
intent.putExtra("beaconService", message);
sendBroadcast(intent);
}
private void broadcastSystemLog (String message) {
Intent intent = new Intent();
intent.setAction("beaconBroadcast");
intent.putExtra("beaconServiceLog", message);
sendBroadcast(intent);
}
private void startForeground () {
NotificationCompat.Builder notificationBuilder = null;
Notification notification = null;
if (Build.VERSION.SDK_INT >= 26) {
notificationBuilder = new NotificationCompat.Builder(this, "rangingService")
.setContentTitle("Active Scanning")
.setContentText("App is scanning for nearby beacons");
notification = notificationBuilder.build();
} else {
notificationBuilder = new NotificationCompat.Builder(this)
.setContentTitle("Active Scanning")
.setContentText("App is scanning for nearby beacons");
notification = notificationBuilder.build();
}
startForeground(1234, notification);
}
private void terminate () {
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
beaconManager.removeAllRangeNotifiers();
beaconManager.unbind(this);
beaconManager.setEnableScheduledScanJobs(true);
((BeaconApplication)getApplication()).resumeScanning();
stopSelf();
Log.i("selfBeaconService", "service stopped");
broadcastSystemLog("BeaconSevice stopped.");
}
}
A few things to check:
Ensure you have added code to dynamically request location permission at runtime. See here for how to do that.
After adding the above, make sure this permission has been properly obtained. Go to. Settings->Apps->{your app name}->Permissions to see
Make sure Bluetooth and Location are enabled on your phone.
If you have checked all of the above and it still does not work, try an off the shelf beacon detector like BeaconScope. If it does not detect, there may be a problem with either your phone hardware or your beacon hardware.

why restart the service

i have a problem in my service, the service is runnig from MainActivity (i am doing test) and extends of service.
i want to use the service from foreground and background (when the app is closed) and i already have my first problem:
my service(have a counter that is displayed by LOG) is restarting when i close the app.
also i want to be able to use the service with the open app and close app, in other words to use both the Service Started and Link Service
public class MyService extends Service {
private Thread backgroundThread;
private boolean isRunning;
public MyService() {
Log.e("MyService","constructor");
}
#Override
public void onCreate() {
super.onCreate();
isRunning = false;
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Log.e("onStartCommand","Servicio Llamado");
if (!this.isRunning) {
Log.e("onStartCommand","hilo iniciandose");
this.backgroundThread = new Thread(myTask);
runTask();
}
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e("onDestroy","servicio destuido");
}
private void runTask(){
this.isRunning = true;
this.backgroundThread.start();
}
private Runnable myTask = new Runnable() {
public void run() {
Log.e("myTask","hilo iniciado");
int i = 0;
do{
pauseService();
Log.e("myTask","hilo contador: "+i);
//Toast.makeText(getApplicationContext(),"CONTADOR = "+j, Toast.LENGTH_SHORT).show(); //no working :(
i++;
}while (i<10);
/*
//linea de detencion del servicio
//stopSelf();
isRunning=false;
backgroundThread.interrupt();
//backgroundThread = new Thread(myTask);
*/
Log.e("myTask","hilo cerrado");
}
};
private void pauseService(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
In main Activity
Intent intent = new Intent(MainActivity.this,MyService.class);
intent.putExtra("iteraciones",10);
startService(intent);
why because the service restarts when I close the application and how can I avoid it?

Issue in AltBeacon Monitoring and Ranging android

I am using this code for ranging and monitoring in Altbeacon
class Appclass extends Application implements BootstrapNotifier {
private RegionBootstrap regionBootstrap;
private BackgroundPowerSaver backgroundPowerSaver;
private boolean haveDetectedBeaconsSinceBoot = false;
public static Region region1;
private static boolean activityVisible;
public static Appclass instances;
public static BeaconManager beaconManager;
public void onCreate() {
super.onCreate();
instances = this;beaconManager=org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setForegroundScanPeriod(1100l);
beaconManager.setForegroundBetweenScanPeriod(0l);
beaconManager.setAndroidLScanningDisabled(true);
beaconManager.setBackgroundBetweenScanPeriod(01);
beaconManager.setBackgroundScanPeriod(1100l);
try {
beaconManager.updateScanPeriods();
} catch (Exception e) {
}
Log.d("", "setting up background monitoring for beacons and power saving");
// wake up the app when a beacon is seen
region1 = new Region("backgroundRegion",
null, null, null);
regionBootstrap = new RegionBootstrap(this, region1);
backgroundPowerSaver = new BackgroundPowerSaver(this);
}
#Override
public void didEnterRegion(Region region) {
Log.d("ABC", "Enter");
Log.d("ABC value", region.getId2() + " " + region.getId3());
try { Intent i = new Intent(getApplicationContext(), AbcService.class);
startService(i);
} catch (Exception e) {
}
}
#Override
public void didExitRegion(Region region) {
Log.d("ABC", "exit");
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
and then in my AbcService class code is:
class AbcService extends Service implements BeaconConsumer, MonitorNotifier, RangeNotifier {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Appclass.beaconManager.bind(this);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
} catch (Exception e) {
}
return START_STICKY;
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
Log.d("ABC", "range");
}
#Override
public void onBeaconServiceConnect() {
Appclass.beaconManager.setMonitorNotifier(this);
Appclass.beaconManager.setRangeNotifier(this);
}
#Override
public void didEnterRegion(Region region) {
try {
Log.d("ABC", "didEnterRegion");
Log.d("ABC", "" + region.getId2() + region.getId3());
Appclass.beaconManager.startRangingBeaconsInRegion(Appclass.region1);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didExitRegion(Region region) {
try {
Log.d("ABC", "didExitRegion");
Appclass.beaconManager.stopRangingBeaconsInRegion(Appclass.region1);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
}
}
now issue are getting that the didEnterRegion method of Application class calling every time when we enter in beacon range but the didEnterRegion method of AbcService class not calling some time and also not start ranging. what is the issue in my code?
A few tips:
Start ranging the same time as you start monitoring. There is no reason to wait for an entered region callback or to stop ranging when you exit the region.
Add logging to didDetermineStateFirRegion. This method gets called when a beacon appears after app startup even if the device was already in region from when it was previously running. didEnterRegion only gets called if beacons matching the region actually disappear for 15+ seconds and then reappear.

How to create notification with media controls for API 16 service

I have a service playing music, and I need it do display a notification with "play", "pause" and "stop" buttons. My service code is:
public class RadioService extends Service implements MediaPlayer.OnPreparedListener {
MediaPlayer radioPlayer;
String url = "radiourl";
String action;
public RadioService() {
}
#Override
public IBinder onBind(Intent intent) {
Log.e("Service", "Bind");
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e("Service", "onStart");
action = intent.getAction();
Log.e("ServiceAction", action);
switch (action) {
case "play":
radioPlayer = new MediaPlayer();
radioPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
radioPlayer.setDataSource(url);
} catch (IOException e) {
Log.e("setDataSource", e.toString());
}
radioPlayer.prepareAsync();
radioPlayer.setOnPreparedListener(this);
}
return START_STICKY;
}
#Override
public void onPrepared(MediaPlayer radioPlayer) {
Log.e("Service", "onPrepared");
radioPlayer.start();
}
#Override
public void onDestroy() {
Log.e("Service", "onDestroy");
if(radioPlayer != null && radioPlayer.isPlaying()) {
radioPlayer.stop();
radioPlayer.reset();
radioPlayer.release();
}
super.onDestroy();
}
}
My notification has to be compatible with API 16 and higher. I want notification buttons to send an action to my service, that will execute a proper case in my switch instruction. Is this even possibe? How should my service look like?

Android remote service doesn't call service methods

I'm developing a GPS tracking software on android. I need IPC to control the service from different activities. So I decide to develop a remote service with AIDL. This wasn't a big problem but now it's always running into the methods of the interface and not into those of my service class. Maybe someone could help me?
Here my AIDL file:
package test.de.android.tracker
interface ITrackingServiceRemote {
void startTracking(in long trackId);
void stopTracking();
void pauseTracking();
void resumeTracking(in long trackId);
long trackingState();
}
And the here a short version of my service class:
public class TrackingService extends Service implements LocationListener{
private LocationManager mLocationManager;
private TrackDb db;
private long trackId;
private boolean isTracking = false;
#Override
public void onCreate() {
super.onCreate();
mNotificationManager = (NotificationManager) this
.getSystemService(NOTIFICATION_SERVICE);
mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
db = new TrackDb(this.getApplicationContext());
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public void onDestroy(){
//TODO
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent){
return this.mBinder;
}
private IBinder mBinder = new ITrackingServiceRemote.Stub() {
public void startTracking(long trackId) throws RemoteException {
TrackingService.this.startTracking(trackId);
}
public void pauseTracking() throws RemoteException {
TrackingService.this.pauseTracking();
}
public void resumeTracking(long trackId) throws RemoteException {
TrackingService.this.resumeTracking(trackId);
}
public void stopTracking() throws RemoteException {
TrackingService.this.stopTracking();
}
public long trackingState() throws RemoteException {
long state = TrackingService.this.trackingState();
return state;
}
};
public synchronized void startTracking(long trackId) {
// request updates every 250 meters or 0 sec
this.trackId = trackId;
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 250, this);
isTracking = true;
}
public synchronized long trackingState() {
if(isTracking){
return trackId;
} else
return -1;
}
public synchronized void stopTracking() {
if(isTracking){
mLocationManager.removeUpdates(this);
isTracking = false;
} else
Log.i(TAG, "Could not stop because service is not tracking at the moment");
}
public synchronized void resumeTracking(long trackId) {
if(!isTracking){
this.trackId = trackId;
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0, 250, this);
isTracking = true;
} else
Log.i(TAG, "Could not resume because service is tracking already track " + this.trackId);
}
public synchronized void pauseTracking() {
if(isTracking){
mLocationManager.removeUpdates(this);
isTracking = false;
} else
Log.i(TAG, "Could not pause because service is not tracking at the moment");
}
public void onLocationChanged(Location location) {
//TODO
}
For easier access from the client I wrote a ServiceManager class which sets up the ServiceConnection and you can call the service methods. Here my code for this:
public class TrackingServiceManager{
private static final String TAG = "TrackingServiceManager";
private ITrackingServiceRemote mService = null;
private Context mContext;
private Boolean isBound = false;
private ServiceConnection mServiceConnection;
public TrackingServiceManager(Context ctx){
this.mContext = ctx;
}
public void start(long trackId) {
if (isBound && mService != null) {
try {
mService.startTracking(trackId);
} catch (RemoteException e) {
Log.e(TAG, "Could not start tracking!",e);
}
} else
Log.i(TAG, "No Service bound! 1");
}
public void stop(){
if (isBound && mService != null) {
try {
mService.stopTracking();
} catch (RemoteException e) {
Log.e(TAG, "Could not stop tracking!",e);
}
} else
Log.i(TAG, "No Service bound!");
}
public void pause(){
if (isBound && mService != null) {
try {
mService.pauseTracking();
} catch (RemoteException e) {
Log.e(TAG, "Could not pause tracking!",e);
}
} else
Log.i(TAG, "No Service bound!");
}
public void resume(long trackId){
if (isBound && mService != null) {
try {
mService.resumeTracking(trackId);
} catch (RemoteException e) {
Log.e(TAG, "Could not resume tracking!",e);
}
} else
Log.i(TAG, "No Service bound!");
}
public float state(){
if (isBound && mService != null) {
try {
return mService.trackingState();
} catch (RemoteException e) {
Log.e(TAG, "Could not resume tracking!",e);
return -1;
}
} else
Log.i(TAG, "No Service bound!");
return -1;
}
/**
* Method for binding the Service with client
*/
public boolean connectService(){
mServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
TrackingServiceManager.this.mService = ITrackingServiceRemote.Stub.asInterface(service);
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
if (mService != null) {
mService = null;
}
}
};
Intent mIntent = new Intent("test.de.android.tracker.action.intent.TrackingService");
this.isBound = this.mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
return this.isBound;
}
public void disconnectService(){
this.mContext.unbindService(mServiceConnection);
this.isBound = false;
}
}
If i now try to call a method from an activity for example start(trackId) nothing happens. The binding is OK. When debugging it always runs into the startTracking() in the generated ITrackingServiceRemote.java file and not into my TrackingService class. Where is the problem? I can't find anything wrong.
Thanks in advance!
Tobias
I need IPC to control the service from
different activities. So I decide to
develop a remote service with AIDL.
You do not need IPC to control the service from different activities. You may need IPC to control the service from different applications (i.e., separate APKs).
When debugging it always runs into the
startTracking() in the generated
ITrackingServiceRemote.java file and
not into my TrackingService class.
Your activity has a client-side proxy representing the service interface. The service itself is supposed to be running in a completely separate process from a completely separate APK.
I recommend that you get rid of the AIDL and switch back to the local binding pattern, at least long enough to get your activity and service working. Then, and only then, should you pull them apart into separate APKs, if that is indeed the desired end.

Categories

Resources