├── .github
└── workflows
│ ├── fastlane.yml
│ └── unit-test.yml
├── .gitignore
├── .idea
└── inspectionProfiles
│ └── Project_Default.xml
├── LICENSE.md
├── README.md
├── _docs
├── .htaccess
├── baseline_add_a_photo_white_48.png
├── baseline_filter_vintage_white_48.png
├── credits.html
├── devices.html
├── exposure_locked.png
├── exposure_unlocked.png
├── focus_mode_auto.png
├── focus_mode_continuous_picture.png
├── focus_mode_edof.png
├── focus_mode_fixed.png
├── focus_mode_infinity.png
├── focus_mode_locked.png
├── focus_mode_manual.png
├── help.html
├── history.html
├── ic_exposure_white_48dp.png
├── ic_gps_fixed_white_48dp.png
├── ic_launcher.png
├── ic_mic_white_48dp.png
├── ic_pause_circle_outline_white_48dp.png
├── index.html
├── info.html
├── popup.png
├── privacy_oc.html
├── settings.png
├── share.png
├── stylesheet.css
├── switch_camera.png
├── take_photo.png
├── take_photo_when_video_recording.png
├── take_video.png
└── trash.png
├── androidx_LICENSE-2.0.txt
├── api_client
├── .gitignore
├── README.md
├── async_imu_example.py
├── basic_example.py
├── requirements.txt
└── src
│ ├── RemoteControl.py
│ └── __init__.py
├── app
├── build.gradle
└── src
│ ├── androidTest
│ ├── java
│ │ └── net
│ │ │ └── sourceforge
│ │ │ └── opencamera
│ │ │ └── test
│ │ │ ├── AvgTests.java
│ │ │ ├── HDRNTests.java
│ │ │ ├── HDRTests.java
│ │ │ ├── MainActivityTest.java
│ │ │ ├── MainTests.java
│ │ │ ├── Nexus7Tests.java
│ │ │ ├── PanoramaTests.java
│ │ │ ├── PhotoCamera2Tests.java
│ │ │ ├── PhotoTests.java
│ │ │ ├── SubsetTests.java
│ │ │ └── VideoTests.java
│ └── res
│ │ ├── drawable-hdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── androidx_LICENSE-2.0.txt
│ │ ├── google_material_design_icons_LICENSE-2.0.txt
│ │ ├── gpl-3.0.txt
│ │ └── server_config.properties
│ ├── java
│ │ ├── com
│ │ │ └── googleresearch
│ │ │ │ └── capturesync
│ │ │ │ ├── PhaseAlignController.java
│ │ │ │ ├── SoftwareSyncController.java
│ │ │ │ └── softwaresync
│ │ │ │ ├── ClientInfo.java
│ │ │ │ ├── NetworkHelpers.java
│ │ │ │ ├── RpcCallback.java
│ │ │ │ ├── SimpleNetworkTimeProtocol.java
│ │ │ │ ├── SntpListener.java
│ │ │ │ ├── SntpOffsetResponse.java
│ │ │ │ ├── SoftwareSyncBase.java
│ │ │ │ ├── SoftwareSyncClient.java
│ │ │ │ ├── SoftwareSyncLeader.java
│ │ │ │ ├── SyncConstants.java
│ │ │ │ ├── SystemTicker.java
│ │ │ │ ├── Ticker.java
│ │ │ │ ├── TimeDomainConverter.java
│ │ │ │ ├── TimeUtils.java
│ │ │ │ └── phasealign
│ │ │ │ ├── PeriodCalculator.java
│ │ │ │ ├── PhaseAligner.java
│ │ │ │ ├── PhaseConfig.java
│ │ │ │ ├── PhaseResponse.java
│ │ │ │ └── StreamUtils.java
│ │ └── net
│ │ │ └── sourceforge
│ │ │ └── opencamera
│ │ │ ├── AudioListener.java
│ │ │ ├── ExtendedAppInterface.java
│ │ │ ├── GyroSensor.java
│ │ │ ├── HDRProcessor.java
│ │ │ ├── HDRProcessorException.java
│ │ │ ├── ImageSaver.java
│ │ │ ├── LocationSupplier.java
│ │ │ ├── MagneticSensor.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MyApplicationInterface.java
│ │ │ ├── MyAudioTriggerListenerCallback.java
│ │ │ ├── MyDebug.java
│ │ │ ├── MyPreferenceFragment.java
│ │ │ ├── MyTileService.java
│ │ │ ├── MyTileServiceFrontCamera.java
│ │ │ ├── MyTileServiceVideo.java
│ │ │ ├── MyWidgetProvider.java
│ │ │ ├── MyWidgetProviderTakePhoto.java
│ │ │ ├── OpenCameraApplication.java
│ │ │ ├── PanoramaProcessor.java
│ │ │ ├── PanoramaProcessorException.java
│ │ │ ├── PermissionHandler.java
│ │ │ ├── PreferenceHandler.java
│ │ │ ├── PreferenceKeys.java
│ │ │ ├── SaveLocationHistory.java
│ │ │ ├── SettingsManager.java
│ │ │ ├── SoundPoolManager.java
│ │ │ ├── SpeechControl.java
│ │ │ ├── StorageUtils.java
│ │ │ ├── StorageUtilsWrapper.java
│ │ │ ├── TakePhoto.java
│ │ │ ├── TextFormatter.java
│ │ │ ├── ToastBoxer.java
│ │ │ ├── cameracontroller
│ │ │ ├── CameraController.java
│ │ │ ├── CameraController1.java
│ │ │ ├── CameraController2.java
│ │ │ ├── CameraControllerException.java
│ │ │ ├── CameraControllerManager.java
│ │ │ ├── CameraControllerManager1.java
│ │ │ ├── CameraControllerManager2.java
│ │ │ ├── RawImage.java
│ │ │ └── YuvImageUtils.java
│ │ │ ├── preview
│ │ │ ├── ApplicationInterface.java
│ │ │ ├── BasicApplicationInterface.java
│ │ │ ├── CanvasView.java
│ │ │ ├── Preview.java
│ │ │ ├── VideoProfile.java
│ │ │ ├── VideoQualityHandler.java
│ │ │ └── camerasurface
│ │ │ │ ├── CameraSurface.java
│ │ │ │ ├── MySurfaceView.java
│ │ │ │ └── MyTextureView.java
│ │ │ ├── recsync
│ │ │ ├── SoftwareSyncHelper.java
│ │ │ └── SyncSettingsContainer.java
│ │ │ ├── remotecontrol
│ │ │ ├── BluetoothLeService.java
│ │ │ ├── BluetoothRemoteControl.java
│ │ │ ├── DeviceScanner.java
│ │ │ └── KrakenGattAttributes.java
│ │ │ ├── sensorlogging
│ │ │ ├── FlashController.java
│ │ │ ├── RawSensorInfo.java
│ │ │ ├── VideoFrameInfo.java
│ │ │ └── VideoPhaseInfo.java
│ │ │ ├── sensorremote
│ │ │ ├── RemoteRpcConfig.java
│ │ │ ├── RemoteRpcRequestHandler.java
│ │ │ ├── RemoteRpcResponse.java
│ │ │ └── RemoteRpcServer.java
│ │ │ └── ui
│ │ │ ├── ArraySeekBarPreference.java
│ │ │ ├── DrawPreview.java
│ │ │ ├── FileInfo.java
│ │ │ ├── FolderChooserDialog.java
│ │ │ ├── MainUI.java
│ │ │ ├── ManualSeekbars.java
│ │ │ └── PopupView.java
│ ├── res
│ │ ├── drawable-hdpi
│ │ │ ├── baseline_add_a_photo_white_48.png
│ │ │ ├── baseline_bluetooth_white_48.png
│ │ │ ├── baseline_check_white_48.png
│ │ │ ├── baseline_close_white_48.png
│ │ │ ├── baseline_filter_vintage_white_48.png
│ │ │ ├── baseline_folder_open_white_48.png
│ │ │ ├── baseline_highlight_white_48.png
│ │ │ ├── baseline_panorama_horizontal_white_48.png
│ │ │ ├── baseline_photo_library_white_48.png
│ │ │ ├── baseline_remove_red_eye_white_48.png
│ │ │ ├── baseline_rotate_left_white_48.png
│ │ │ ├── baseline_rotate_right_white_48.png
│ │ │ ├── baseline_shutter_speed_white_48.png
│ │ │ ├── baseline_text_fields_red_48.png
│ │ │ ├── baseline_text_fields_white_48.png
│ │ │ ├── flash_auto.png
│ │ │ ├── flash_off.png
│ │ │ ├── flash_on.png
│ │ │ ├── ic_align_phases_48dp.png
│ │ │ ├── ic_burst_mode_white_48dp.png
│ │ │ ├── ic_colorize_white_48dp.png
│ │ │ ├── ic_empty.png
│ │ │ ├── ic_exposure_red_48dp.png
│ │ │ ├── ic_exposure_white_48dp.png
│ │ │ ├── ic_face_red_48dp.png
│ │ │ ├── ic_face_white_48dp.png
│ │ │ ├── ic_fast_forward_white_48dp.png
│ │ │ ├── ic_gps_fixed_red_48dp.png
│ │ │ ├── ic_gps_fixed_white_48dp.png
│ │ │ ├── ic_gps_off_white_48dp.png
│ │ │ ├── ic_hdr_on_white_48dp.png
│ │ │ ├── ic_help_outline_white_48dp.png
│ │ │ ├── ic_imu_outline_white_48dp.png
│ │ │ ├── ic_info_outline_white_48dp.png
│ │ │ ├── ic_launcher_take_photo.png
│ │ │ ├── ic_mic_off_white_48dp.png
│ │ │ ├── ic_mic_red_48dp.png
│ │ │ ├── ic_mic_white_48dp.png
│ │ │ ├── ic_more_horiz_white_48dp.png
│ │ │ ├── ic_pause_circle_outline_white_48dp.png
│ │ │ ├── ic_photo_camera_white_48dp.png
│ │ │ ├── ic_photo_size_select_large_white_48dp.png
│ │ │ ├── ic_play_circle_outline_white_48dp.png
│ │ │ ├── ic_power_settings_new_white_48dp.png
│ │ │ ├── ic_recsync.png
│ │ │ ├── ic_save_white_48dp.png
│ │ │ ├── ic_slow_motion_video_white_48dp.png
│ │ │ ├── ic_sync_settings_48dp.png
│ │ │ ├── ic_sync_settings_red_48dp.png
│ │ │ ├── ic_text_format_red_48dp.png
│ │ │ ├── ic_text_format_white_48dp.png
│ │ │ ├── ic_timelapse_white_48dp.png
│ │ │ ├── ic_timer_white_48dp.png
│ │ │ ├── ic_touch_app_white_48dp.png
│ │ │ ├── ic_videocam_white_48dp.png
│ │ │ ├── settings.png
│ │ │ ├── share.png
│ │ │ ├── switch_camera.png
│ │ │ └── trash.png
│ │ ├── drawable-mdpi
│ │ │ ├── auto_stabilise_icon.png
│ │ │ ├── auto_stabilise_icon_red.png
│ │ │ ├── baseline_add_a_photo_white_48.png
│ │ │ ├── baseline_bluetooth_white_48.png
│ │ │ ├── baseline_check_white_48.png
│ │ │ ├── baseline_close_white_48.png
│ │ │ ├── baseline_filter_vintage_white_48.png
│ │ │ ├── baseline_folder_open_white_48.png
│ │ │ ├── baseline_highlight_white_48.png
│ │ │ ├── baseline_panorama_horizontal_white_48.png
│ │ │ ├── baseline_photo_library_white_48.png
│ │ │ ├── baseline_remove_red_eye_white_48.png
│ │ │ ├── baseline_rotate_left_white_48.png
│ │ │ ├── baseline_rotate_right_white_48.png
│ │ │ ├── baseline_shutter_speed_white_48.png
│ │ │ ├── baseline_text_fields_red_48.png
│ │ │ ├── baseline_text_fields_white_48.png
│ │ │ ├── dro_icon.png
│ │ │ ├── expo_icon.png
│ │ │ ├── exposure_locked.png
│ │ │ ├── exposure_unlocked.png
│ │ │ ├── flash_auto.png
│ │ │ ├── flash_off.png
│ │ │ ├── flash_on.png
│ │ │ ├── focus_bracket_icon.png
│ │ │ ├── focus_mode_auto.png
│ │ │ ├── focus_mode_continuous_picture.png
│ │ │ ├── focus_mode_continuous_video.png
│ │ │ ├── focus_mode_edof.png
│ │ │ ├── focus_mode_fixed.png
│ │ │ ├── focus_mode_infinity.png
│ │ │ ├── focus_mode_locked.png
│ │ │ ├── focus_mode_manual.png
│ │ │ ├── ic_align_phases_48dp.png
│ │ │ ├── ic_burst_mode_white_48dp.png
│ │ │ ├── ic_colorize_white_48dp.png
│ │ │ ├── ic_empty.png
│ │ │ ├── ic_exposure_red_48dp.png
│ │ │ ├── ic_exposure_white_48dp.png
│ │ │ ├── ic_face_red_48dp.png
│ │ │ ├── ic_face_white_48dp.png
│ │ │ ├── ic_fast_forward_white_48dp.png
│ │ │ ├── ic_gps_fixed_red_48dp.png
│ │ │ ├── ic_gps_fixed_white_48dp.png
│ │ │ ├── ic_gps_off_white_48dp.png
│ │ │ ├── ic_hdr_on_white_48dp.png
│ │ │ ├── ic_help_outline_white_48dp.png
│ │ │ ├── ic_imu_outline_white_48dp.png
│ │ │ ├── ic_info_outline_white_48dp.png
│ │ │ ├── ic_launcher_take_photo.png
│ │ │ ├── ic_mic_off_white_48dp.png
│ │ │ ├── ic_mic_red_48dp.png
│ │ │ ├── ic_mic_white_48dp.png
│ │ │ ├── ic_more_horiz_white_48dp.png
│ │ │ ├── ic_pause_circle_outline_white_48dp.png
│ │ │ ├── ic_photo_camera_white_48dp.png
│ │ │ ├── ic_photo_size_select_large_white_48dp.png
│ │ │ ├── ic_play_circle_outline_white_48dp.png
│ │ │ ├── ic_power_settings_new_white_48dp.png
│ │ │ ├── ic_recsync.png
│ │ │ ├── ic_save_white_48dp.png
│ │ │ ├── ic_slow_motion_video_white_48dp.png
│ │ │ ├── ic_stat_notify_take_photo.png
│ │ │ ├── ic_sync_settings_48dp.png
│ │ │ ├── ic_sync_settings_red_48dp.png
│ │ │ ├── ic_text_format_red_48dp.png
│ │ │ ├── ic_text_format_white_48dp.png
│ │ │ ├── ic_timelapse_white_48dp.png
│ │ │ ├── ic_timer_white_48dp.png
│ │ │ ├── ic_touch_app_white_48dp.png
│ │ │ ├── ic_videocam_white_48dp.png
│ │ │ ├── iso_icon.png
│ │ │ ├── nr_icon.png
│ │ │ ├── popup.png
│ │ │ ├── popup_flash_auto.png
│ │ │ ├── popup_flash_off.png
│ │ │ ├── popup_flash_on.png
│ │ │ ├── popup_flash_red_eye.png
│ │ │ ├── popup_flash_torch.png
│ │ │ ├── raw_icon.png
│ │ │ ├── raw_off_icon.png
│ │ │ ├── raw_only_icon.png
│ │ │ ├── settings.png
│ │ │ ├── share.png
│ │ │ ├── switch_camera.png
│ │ │ ├── take_photo.png
│ │ │ ├── take_photo_pref.png
│ │ │ ├── take_photo_pressed.png
│ │ │ ├── take_photo_when_video_recording.png
│ │ │ ├── take_video.png
│ │ │ ├── take_video_pref.png
│ │ │ ├── take_video_pressed.png
│ │ │ ├── take_video_recording.png
│ │ │ ├── trash.png
│ │ │ ├── white_balance_locked.png
│ │ │ └── white_balance_unlocked.png
│ │ ├── drawable-xhdpi
│ │ │ ├── baseline_add_a_photo_white_48.png
│ │ │ ├── baseline_bluetooth_white_48.png
│ │ │ ├── baseline_check_white_48.png
│ │ │ ├── baseline_close_white_48.png
│ │ │ ├── baseline_filter_vintage_white_48.png
│ │ │ ├── baseline_folder_open_white_48.png
│ │ │ ├── baseline_highlight_white_48.png
│ │ │ ├── baseline_panorama_horizontal_white_48.png
│ │ │ ├── baseline_photo_library_white_48.png
│ │ │ ├── baseline_remove_red_eye_white_48.png
│ │ │ ├── baseline_rotate_left_white_48.png
│ │ │ ├── baseline_rotate_right_white_48.png
│ │ │ ├── baseline_shutter_speed_white_48.png
│ │ │ ├── baseline_text_fields_red_48.png
│ │ │ ├── baseline_text_fields_white_48.png
│ │ │ ├── flash_auto.png
│ │ │ ├── flash_off.png
│ │ │ ├── flash_on.png
│ │ │ ├── ic_align_phases_48dp.png
│ │ │ ├── ic_burst_mode_white_48dp.png
│ │ │ ├── ic_colorize_white_48dp.png
│ │ │ ├── ic_empty.png
│ │ │ ├── ic_exposure_red_48dp.png
│ │ │ ├── ic_exposure_white_48dp.png
│ │ │ ├── ic_face_red_48dp.png
│ │ │ ├── ic_face_white_48dp.png
│ │ │ ├── ic_fast_forward_white_48dp.png
│ │ │ ├── ic_gps_fixed_red_48dp.png
│ │ │ ├── ic_gps_fixed_white_48dp.png
│ │ │ ├── ic_gps_off_white_48dp.png
│ │ │ ├── ic_hdr_on_white_48dp.png
│ │ │ ├── ic_help_outline_white_48dp.png
│ │ │ ├── ic_imu_outline_white_48dp.png
│ │ │ ├── ic_info_outline_white_48dp.png
│ │ │ ├── ic_launcher_take_photo.png
│ │ │ ├── ic_mic_off_white_48dp.png
│ │ │ ├── ic_mic_red_48dp.png
│ │ │ ├── ic_mic_white_48dp.png
│ │ │ ├── ic_more_horiz_white_48dp.png
│ │ │ ├── ic_pause_circle_outline_white_48dp.png
│ │ │ ├── ic_photo_camera_white_48dp.png
│ │ │ ├── ic_photo_size_select_large_white_48dp.png
│ │ │ ├── ic_play_circle_outline_white_48dp.png
│ │ │ ├── ic_power_settings_new_white_48dp.png
│ │ │ ├── ic_recsync.png
│ │ │ ├── ic_save_white_48dp.png
│ │ │ ├── ic_slow_motion_video_white_48dp.png
│ │ │ ├── ic_sync_settings_48dp.png
│ │ │ ├── ic_sync_settings_red_48dp.png
│ │ │ ├── ic_text_format_red_48dp.png
│ │ │ ├── ic_text_format_white_48dp.png
│ │ │ ├── ic_timelapse_white_48dp.png
│ │ │ ├── ic_timer_white_48dp.png
│ │ │ ├── ic_touch_app_white_48dp.png
│ │ │ ├── ic_videocam_white_48dp.png
│ │ │ ├── settings.png
│ │ │ ├── share.png
│ │ │ ├── switch_camera.png
│ │ │ ├── take_photo.png
│ │ │ ├── take_photo_pref.png
│ │ │ ├── take_photo_pressed.png
│ │ │ ├── take_photo_when_video_recording.png
│ │ │ ├── take_video.png
│ │ │ ├── take_video_pressed.png
│ │ │ ├── take_video_recording.png
│ │ │ └── trash.png
│ │ ├── drawable-xxhdpi
│ │ │ ├── auto_stabilise_icon.png
│ │ │ ├── auto_stabilise_icon_red.png
│ │ │ ├── baseline_add_a_photo_white_48.png
│ │ │ ├── baseline_bluetooth_white_48.png
│ │ │ ├── baseline_check_white_48.png
│ │ │ ├── baseline_close_white_48.png
│ │ │ ├── baseline_filter_vintage_white_48.png
│ │ │ ├── baseline_folder_open_white_48.png
│ │ │ ├── baseline_highlight_white_48.png
│ │ │ ├── baseline_panorama_horizontal_white_48.png
│ │ │ ├── baseline_photo_library_white_48.png
│ │ │ ├── baseline_remove_red_eye_white_48.png
│ │ │ ├── baseline_rotate_left_white_48.png
│ │ │ ├── baseline_rotate_right_white_48.png
│ │ │ ├── baseline_shutter_speed_white_48.png
│ │ │ ├── baseline_text_fields_red_48.png
│ │ │ ├── baseline_text_fields_white_48.png
│ │ │ ├── dro_icon.png
│ │ │ ├── expo_icon.png
│ │ │ ├── flash_auto.png
│ │ │ ├── flash_off.png
│ │ │ ├── flash_on.png
│ │ │ ├── focus_bracket_icon.png
│ │ │ ├── ic_align_phases_48dp.png
│ │ │ ├── ic_burst_mode_white_48dp.png
│ │ │ ├── ic_colorize_white_48dp.png
│ │ │ ├── ic_empty.png
│ │ │ ├── ic_exposure_red_48dp.png
│ │ │ ├── ic_exposure_white_48dp.png
│ │ │ ├── ic_face_red_48dp.png
│ │ │ ├── ic_face_white_48dp.png
│ │ │ ├── ic_fast_forward_white_48dp.png
│ │ │ ├── ic_gps_fixed_red_48dp.png
│ │ │ ├── ic_gps_fixed_white_48dp.png
│ │ │ ├── ic_gps_off_white_48dp.png
│ │ │ ├── ic_hdr_on_white_48dp.png
│ │ │ ├── ic_help_outline_white_48dp.png
│ │ │ ├── ic_imu_outline_white_48dp.png
│ │ │ ├── ic_info_outline_white_48dp.png
│ │ │ ├── ic_launcher_take_photo.png
│ │ │ ├── ic_mic_off_white_48dp.png
│ │ │ ├── ic_mic_red_48dp.png
│ │ │ ├── ic_mic_white_48dp.png
│ │ │ ├── ic_more_horiz_white_48dp.png
│ │ │ ├── ic_pause_circle_outline_white_48dp.png
│ │ │ ├── ic_photo_camera_white_48dp.png
│ │ │ ├── ic_photo_size_select_large_white_48dp.png
│ │ │ ├── ic_play_circle_outline_white_48dp.png
│ │ │ ├── ic_power_settings_new_white_48dp.png
│ │ │ ├── ic_recsync.png
│ │ │ ├── ic_save_white_48dp.png
│ │ │ ├── ic_slow_motion_video_white_48dp.png
│ │ │ ├── ic_stat_notify_take_photo.png
│ │ │ ├── ic_sync_settings_48dp.png
│ │ │ ├── ic_sync_settings_red_48dp.png
│ │ │ ├── ic_text_format_red_48dp.png
│ │ │ ├── ic_text_format_white_48dp.png
│ │ │ ├── ic_timelapse_white_48dp.png
│ │ │ ├── ic_timer_white_48dp.png
│ │ │ ├── ic_touch_app_white_48dp.png
│ │ │ ├── ic_videocam_white_48dp.png
│ │ │ ├── iso_icon.png
│ │ │ ├── nr_icon.png
│ │ │ ├── raw_icon.png
│ │ │ ├── raw_off_icon.png
│ │ │ ├── raw_only_icon.png
│ │ │ ├── settings.png
│ │ │ ├── share.png
│ │ │ ├── switch_camera.png
│ │ │ └── trash.png
│ │ ├── drawable-xxxhdpi
│ │ │ ├── baseline_add_a_photo_white_48.png
│ │ │ ├── baseline_bluetooth_white_48.png
│ │ │ ├── baseline_check_white_48.png
│ │ │ ├── baseline_close_white_48.png
│ │ │ ├── baseline_filter_vintage_white_48.png
│ │ │ ├── baseline_folder_open_white_48.png
│ │ │ ├── baseline_highlight_white_48.png
│ │ │ ├── baseline_panorama_horizontal_white_48.png
│ │ │ ├── baseline_photo_library_white_48.png
│ │ │ ├── baseline_remove_red_eye_white_48.png
│ │ │ ├── baseline_rotate_left_white_48.png
│ │ │ ├── baseline_rotate_right_white_48.png
│ │ │ ├── baseline_shutter_speed_white_48.png
│ │ │ ├── baseline_text_fields_red_48.png
│ │ │ ├── baseline_text_fields_white_48.png
│ │ │ ├── ic_align_phases_48dp.png
│ │ │ ├── ic_burst_mode_white_48dp.png
│ │ │ ├── ic_colorize_white_48dp.png
│ │ │ ├── ic_empty.png
│ │ │ ├── ic_exposure_red_48dp.png
│ │ │ ├── ic_exposure_white_48dp.png
│ │ │ ├── ic_face_red_48dp.png
│ │ │ ├── ic_face_white_48dp.png
│ │ │ ├── ic_fast_forward_white_48dp.png
│ │ │ ├── ic_gps_fixed_red_48dp.png
│ │ │ ├── ic_gps_fixed_white_48dp.png
│ │ │ ├── ic_gps_off_white_48dp.png
│ │ │ ├── ic_hdr_on_white_48dp.png
│ │ │ ├── ic_help_outline_white_48dp.png
│ │ │ ├── ic_imu_outline_white_48dp.png
│ │ │ ├── ic_info_outline_white_48dp.png
│ │ │ ├── ic_mic_off_white_48dp.png
│ │ │ ├── ic_more_horiz_white_48dp.png
│ │ │ ├── ic_pause_circle_outline_white_48dp.png
│ │ │ ├── ic_photo_camera_white_48dp.png
│ │ │ ├── ic_photo_size_select_large_white_48dp.png
│ │ │ ├── ic_play_circle_outline_white_48dp.png
│ │ │ ├── ic_power_settings_new_white_48dp.png
│ │ │ ├── ic_recsync.png
│ │ │ ├── ic_save_white_48dp.png
│ │ │ ├── ic_slow_motion_video_white_48dp.png
│ │ │ ├── ic_sync_settings_48dp.png
│ │ │ ├── ic_sync_settings_red_48dp.png
│ │ │ ├── ic_text_format_red_48dp.png
│ │ │ ├── ic_text_format_white_48dp.png
│ │ │ ├── ic_timelapse_white_48dp.png
│ │ │ ├── ic_timer_white_48dp.png
│ │ │ ├── ic_touch_app_white_48dp.png
│ │ │ ├── ic_videocam_white_48dp.png
│ │ │ └── settings.png
│ │ ├── drawable
│ │ │ ├── circle_background.xml
│ │ │ ├── shortcut_gallery.xml
│ │ │ ├── shortcut_ic_face_white_48dp.xml
│ │ │ ├── shortcut_ic_photo_camera_white_48dp.xml
│ │ │ ├── shortcut_ic_videocam_white_48dp.xml
│ │ │ ├── shortcut_settings.xml
│ │ │ ├── take_photo_selector.xml
│ │ │ └── take_video_selector.xml
│ │ ├── layout
│ │ │ ├── activity_device_select.xml
│ │ │ ├── activity_main.xml
│ │ │ ├── arrayseekbarpreference.xml
│ │ │ ├── listitem_device.xml
│ │ │ ├── widget_layout.xml
│ │ │ └── widget_layout_take_photo.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── raw
│ │ │ ├── default_phaseconfig.json
│ │ │ ├── mybeep.ogg
│ │ │ └── mybeep_hi.ogg
│ │ ├── values-az
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-be
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-cs
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-de
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-el
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-fr
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-hu
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-ja
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-ko
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-nb
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-pl
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-pt-rBR
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-pt-rPT
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-sl
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-sw600dp
│ │ │ └── dimens.xml
│ │ ├── values-sw720dp-land
│ │ │ └── dimens.xml
│ │ ├── values-tr
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-uk
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-v11
│ │ │ └── styles.xml
│ │ ├── values-v14
│ │ │ └── styles.xml
│ │ ├── values-v21
│ │ │ └── styles.xml
│ │ ├── values-vi
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values-zh-rTW
│ │ │ ├── arrays.xml
│ │ │ └── strings.xml
│ │ ├── values
│ │ │ ├── arrays.xml
│ │ │ ├── colors.xml
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── xml-v25
│ │ │ └── shortcuts.xml
│ │ └── xml
│ │ │ ├── preferences.xml
│ │ │ ├── widget_info.xml
│ │ │ └── widget_info_take_photo.xml
│ └── rs
│ │ ├── align_mtb.rs
│ │ ├── avg_brighten.rs
│ │ ├── calculate_sharpness.rs
│ │ ├── create_mtb.rs
│ │ ├── feature_detector.rs
│ │ ├── histogram_adjust.rs
│ │ ├── histogram_compute.rs
│ │ ├── process_avg.rs
│ │ ├── process_hdr.rs
│ │ └── pyramid_blending.rs
│ └── test
│ └── java
│ └── net
│ └── sourceforge
│ └── opencamera
│ └── test
│ └── UnitTest.java
├── build.gradle
├── fastlane
└── metadata
│ └── android
│ └── en-US
│ ├── changelogs
│ └── 81.txt
│ ├── full_description.txt
│ ├── images
│ ├── icon.png
│ └── phoneScreenshots
│ │ ├── 1.png
│ │ ├── 2.png
│ │ └── 3.png
│ ├── short_description.txt
│ └── title.txt
├── google_material_design_icons_LICENSE-2.0.txt
├── gpl-3.0.txt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── makesrcarchive.bat
├── my-release-key.keystore.gpg
├── opencamera-extended-0152130a4960.json.enc
├── opencamera_source.txt
└── settings.gradle
/.github/workflows/fastlane.yml:
--------------------------------------------------------------------------------
1 | name: Validate Fastlane metadata
2 |
3 | on: [ push, workflow_dispatch ]
4 |
5 | jobs:
6 | validate:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v3
10 |
11 | - uses: ashutoshgngwr/validate-fastlane-supply-metadata@v2
12 |
--------------------------------------------------------------------------------
/.github/workflows/unit-test.yml:
--------------------------------------------------------------------------------
1 | name: Run unit tests
2 |
3 | on: [ push, workflow_dispatch ]
4 |
5 | env:
6 | keystore_password: ${{ secrets.KeystorePassword }}
7 | keystore_alias: ${{ secrets.KeystoreAlias }}
8 | keystore_alias_password: ${{ secrets.KeystoreAliasPassword }}
9 |
10 | jobs:
11 | unit-test:
12 | runs-on: ubuntu-latest
13 |
14 | steps:
15 | - uses: actions/checkout@v2
16 |
17 | - uses: actions/setup-java@v2
18 | with:
19 | distribution: 'adopt'
20 | java-version: '8'
21 |
22 | - name: Cache Gradle packages
23 | uses: actions/cache@v2
24 | with:
25 | path: |
26 | ~/.gradle/caches
27 | ~/.gradle/wrapper
28 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
29 | restore-keys: |
30 | ${{ runner.os }}-gradle-
31 |
32 | - name: Decrypt keystore file
33 | env:
34 | enc_key: ${{ secrets.KeystoreEncKey }}
35 | run: gpg --quiet --batch --yes --decrypt --passphrase="$enc_key" --output my-release-key.keystore my-release-key.keystore.gpg
36 |
37 | - name: Assemble debug
38 | run: ./gradlew assembleDebug
39 |
40 | - name: Assemble release
41 | run: ./gradlew assembleRelease
42 |
43 | - name: Test debug
44 | run: ./gradlew testDebugUnitTest
45 |
46 | - name: Test release
47 | run: ./gradlew testReleaseUnitTest
48 |
49 | - name: Cleanup Gradle Cache
50 | # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
51 | # Restoring these files from a GitHub Actions cache might cause problems for future builds.
52 | run: |
53 | rm -f ~/.gradle/caches/modules-2/modules-2.lock
54 | rm -f ~/.gradle/caches/modules-2/gc.properties
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | _archive/
2 | _devdocs/
3 | _docs/*.jpg
4 | _docs/ads.txt
5 | _docs/app-ads.txt
6 | _docs/gplay.html
7 | _other/
8 | _saved/
9 |
10 | .gradle/
11 |
12 | .idea/*
13 | !.idea/inspectionProfiles
14 |
15 | build/
16 | app/release/
17 | gfx/
18 | testdata/
19 |
20 | *.db
21 | *.iml
22 | *.apk
23 | *.ap_
24 |
25 | local.properties
26 | uninstall.bat
27 |
28 | *.keystore
29 |
30 | opencamera-extended-firebase-adminsdk-yv5yz-e33a8ce5c1.json
31 |
32 | *.csv
33 |
34 | *.mp4
35 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech. 17 | */ 18 | 19 | package com.googleresearch.capturesync.softwaresync; 20 | 21 | /** 22 | * Interface for RPC callbacks, the base methods used for communicating between devices. 23 | */ 24 | public interface RpcCallback { 25 | 26 | /** 27 | * The callback method called when an RPC is received. 28 | * 29 | * @param payload Contains the payload sent by the RPC. 30 | */ 31 | void call(String payload); 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/com/googleresearch/capturesync/softwaresync/SntpOffsetResponse.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 The Google Research Authors. 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech. 17 | */ 18 | 19 | package com.googleresearch.capturesync.softwaresync; 20 | 21 | /** 22 | * AutoValue class for SNTP offsetNs, synchronization accuracy and status. 23 | */ 24 | public final class SntpOffsetResponse { 25 | private final long mOffsetNs; 26 | private final long mSyncAccuracyNs; 27 | private final boolean mStatus; 28 | 29 | static SntpOffsetResponse create(long offset, long syncAccuracy, boolean status) { 30 | return new SntpOffsetResponse(offset, syncAccuracy, status); 31 | } 32 | 33 | private SntpOffsetResponse(long offsetNs, long syncAccuracyNs, boolean status) { 34 | mOffsetNs = offsetNs; 35 | mSyncAccuracyNs = syncAccuracyNs; 36 | mStatus = status; 37 | } 38 | 39 | /** 40 | * The time delta (leader - client) in nanoseconds of the AP SystemClock domain. 41 | * 42 | *
The client can take their local_time to get leader_time via: local_time (leader - client) = 43 | * leader_time. 44 | */ 45 | public long offsetNs() { 46 | return mOffsetNs; 47 | } 48 | 49 | /** 50 | * The worst case error in the clock domains between leader and client for this response, in 51 | * nanoseconds of the AP SystemClock domain. 52 | */ 53 | public long syncAccuracyNs() { 54 | return mSyncAccuracyNs; 55 | } 56 | 57 | /** 58 | * The success status of this response. 59 | */ 60 | public boolean status() { 61 | return mStatus; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/googleresearch/capturesync/softwaresync/SystemTicker.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 The Google Research Authors. 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech. 17 | */ 18 | 19 | package com.googleresearch.capturesync.softwaresync; 20 | 21 | import android.os.SystemClock; 22 | 23 | /** 24 | * Simple implementation of Ticker interface using the SystemClock elapsed realtime clock. 25 | */ 26 | public class SystemTicker implements Ticker { 27 | @Override 28 | public long read() { 29 | return SystemClock.elapsedRealtimeNanos(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/googleresearch/capturesync/softwaresync/Ticker.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 The Google Research Authors. 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech. 17 | */ 18 | 19 | package com.googleresearch.capturesync.softwaresync; 20 | 21 | /** 22 | * Interface for getting the time in nanoseconds, abstracting out accessing system time. 23 | */ 24 | public interface Ticker { 25 | /* Returns the time in nanoseconds. */ 26 | long read(); 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/googleresearch/capturesync/softwaresync/TimeDomainConverter.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 The Google Research Authors. 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech. 17 | */ 18 | 19 | package com.googleresearch.capturesync.softwaresync; 20 | 21 | /** 22 | * Interface used to manage time domain conversion, implemented by {@link SoftwareSyncBase}. This 23 | * allows {@link ResultProcessor} to convert sensor timestamps to the synchronized time domain 24 | * without needing full access to the softwaresync object. 25 | */ 26 | public interface TimeDomainConverter { 27 | 28 | /** 29 | * Calculates the leader time associated with the given local time in nanoseconds. The local time 30 | * must be in the SystemClock.elapsedRealTimeNanos() localClock domain, nanosecond units. This 31 | * includes timestamps such as the sensor timestamp from the camera. leader_time = 32 | * local_elapsed_time_ns + leader_from_local_ns. 33 | * 34 | * @param localTimeNs given local time (local clock SystemClock.elapsedRealtimeNanos() domain). 35 | * @return leader synchronized time in nanoseconds. 36 | */ 37 | long leaderTimeForLocalTimeNs(long localTimeNs); 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/googleresearch/capturesync/softwaresync/TimeUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2019 The Google Research Authors. 3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *
10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | *
16 | * Modifications copyright (C) 2021 Mobile Robotics Lab. at Skoltech.
17 | */
18 |
19 | package com.googleresearch.capturesync.softwaresync;
20 |
21 | /**
22 | * Helper conversions between time scales.
23 | */
24 | public final class TimeUtils {
25 |
26 | public static double nanosToMillis(double nanos) {
27 | return nanos / 1_000_000L;
28 | }
29 |
30 | public static long nanosToSeconds(long nanos) {
31 | return nanos / 1_000_000_000L;
32 | }
33 |
34 | public static double nanosToSeconds(double nanos) {
35 | return nanos / 1_000_000_000L;
36 | }
37 |
38 | public static long millisToNanos(long millis) {
39 | return millis * 1_000_000L;
40 | }
41 |
42 | public static long secondsToNanos(int seconds) {
43 | return seconds * 1_000_000_000L;
44 | }
45 |
46 | private TimeUtils() {
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/googleresearch/capturesync/softwaresync/phasealign/StreamUtils.java:
--------------------------------------------------------------------------------
1 | package com.googleresearch.capturesync.softwaresync.phasealign;
2 |
3 | import android.os.Build;
4 |
5 | import androidx.annotation.RequiresApi;
6 |
7 | import java.util.Iterator;
8 | import java.util.Objects;
9 | import java.util.Spliterator;
10 | import java.util.Spliterators;
11 | import java.util.function.BiFunction;
12 | import java.util.stream.Stream;
13 | import java.util.stream.StreamSupport;
14 |
15 | /**
16 | * Helper functions to works with {@link java.util.stream.Stream}.
17 | */
18 | public class StreamUtils {
19 |
20 | private StreamUtils() {
21 | }
22 |
23 | /**
24 | * Constructs a new stream with the results of applying the provided function to the contents
25 | * of the provided streams one by one.
26 | * Original implementation: https://stackoverflow.com/a/23529010.
27 | *
28 | * @param a the first stream.
29 | * @param b the second stream.
30 | * @param zipper the function to be applied to the elements of the given streams with the same
31 | * indices.
32 | * @return a stream containing the results of the given function.
33 | */
34 | @RequiresApi(api = Build.VERSION_CODES.N)
35 | public static Stream