Native Functionality Request - Camera Access
You can use the Android SDK v5 to track user behavior of the camera. The examples code below is based on Android's cameraX library. You can also check the implementation in our demo application on GitHub (also based on cameraX).
When using cameraX, the following functions can be tracked out of the box:
- Change flash settings
- Change camera (front / back)
- Take picture
- Open the latest picture
Any other function needs additional implementation work to be tracked.
Please note
- Ensure that event parameters are configured accordingly in your account.
- If you do not use cameraX tracking is possible as well of course, but you might need to adjust implementation.
//Access Camera:
view.findViewById<Button>(R.id.button).setOnClickListener {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(
MainFragmentDirections.actionMainFragmentToPermissionsFragment()
)
//Tracking event is sent
Webtrekk.getInstance().trackCustomEvent("access camera")
}
//Take/Save image:
/** Define callback that will be triggered after a photo has been taken and saved to disk */
private val imageSavedListener = object : ImageCapture.OnImageSavedCallback {
override fun onError(imageCaptureError: Int, message: String, cause: Throwable?) {
Log.e(TAG, "Photo capture failed: $message", cause)
}
override fun onImageSaved(photoFile: File) {
Log.d(TAG, "Photo capture succeeded: ${photoFile.absolutePath}")
// We can only change the foreground Drawable using API level 23+ API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Update the gallery thumbnail with latest picture taken
setGalleryThumbnail(photoFile)
}
// Implicit broadcasts will be ignored for devices running API
// level >= 24, so if you only target 24+ you can remove this statement
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
requireActivity().sendBroadcast(
Intent(android.hardware.Camera.ACTION_NEW_PICTURE, Uri.fromFile(photoFile))
)
}
// If the folder selected is an external media directory, this is unnecessary
// but otherwise other apps will not be able to access our images unless we
// scan them using [MediaScannerConnection]
val mimeType = MimeTypeMap.getSingleton()
.getMimeTypeFromExtension(photoFile.extension)
MediaScannerConnection.scanFile(
context, arrayOf(photoFile.absolutePath), arrayOf(mimeType), null)
//If there is no error, tracking event for taking/saving image is sent
val params: LinkedHashMap<String, String> = LinkedHashMap()
params.put("ck6", "take picture")
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params)
}
}
//Change flash settings:
/** Global variable to keep state of flash mode, default value set to off */
private var flashMode = ImageCapture.FLASH_MODE_OFF
/** Listener for button used to change flash mode */
controls.findViewById<ImageButton>(R.id.flash_mode_button).setOnClickListener {
val flashResource: Int
flashMode = if (flashMode == ImageCapture.FLASH_MODE_OFF){
flashResource = R.drawable.ic_flash_auto_white_24dp;
ImageCapture.FLASH_MODE_AUTO
}
else if (flashMode == ImageCapture.FLASH_MODE_AUTO){
flashResource = R.drawable.ic_flash_on_white_24dp;
ImageCapture.FLASH_MODE_ON
}
else {
flashResource = R.drawable.ic_flash_off_white_24dp;
ImageCapture.FLASH_MODE_OFF
}
val flashButtonImage = container.findViewById<ImageButton>(R.id.flash_mode_button)
// Run the operations in the view's thread
flashButtonImage.post {
// Load thumbnail into circular button using Glide
Glide.with(flashButtonImage)
.load(flashResource)
.apply(RequestOptions.circleCropTransform())
.into(flashButtonImage)
}
//Bind use cases
bindCameraUseCases()
//Tracking event is sent
val params: LinkedHashMap<String, String> = LinkedHashMap()
params.put("ck6", "change flash setting")
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params)
}
//Change lens facing to front or back:
/** Global variable to keep state of chosen camera, default values set to back camera */
private var lensFacing = CameraSelector.LENS_FACING_BACK
/** Listener for button used to switch cameras */
controls.findViewById<ImageButton>(R.id.camera_switch_button).setOnClickListener {
lensFacing = if (CameraSelector.LENS_FACING_FRONT == lensFacing) {
CameraSelector.LENS_FACING_BACK
} else {
CameraSelector.LENS_FACING_FRONT
}
//Bind use cases
bindCameraUseCases()
//Tracking event is sent
val params: LinkedHashMap<String, String> = LinkedHashMap()
params.put("ck6", "change camera")
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params)
}
JAVA
//Access Camera:
view.findViewById(R.id.button).setOnClickListener(v -> {
Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(
MainFragmentDirections.actionMainFragmentToPermissionsFragment());
//Tracking event is sent
Webtrekk.getInstance().trackCustomEvent("access camera", Collections.emptyMap());
});
//Take/Save image:
/** Define callback that will be triggered after a photo has been taken and saved to disk */
private ImageCapture.OnImageSavedCallback imageSavedListener = new ImageCapture.OnImageSavedCallback() {
@Override
public void onError(int imageCaptureError, @NonNull String message, @Nullable Throwable cause) {
Log.e(TAG, "Photo capture failed: " + message, cause);
}
@Override
public void onImageSaved(@NonNull File file) {
String msg = "Pic captured at " + file.getAbsolutePath();
Log.d(TAG, "Photo capture succeeded: " + msg);
// We can only change the foreground Drawable using API level 23+ API
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Update the gallery thumbnail with latest picture taken
setGalleryThumbnail(true);
}
//If there is no error, tracking event for taking/saving image is sent
Map<String, String> params = new LinkedHashMap<>();
params.put("ck6", "take picture");
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params);
}
};
//Change flash settings:
/** Global variable to keep state of flash mode, default value set to off */
private int flashMode = FlashMode.OFF;
/** Listener for button used to change flash mode */
view.findViewById(R.id.flash).setOnClickListener(v -> {
if (flashMode == FlashMode.ON) {
flashMode = FlashMode.OFF;
flashResource = R.drawable.ic_flash_off_white_24dp;
} else if (flashMode == FlashMode.OFF) {
flashMode = FlashMode.AUTO;
flashResource = R.drawable.ic_flash_auto_white_24dp;
} else if (flashMode == FlashMode.AUTO) {
flashMode = FlashMode.ON;
flashResource = R.drawable.ic_flash_on_white_24dp;
}
Glide.with(flashButton)
.load(flashResource)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.apply(RequestOptions.circleCropTransform())
.into(flashButton);
bindPreview(cameraProvider);
//Tracking event is sent
Map<String, String> params = new LinkedHashMap<>();
params.put("ck6", "change flash setting");
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params);
});
//Change lens facing to front or back:
/** Global variable to keep state of chosen camera, default values set to back camera */
private int lensFacing = LensFacing.BACK;
/** Listener for button used to switch cameras */
view.findViewById(R.id.camera_switch_button).setOnClickListener(v -> {
if (lensFacing == LensFacing.BACK)
lensFacing = LensFacing.FRONT;
else
lensFacing = LensFacing.BACK;
bindPreview(cameraProvider);
//Tracking event is sent
Map<String, String> params = new LinkedHashMap<>();
params.put("ck6", "change camera");
Webtrekk.getInstance().trackCustomEvent("click.camera.button", params);
});
JAVA