0

I would like to launch an Activity of my application when a shake event is detected. I would like this to happen outside of my application.

There are many great code snippets here and here for example, of how to correctly implement the SensorEventListener, but even if I don't unregister the listener, it still gets destroyed.

How do I prevent it from being destroyed and register a 'permanent' listener? I can't find any such examples anywhere... Any links or guidance would be really appreciated.

Finally, how would I go about only listening for such events when the display is on? I understand that this may be a hardware restriction anyway.

Thanks in advance.

Community
  • 1
  • 1
brandall
  • 6,094
  • 4
  • 49
  • 103

1 Answers1

1

You can register broadcast receiver for BOOT_COMPLETED intent and in onReceive start your background service with a PARTIAL_WAKELOCK and then register your sensor event listener. Something like this:

@Override
public int onStartCommand(Intent i, int flags, int startId) {
    acquireWakeLock();
    registerSensorListener();
    return START_STICKY;
}

@Override
public void onDestroy() {
    unregisterSensorListener();
    releaseWakeLock();
    super.onDestroy();
}

private void acquireWakeLock() {
    try {
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        if (pm == null) {
            Log.e(TAG, "Power manager not found!");
            return;
        }
        if (wakeLock == null) {
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getPackageName());
            if (wakeLock == null) {
                Log.e(TAG, "Could not create wake lock (null).");
                return;
            }
        }
        if (!wakeLock.isHeld()) {
            wakeLock.acquire();
            if (!wakeLock.isHeld()) {
                Log.e(TAG, "Could not acquire wake lock.");
            }
        }
    } catch (RuntimeException e) {
        Log.e(TAG, "Caught unexpected exception: " + e.getMessage(), e);
    }
}

private void releaseWakeLock() {
    if (wakeLock != null && wakeLock.isHeld()) {
        wakeLock.release();
        wakeLock = null;
    }
}

Hope this helps.

Dmitry Polishuk
  • 119
  • 1
  • 5
  • Thanks for your reply, it's given me some further reading to do. Forgive the perhaps stupid question, but isn't acquiring a partial wakelock the opposite of what I want to do!? I don't want the listener preventing the device from sleeping... – brandall Jun 16 '12 at 18:19
  • As far as I understand, you do not have a choice. In standby mode your [onSensorChanged](http://developer.android.com/reference/android/hardware/SensorEventListener.html#onSensorChanged(android.hardware.SensorEvent) will never be called. – Dmitry Polishuk Jun 16 '12 at 18:40
  • That's ok, I don't want it to be when the display turns off. I definitely need to register using BOOT_COMPLETED, but can unregister when display goes off or enters standby - so I don't think I'll need the partial wakelock. But then register again when display/cpu turns back on..? – brandall Jun 16 '12 at 20:30
  • 1
    Ok, then just handle [Intent.ACTION_SCREEN_OFF](http://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_OFF) and [Intent.ACTION_SCREEN_ON](http://developer.android.com/reference/android/content/Intent.html#ACTION_SCREEN_ON) in your [BroadcastReceiver](http://developer.android.com/reference/android/content/BroadcastReceiver.html) – Dmitry Polishuk Jun 16 '12 at 20:46