Camera availability tip
It’s been a lot of time since I have written something interesting on Android. Following post is on how should we properly listen for camera being released. Duh!
Assume we are have to make our Service aware of camera usage, like Google Photos does it with the option to show Photos logo after you capture new image, for quick navigation to Photos gallery.
Their Service
is triggered byJobScheduler
that starts job when there are changes in MediaStore.Images.Media.EXTERNAL_CONTENT_URI
. But how do they manage to remove fb-chat-head-like-shortcut-icon once you close the camera app? They are waiting for the app to release the camera (≥ Lollipop) and wait for camera app to be removed from foreground (< Lollipop).
There are two concerns here:
- API levels of the given CameraManager
API methods
- API levels of the given ActivityManager
API methods
Base class:
A centralized way to listen for camera availability.
public class CameraAvailability {
public static CameraAvailability get(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraAvailabilityLollipop(context);
}
return new CameraAvailabilityPreLolipop(context);
}
void waitForCameraBeingAvailable(OnCameraReleasedListener l) {
throw new UnsupportedOperationException("Don't call super!");
} interface OnCameraReleasedListener {
void onCameraAvailable();
}
}
Lollipop and above
In camera2
package CameraManager
offers really simple way to listen for camera availability, just by using registerAvailabilityCallback() method
Prior Lollipop
After Lollipop there was uproar about how to get current visible activity, since getAppTasks() joined deprecation club. This is really great opportunity to leverage ActivityManager
.
Here we are monitoring the current top activity is any of the list of activities that can handle ACTION_IMAGE_CAPTURE
intent action. Once the current activity is no longer capable of handling our target intent action, it means that camera has been released. Recursive Runnable
checks every 200ms.
On Stackoverflow there is a proposed way to use old Camera
API and anticipating a RuntimeException
to be thrown if the camera is used when we are attempting to open it.
I’m not fan of this proposed way, because it tries to throw exception and dumping the stacktrace might slow down your device, and it tries to open() and immediately release() the camera just to return boolean.
Usage:
private void registerForCameraAvailability() {
CameraAvailability cameraAvailability = CameraAvailability.get(this);
cameraAvailability.waitForCameraBeingAvailable(this);
}