Tracking Camera Access and User Interactions

Prev Next

You can use the Android SDK to track user interactions with the camera in your app. The following examples are based on Android’s CameraX library, but tracking is also possible with other implementations with minor adjustments.

Out-of-the-box tracking includes:

  • Changing flash settings

  • Switching between front and back cameras

  • Taking pictures

  • Accessing the most recent picture

For any additional functionality, further implementation work may be required to enable tracking.

Please note

Ensure event parameters are configured correctly in your account to capture the necessary data.

//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)
        }
//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);
        });