androidgoogle-apibroadcastreceiveractivity-recognition

How to start Google API - ActivityRecognitionAPI using BroadcastReceivers on device boot?


I have used this API using Activities and it works. I tried starting MainActivity using this BroadcastReceiver and it works. But when I try this, it crashes my App.

Do I need to add flags to intent? How to do that in this case?

I tried these codes but my app crashes on boot:

1) BroadcastReceiver class:

public class startReceiver extends BroadcastReceiver
    implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

public Context appContext;
public GoogleApiClient mApiClient;

@Override
public void onReceive(Context context, Intent intent) {
    appContext = context;

    mApiClient = new GoogleApiClient.Builder(context)
            .addApi(ActivityRecognition.API)
            .addConnectionCallbacks((GoogleApiClient.ConnectionCallbacks) context)
            .addOnConnectionFailedListener((GoogleApiClient.OnConnectionFailedListener) context)
            .build();

    mApiClient.connect();
}

@Override
public void onConnected(@Nullable Bundle bundle) {
    Intent intent = new Intent(appContext, ActivityRecognizedService.class);
    PendingIntent pendingIntent = PendingIntent.getService(appContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mApiClient, 10000, pendingIntent);
}

@Override
public void onConnectionSuspended(int i) {
    Toast.makeText(appContext, "Connection to Google Services suspended!", Toast.LENGTH_LONG).show();
    mApiClient.reconnect();
}

@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
    Toast.makeText(appContext, "Connection to Google Services failed!", Toast.LENGTH_LONG).show();
    mApiClient.connect();
}

2) ActivityRecognizedService

public class ActivityRecognizedService extends IntentService {

public ActivityRecognizedService() {
    super("ActivityRecognizedService");
}

public ActivityRecognizedService(String name) {
    super(name);
}

@Override
protected void onHandleIntent(Intent intent) {
    if (ActivityRecognitionResult.hasResult(intent)) {
        ActivityRecognitionResult result = ActivityRecognitionResult.extractResult(intent);
        handleDetectedActivities(result.getProbableActivities());
    }
}

private void handleDetectedActivities(List<DetectedActivity> probableActivities) {
    for (DetectedActivity activity : probableActivities) {
        switch (activity.getType()) {
            case DetectedActivity.IN_VEHICLE: {
                Log.e("ActivityRecogition", "In Vehicle: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.ON_BICYCLE: {
                Log.e("ActivityRecogition", "On Bicycle: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.ON_FOOT: {
                Log.e("ActivityRecogition", "On Foot: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.RUNNING: {
                Log.e("ActivityRecogition", "Running: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.STILL: {
                Log.e("ActivityRecogition", "Still: " + activity.getConfidence());
                NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
                builder.setContentText("Are you walking?");
                builder.setSmallIcon(R.mipmap.ic_launcher);
                builder.setContentTitle(getString(R.string.app_name));
                NotificationManagerCompat.from(this).notify(0, builder.build());
                break;
            }
            case DetectedActivity.TILTING: {
                Log.e("ActivityRecogition", "Tilting: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.WALKING: {
                Log.e("ActivityRecogition", "Walking: " + activity.getConfidence());
                break;
            }
            case DetectedActivity.UNKNOWN: {
                Log.e("ActivityRecogition", "Unknown: " + activity.getConfidence());
                break;
            }
        }
    }
}

For a start, I used the API as used in this link: http://code.tutsplus.com/tutorials/how-to-recognize-user-activity-with-activity-recognition--cms-25851


Solution

  • Add necessary permissions in your AdnroidManifest.xml:

    <uses-permission android:name = "android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    

    Then you need to link the boot message with a particular BroadcastReceiver, that will receive and process the message("boot") issued by the phone. You can define your broadcast receiver as an extension of WakefulBroadcastReceiver, so that it ensures that the device will stay stay awake until your service is started e.g.

    public class MyBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
      public void onReceive(Context con, Intent i) {
        Intent intent = new Intent(con, MyIntentService.class);
        startWakefulService(con, intent);
      }
    }
    

    After that, declare this receiver in the manifest file:

    <receiver android:name="com.example.MyBroadcastReceiver">  
      <intent-filter>  
        <action android:name="android.intent.action.BOOT_COMPLETED" />  
      </intent-filter>  
    </receiver>
    

    BOOT_COMPLETED message ensures that our receiver is launched on the device boot up. When the boot message is received, the "wakeful" receiver launches the service. Also we need to release the wake lock inside the onHandleIntent so the device can go back to sleep after the service is launched:

    public class MyIntentService extends IntentService {
      @Override
      protected void onHandleIntent(Intent i) {
        //Release the wake lock
        WakefulBroadcastReceiver.completeWakefulIntent(i);
      } 
    }
    

    Now the service will start automatically, whenever device boots