Detecting If a User Is Moving in a Car

Detecting if a user is moving in a car

All the advice about the wisdom (or lack thereof) in guessing about motion states from location data still applies. But regarding your update about Core Motion and M7...

Yes, you can use Core Motion on devices with an M7, M8, M9, etc motion coprocessor(*) to get an indication of whether the user might be driving.

  1. Create a CMMotionActivityManager object (after using its class method isActivityAvailable to determine whether you you have M7(+) features), and either start activity updates or query it for recent activities.
  2. Check the returned CMMotionActivity objects' automotive property to see if iOS thinks the user is/was in a car.
  3. There's no step three.

Like the GPS inferences, though, you should still take this information with a grain of salt. CoreMotion APIs give you iOS' best guess as to the user's activity, but there's no guarantee it's 100% accurate. (For example, I'm not sure if riding a train might count as automotive. Also note that the different activity types are not mutually exclusive.) It's better for your app to check for the activity types you're interested in than to try to exclude the ones you don't want.


(*) M7 devices are those with the A7 SoC: iPhone 5s, iPad Air, iPad mini 2. M8 is A8, M9 is A9, etc. In short, every iOS device introduced since Fall 2013, excluding iPhone 5c.

Can I find out whether the user is driving?

While your app is active you can use CMMotionActivityManager to get the current motion type.

Note that it won't tell you whether the person is driving or a passenger or even in another vehicle that has similar motion characteristics, such as a train. You can't get motion activity updates while your app is suspended.

You could combine it with Signification Location updates to get periodic execution in the background.

This answer has some suggestions on detecting Bluetooth HFP devices by checking the available audio input devices. Note that you can't check this in the background and you can't get a "notification" that a HFP has connected unless you are actively inputting or outputting audio - You would need to check periodically

Android Detect if vehicle moving

As far as i can see it, you have 3 options :

  1. You can implement your own technique for detecting driving - using Activity recognition and receiving location updates, though i recommend not to do so, don't reinvent the wheel, there are good apis developed already.
  2. You could use a free sdk of Neura which can send you an event when your user starts driving and finishes driving.
    Check out this git project : Basically, the project announces notifications with text-to-speech when you start driving, which isn't what you want, but you can do whatever you want when Neura sends you an event for start/finish driving.
    Its very easy to just take this project and make it your own.
    I highly recommend using this option.
  3. You could use google's FenceApi in order to declare a driving fence.

    Though this approach seems good, i've faced with the fact that this api didn't tell me sometimes when user starts/finishes driving, and sometimes it took a long time after i started driving that the api told me of that event.

    a. include dependency to your app's build.gradle file :

       compile 'com.google.android.gms:play-services-location:+'

    compile 'com.google.android.gms:play-services-contextmanager:+'

    b. Manifest definitions :


    <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme" >

    <meta-data
    android:name="com.google.android.awareness.API_KEY"
    android:value="PUT_YOUR_AWARENESS_KEY_HERE" />

    <activity android:name=".MainActivity" >
    <intent-filter>
    <action android:name="android.intent.action.MAIN" />

    <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    </activity>
    </application>


    PUT_YOUR_AWARENESS_KEY_HERE : You need to generate a key here.

    c. Your MainActivity class - explanations attached to the code :

    public class MainActivity extends Activity {

    private GoogleApiClient mGoogleApiClient;
    private PendingIntent mPendingIntent;
    private FenceReceiver mFenceReceiver;

    // The intent action which will be fired when your fence is triggered.
    private final String FENCE_RECEIVER_ACTION = BuildConfig.APPLICATION_ID + "FENCE_RECEIVER_ACTION";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    mGoogleApiClient = new GoogleApiClient.Builder(this).addApi(Awareness.API).build();
    mGoogleApiClient.connect();
    // Set up the PendingIntent that will be fired when the fence is triggered.
    mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(FENCE_RECEIVER_ACTION), 0);
    // The broadcast receiver that will receive intents when a fence is triggered.
    mFenceReceiver = new FenceReceiver();
    registerReceiver(mFenceReceiver, new IntentFilter(FENCE_RECEIVER_ACTION));
    createFence(DetectedActivityFence.IN_VEHICLE, "InVehicleFence");
    }

    @Override
    public void onDestroy() {
    try {
    unregisterReceiver(mFenceReceiver); //Don't forget to unregister the receiver
    } catch (Exception e) {
    e.printStackTrace();
    }
    super.onDestroy();
    }

    private void createFence(int detectedActivityFence, final String fenceKey) {
    AwarenessFence fence = DetectedActivityFence.during(detectedActivityFence);
    // Register the fence to receive callbacks.
    Awareness.FenceApi.updateFences(
    mGoogleApiClient, new FenceUpdateRequest.Builder().addFence(fenceKey, fence, mPendingIntent)
    .build()).setResultCallback(new ResultCallback<Status>() {
    @Override
    public void onResult(@NonNull Status status) {
    if (status.isSuccess()) {
    Log.i(getClass().getSimpleName(), "Successfully registered.");
    } else {
    Log.e(getClass().getSimpleName(), "Could not be registered: " + status);
    }
    }
    });
    }

    // Handle the callback on the Intent.
    public class FenceReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
    FenceState fenceState = FenceState.extract(intent);
    switch (fenceState.getCurrentState()) {
    case FenceState.TRUE:
    Log.i(fenceState.getFenceKey(), "Driving");
    break;
    case FenceState.FALSE:
    Log.i(fenceState.getFenceKey(), "Not driving");
    break;
    }
    }
    }
    }

Determining if user is driving using gps

You probably want to set up some AsyncTask (background thread) with a call back function of your preference, which will be called when the speed is over 10 MPH. You can use the Location.GetSpeed() function.

Also, you might want to take note of the fact that it returns in meters/second. But this is a trivial conversion.



Related Topics



Leave a reply



Submit