Compare commits

...

132 Commits

Author SHA1 Message Date
Hardcore Sushi 5144947a4a
Media player fixes: better handling of RTL & orientation 2 weeks ago
Muhmmad14333653 6b52eed9d0
update arabic translation 2 weeks ago
Muhmmad14333653 2a257d91d0
update Arabic translation 2 weeks ago
Hardcore Sushi f837556af5
Fix explorer info bar color in dark mode 2 weeks ago
Hardcore Sushi b7ab267d16
Arabic translation 2 weeks ago
Hardcore Sushi 5ea0b8ad41
Actually fix camera icon tint bug 2 weeks ago
Hardcore Sushi ec348383c6
Fix camera icon tint bug 2 weeks ago
Hardcore Sushi c8d266150c
Fix explorer menu display 2 weeks ago
CyanWolf 4bbc9360b4
Update Spanish translation 4 weeks ago
Hardcore Sushi 8aa2be2b05
Update libgocryptfs & Small UX fix 4 weeks ago
Hardcore Sushi e2248220c4
DroidFS v1.10.0 4 weeks ago
Hardcore Sushi 7959b20b3f
Update libgocryptfs 4 weeks ago
solokot 8cebe499f0
Updated Russian translation 4 weeks ago
cyanwolfg a22b9d8fa8
Update Spanish translation 4 weeks ago
Hardcore Sushi cba1418417
Fix move operation 4 weeks ago
Hardcore Sushi b6b8bba666
Save checkbox state if opening volume fails 4 weeks ago
Hardcore Sushi e00abdf5bb
Switch to Kotlin coroutines 4 weeks ago
Hardcore Sushi 72cce1d7e1
Show a fingerprint icon when password hash is saved 1 month ago
Hardcore Sushi 55b0ac0daa
Prefill text field with current name when renaming a volume 1 month ago
Hardcore Sushi 53f28e9475
Pin passwords 1 month ago
Hardcore Sushi f1d4b07726
Show total number of selected items 1 month ago
Hardcore Sushi 339309b00d
Fix image viewer rotation handling 1 month ago
Hardcore Sushi e6a1285e0a
Fix camera output rotation 1 month ago
Hardcore Sushi ab48f9219b
CameraActivity: only bind 2 use cases at most + some other fixes 1 month ago
Hardcore Sushi c521c7f998
Open default volume on application startup 1 month ago
Hardcore Sushi 1d13dfbde3
Always show total size & Add some explorer info bar translations 1 month ago
Hardcore Sushi 36ab66fb43
Show number of files & folders in current directory 1 month ago
Hardcore Sushi 1caabc2554
Fix explorer layouts 1 month ago
Hardcore Sushi f541504e07
Refactor RecyclerView adapters 1 month ago
Hardcore Sushi 4de5b41102
Thumbnails cache & Don't do full reload on selection change 1 month ago
Hardcore Sushi 4f9aa55dfe
Explorer grid layout 1 month ago
Hardcore Sushi 91de54018d
Prompt for password if fingerprint authentification fails 2 months ago
Hardcore Sushi 2697eaf11b
Spanish translation 2 months ago
Hardcore Sushi 9e69805ade
Update ptbr translation 2 months ago
Hardcore Sushi 18d0f50094
Update to libpdfviewer 13 2 months ago
Hardcore Sushi e32e106ce3
Fix video player controls 2 months ago
Hardcore Sushi 4608a7a165
Fix MainSettingsFragment crash 2 months ago
Hardcore Sushi 985be2de59
Add HEIC to the image extension list 2 months ago
solokot f07d99efed
Updated Russian translation 2 months ago
Hardcore Sushi 4a55d826d9
Volume renaming 2 months ago
Hardcore Sushi 2ee7a5b871
Allow changing thumbnail max size 2 months ago
Hardcore Sushi 72321b8ec5
Switch to StyledPlayerView 2 months ago
Hardcore Sushi 7226cc8218
Fix UI bug on too long volume paths 2 months ago
Hardcore Sushi 55be5cd0e7
DroidFS v1.9.0 2 months ago
solokot 3c4515e4e9
Update Russian translation 2 months ago
Hardcore Sushi 29eb34e1d5
New screenshots 2 months ago
Hardcore Sushi d6f727a142
Fix error message when creating volume on external SD card 2 months ago
Hardcore Sushi 6d5fc465c7
Fix UI bug on alert dialogs 2 months ago
Hardcore Sushi ed0b5eb483
Add PDF in OpenAs dialog & libpdfviewer dialog crash fix 2 months ago
Hardcore Sushi fd0296f801
Update libpdfviewer 2 months ago
Hardcore Sushi 58391802be
More accurate directory size 2 months ago
Hardcore Sushi e01b5a3098
Volume copy 2 months ago
Hardcore Sushi bea0906f65
Display file name on video player 2 months ago
Hardcore Sushi 71a314b0a0
New home UI 2 months ago
Hardcore Sushi 842667cdee
Update ptbr translation 3 months ago
Hardcore Sushi e5bcc5cfc2
Update dependencies 3 months ago
Hardcore Sushi 32508344fe
Update PGP key 3 months ago
Hardcore Sushi ee3df7c3bf
Icon for PDF files 3 months ago
Hardcore Sushi b18232615d
PDF viewer 3 months ago
Hardcore Sushi 83efc53edc
Update PGP keyserver 4 months ago
Hardcore Sushi f546e64c34
ImageViwer: retrieve screen size with Resources.getSystem().displayMetrics 4 months ago
Hardcore Sushi 822aba9481
Better build explanation 4 months ago
Hardcore Sushi 3007bf756c
Fix video player UI bug 4 months ago
solokot 87cd88232e
Update russian translation 4 months ago
Hardcore Sushi 832fd1d34b
DoubleTapPlayerView 4 months ago
Hardcore Sushi 3ae7e4df70
Remove DialogSingleChoiceAdapter 4 months ago
Hardcore Sushi 55883172a1
Consider WebP as image 4 months ago
Hardcore Sushi b366fa1877
Fill viewport in text editor 4 months ago
Hardcore Sushi 95eed07719
Natural file name sorting 4 months ago
Hardcore Sushi f15b17c936
Fix scroll issue on OpenActivity & ChangePasswordActivity 4 months ago
Hardcore Sushi 5d6f53b37a
Change icon of mode button when switching between photo & video mode 4 months ago
Hardcore Sushi 23d017780f
Flush previous image before loading the next in ImageViewer 5 months ago
Hardcore Sushi bee2997f90
Update dependencies 5 months ago
Hardcore Sushi 80c5277936
Reset flash state when switching to back camera in video mode 5 months ago
solokot a9d4284b43
Updated Russian translation 5 months ago
Hardcore Sushi 7ca9398766
Fix size formatting 5 months ago
Hardcore Sushi bd4c935c4c
Downscale image when decoding with BitmapFactory 5 months ago
Hardcore Sushi b65ee230be
Fix flash and timer for video recording 5 months ago
Hardcore Sushi 8b4adfbe21
Update dependencies 5 months ago
Hardcore Sushi 57e93f0b49
Fix video player auto rotation 5 months ago
Hang Hang be802aa5af
Legacy fullscreen mode option & Button to toggle screen orientation in video player 5 months ago
Hardcore Sushi d1a556b8c6
Invalidate options menu when changing explorer elements 5 months ago
solokot 83525159e3
Updated Russian translation to v1.7.0 6 months ago
Hardcore Sushi 4f8bf860e0
Don't use DayNight themes 6 months ago
Hardcore Sushi 2ee0c679fb
Fix bugs when renaming 6 months ago
Hardcore Sushi 23a20b7ddb
Fix delete icon color bug 6 months ago
Hardcore Sushi fd5ddc02b1
Thumbnails 6 months ago
Hardcore Sushi e3df7be3b5
Switch explorer from ListView to RecyclerView 6 months ago
Hardcore Sushi 65ecdd19ca
Remove some deprecation warnings 6 months ago
Hardcore Sushi d3f0d059f8
Switch from Cyanea to Themes 6 months ago
Hardcore Sushi d572a8d2dc
Update dependencies 6 months ago
Hardcore Sushi 01a9c261f5
Fix image viewer 6 months ago
Hardcore Sushi 1cab607fa1
Decode images with BitmapFactory instead of Glide 7 months ago
Hardcore Sushi 26153d44b9
Update description & build process for F-Droid 7 months ago
solokot 2d0ec3529d
Updated Russian translation 7 months ago
Hardcore Sushi e96d4724d3
Adapt to write access at Android/data/sushi.hardcore.droidfs on SD cards 7 months ago
Hardcore Sushi 6158b36c9f
Fix fingerprint checkbox behavior 7 months ago
Hardcore Sushi b273fa828b
Upgrade CameraX 7 months ago
Hardcore Sushi 5349d40da9
Add "Open as" option in explorer menu 7 months ago
Hardcore Sushi c858d556d5
Exoplayer repeat & shuffle controls 7 months ago
Hardcore Sushi e47d9f4548
XChaCha20-Ploy1305 support 7 months ago
Hardcore Sushi a377b61240
Use FFmpeg shared libraries & Update build instructions 7 months ago
Hardcore Sushi 497c22edc1
Fix recorded video rotation 7 months ago
Hardcore Sushi dc89c02b9f
Video recording 7 months ago
Hardcore Sushi fd98c42014
DroidFS v1.5.4 9 months ago
solokot 0fdd889697
Update Russian translation to v1.5.3 9 months ago
Hardcore Sushi b9a7411cdb
Remove some other deprecation warnings 9 months ago
Hardcore Sushi d36910ac19
Fix proguard rules 9 months ago
Hardcore Sushi dc62f73188
Update gradle plugin 9 months ago
Hardcore Sushi 4ede408aac
Remove some deprecation warnings 9 months ago
Hardcore Sushi 52eab2a2df
Fix a nasty bug with playlists 9 months ago
Hardcore Sushi b65ac79175
Update dependencies & Add camera capture mode settings 9 months ago
Hardcore Sushi ba42938f5a
Upgrade to OpenSSL v1.1.1l 9 months ago
Hardcore Sushi 54b6d03335
Upgrade to libgocryptfs v2.1 9 months ago
solokot de0f45a05c
Update Russian translation 9 months ago
Hardcore Sushi 6f49cec157
Delete root directory from background service when wiping 9 months ago
Hardcore Sushi faeab5d3f6
Add ".properties" to the text file extensions list 9 months ago
Hardcore Sushi c2c1e4b1e9
Delete file & folder on wipe 9 months ago
Anon7250 5cc9abfd76
Adding an 'Import/Encrypt Folder' button 9 months ago
Hardcore Sushi 60ba9531be
Upgrade gradle 9 months ago
mezysinc 47bd751b66
update ptbr 10 months ago
Hardcore Sushi a4a1454d91
Update dependencies 10 months ago
solokot 90c63f4599
Updated Russian language 10 months ago
Hardcore Sushi 5951237f2c
Optional folder mapping 10 months ago
mezysinc 7d5eb19eb7
ptbr update 11 months ago
Hardcore Sushi b8646b0fff
Upgrade libgocryptfs 11 months ago
Hardcore Sushi cffc24e4ba
Create new file in the current directory 11 months ago
Hardcore Sushi 286253c542
Set permissions when creating files and folders 11 months ago
Hardcore Sushi f58517e904
Thread-safe directory listing 11 months ago
Hardcore Sushi e5ed825557
Add F-Droid download links in README 11 months ago
Hardcore Sushi 2c69c59331
Specify NDK v21 in README 11 months ago
Hardcore Sushi e017fa85bd
Update README for v1.5.0 11 months ago
  1. 3
      .gitmodules
  2. 102
      README.md
  3. 56
      app/CMakeLists.txt
  4. 51
      app/build.gradle
  5. 2
      app/ffmpeg/.gitignore
  6. 94
      app/ffmpeg/build.sh
  7. 2
      app/libgocryptfs
  8. 12
      app/proguard-rules.pro
  9. 68
      app/src/main/AndroidManifest.xml
  10. 57
      app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt
  11. 484
      app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt
  12. 301
      app/src/main/java/sushi/hardcore/droidfs/ChangePasswordActivity.kt
  13. 11
      app/src/main/java/sushi/hardcore/droidfs/ColoredApplication.kt
  14. 79
      app/src/main/java/sushi/hardcore/droidfs/ConstValues.kt
  15. 190
      app/src/main/java/sushi/hardcore/droidfs/CreateActivity.kt
  16. 259
      app/src/main/java/sushi/hardcore/droidfs/FingerprintProtector.kt
  17. 141
      app/src/main/java/sushi/hardcore/droidfs/GocryptfsVolume.kt
  18. 55
      app/src/main/java/sushi/hardcore/droidfs/LoadingTask.kt
  19. 641
      app/src/main/java/sushi/hardcore/droidfs/MainActivity.kt
  20. 273
      app/src/main/java/sushi/hardcore/droidfs/OpenActivity.kt
  21. 13
      app/src/main/java/sushi/hardcore/droidfs/SensorOrientationListener.kt
  22. 118
      app/src/main/java/sushi/hardcore/droidfs/SettingsActivity.kt
  23. 53
      app/src/main/java/sushi/hardcore/droidfs/Volume.kt
  24. 369
      app/src/main/java/sushi/hardcore/droidfs/VolumeActionActivity.kt
  25. 31
      app/src/main/java/sushi/hardcore/droidfs/VolumeDatabase.kt
  26. 33
      app/src/main/java/sushi/hardcore/droidfs/adapters/DialogSingleChoiceAdapter.kt
  27. 279
      app/src/main/java/sushi/hardcore/droidfs/adapters/ExplorerElementAdapter.kt
  28. 7
      app/src/main/java/sushi/hardcore/droidfs/adapters/IconTextDialogAdapter.kt
  29. 1
      app/src/main/java/sushi/hardcore/droidfs/adapters/OpenAsDialogAdapter.kt
  30. 111
      app/src/main/java/sushi/hardcore/droidfs/adapters/SavedVolumesAdapter.kt
  31. 80
      app/src/main/java/sushi/hardcore/droidfs/adapters/SelectableAdapter.kt
  32. 111
      app/src/main/java/sushi/hardcore/droidfs/adapters/VolumeAdapter.kt
  33. 6
      app/src/main/java/sushi/hardcore/droidfs/add_volume/Action.kt
  34. 79
      app/src/main/java/sushi/hardcore/droidfs/add_volume/AddVolumeActivity.kt
  35. 207
      app/src/main/java/sushi/hardcore/droidfs/add_volume/CreateVolumeFragment.kt
  36. 275
      app/src/main/java/sushi/hardcore/droidfs/add_volume/SelectPathFragment.kt
  37. 72
      app/src/main/java/sushi/hardcore/droidfs/collation/ByteString.kt
  38. 47
      app/src/main/java/sushi/hardcore/droidfs/collation/ByteStringBuilder.kt
  39. 115
      app/src/main/java/sushi/hardcore/droidfs/collation/CollatorFileNameExtensions.kt
  40. 95
      app/src/main/java/sushi/hardcore/droidfs/content_providers/ExternalProvider.kt
  41. 479
      app/src/main/java/sushi/hardcore/droidfs/explorers/BaseExplorerActivity.kt
  42. 356
      app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivity.kt
  43. 12
      app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityDrop.kt
  44. 10
      app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerActivityPick.kt
  45. 37
      app/src/main/java/sushi/hardcore/droidfs/explorers/ExplorerElement.kt
  46. 4
      app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationNotification.kt
  47. 439
      app/src/main/java/sushi/hardcore/droidfs/file_operations/FileOperationService.kt
  48. 20
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/AudioPlayer.kt
  49. 91
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/FileViewerActivity.kt
  50. 2
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/GocryptfsDataSource.kt
  51. 100
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/ImageViewer.kt
  52. 72
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/MediaPlayer.kt
  53. 47
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/PdfViewer.kt
  54. 24
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/TextEditor.kt
  55. 28
      app/src/main/java/sushi/hardcore/droidfs/file_viewers/VideoPlayer.kt
  56. 33
      app/src/main/java/sushi/hardcore/droidfs/util/PathUtils.kt
  57. 20
      app/src/main/java/sushi/hardcore/droidfs/util/WidgetUtil.kt
  58. 44
      app/src/main/java/sushi/hardcore/droidfs/util/Wiper.kt
  59. 94
      app/src/main/java/sushi/hardcore/droidfs/video_recording/MediaMuxer.kt
  60. 7
      app/src/main/java/sushi/hardcore/droidfs/video_recording/SeekableWriter.kt
  61. 1767
      app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCapture.java
  62. 212
      app/src/main/java/sushi/hardcore/droidfs/video_recording/VideoCaptureConfig.java
  63. 198
      app/src/main/java/sushi/hardcore/droidfs/widgets/CircleClipTapView.kt
  64. 46
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredAlertDialogBuilder.kt
  65. 28
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredBorderListView.kt
  66. 15
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredCheckBox.kt
  67. 15
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredEditText.kt
  68. 18
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredFAB.kt
  69. 14
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredImageButton.kt
  70. 14
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredImageView.kt
  71. 30
      app/src/main/java/sushi/hardcore/droidfs/widgets/ColoredListPreference.kt
  72. 61
      app/src/main/java/sushi/hardcore/droidfs/widgets/CustomAlertDialogBuilder.kt
  73. 216
      app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapOverlay.kt
  74. 169
      app/src/main/java/sushi/hardcore/droidfs/widgets/DoubleTapPlayerView.kt
  75. 39
      app/src/main/java/sushi/hardcore/droidfs/widgets/EditTextDialog.kt
  76. 26
      app/src/main/java/sushi/hardcore/droidfs/widgets/NonScrollableColoredBorderListView.kt
  77. 16
      app/src/main/java/sushi/hardcore/droidfs/widgets/SimpleActionPreference.kt
  78. 25
      app/src/main/java/sushi/hardcore/droidfs/widgets/ThemeColor.kt
  79. 38
      app/src/main/native/gocryptfs_jni.c
  80. 131
      app/src/main/native/libmux.c
  81. 2
      app/src/main/res/drawable/button_background.xml
  82. 6
      app/src/main/res/drawable/icon_camera.xml
  83. 5
      app/src/main/res/drawable/icon_create_new_folder.xml
  84. 2
      app/src/main/res/drawable/icon_decrypt.xml
  85. 4
      app/src/main/res/drawable/icon_delete.xml
  86. 5
      app/src/main/res/drawable/icon_encrypt.xml
  87. 2
      app/src/main/res/drawable/icon_file_audio.xml
  88. 2
      app/src/main/res/drawable/icon_file_image.xml
  89. 9
      app/src/main/res/drawable/icon_file_pdf.xml
  90. 2
      app/src/main/res/drawable/icon_file_text.xml
  91. 2
      app/src/main/res/drawable/icon_file_unknown.xml
  92. 2
      app/src/main/res/drawable/icon_file_video.xml
  93. 4
      app/src/main/res/drawable/icon_fingerprint.xml
  94. 2
      app/src/main/res/drawable/icon_folder.xml
  95. 9
      app/src/main/res/drawable/icon_folder_search.xml
  96. 2
      app/src/main/res/drawable/icon_gitea.xml
  97. 2
      app/src/main/res/drawable/icon_github.xml
  98. 9
      app/src/main/res/drawable/icon_hidden.xml
  99. 5
      app/src/main/res/drawable/icon_high_quality.xml
  100. 5
      app/src/main/res/drawable/icon_image.xml
  101. Some files were not shown because too many files have changed in this diff Show More

3
.gitmodules vendored

@ -1,3 +1,6 @@
[submodule "app/libgocryptfs"]
path = app/libgocryptfs
url = https://forge.chapril.org/hardcoresushi/libgocryptfs.git
[submodule "libpdfviewer"]
path = libpdfviewer
url = https://forge.chapril.org/hardcoresushi/libpdfviewer.git

102
README.md

@ -8,7 +8,7 @@ It currently only works with [gocryptfs](https://github.com/rfjakob/gocryptfs) b
<img src="https://forge.chapril.org/hardcoresushi/DroidFS/raw/branch/master/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png" height="500">
</p>
# Disclamer
# Disclaimer
DroidFS is provided "as is", without any warranty of any kind.
It shouldn't be considered as an absolute safe way to store files.
DroidFS cannot protect you from screen recording apps, keyloggers, apk backdooring, compromised root accesses, memory dumps etc.
@ -42,13 +42,27 @@ It is strongly recommended to read the documentation of a feature before enablin
* Features requiring temporary writing of the plain file to disk (DroidFS internal storage). This file could be read by apps with root access or by physical access if your device is not encrypted.
# Download
You can download the latest version in the Releases section. All APKs from v1.3.0 are signed with my PGP key available on keyservers:
<a href="https://f-droid.org/packages/sushi.hardcore.droidfs">
<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on.png" height="75">
</a>
`gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 007F84120107191E` \
Fingerprint: `BD5621479E7B74D36A405BE8007F84120107191E` \
You can download DroidFS from [F-Droid](https://f-droid.org/packages/sushi.hardcore.droidfs) or from the "Releases" section in the repo.
APKs available here are signed with my PGP key available on keyservers:
`gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys AFE384344A45E13A` \
Fingerprint: `B64E FE86 CEE1 D054 F082 1711 AFE3 8434 4A45 E13A` \
Email: `Hardcore Sushi <hardcore.sushi@disroot.org>`
To verify APKs: `gpg --verify <ASC file> <APK file>`
To verify APKs, save the PGP-signed message to a file and run `gpg --verify <the file>`. __Don't install any APK if the verification fails !__
If the signature is valid, you can compare the SHA256 checksums with:
```
sha256sum <APK file>
```
__Don't install the APK if the checksums don't match!__
F-Droid APKs should be signed with the F-Droid key. More details [here](https://f-droid.org/docs/Release_Channels_and_Signing_Keys).
# Permissions
DroidFS need some permissions to work properly. Here is why:
@ -61,7 +75,10 @@ DroidFS need some permissions to work properly. Here is why:
Required to encrypt/decrypt password hashes using a fingerprint protected key.
</li>
<li><h4>Camera:</h4>
Needed to take photos directly from DroidFS to import them securely. You can deny this permission if you don't want to use it.
Needed to take photos & videos directly encrypted inside DroidFS. You can deny this permission if you don't want to use it.
</li>
<li><h4>Record audio:</h4>
Required if you want sound on video recorded with DroidFS.
</li>
</ul>
@ -71,59 +88,78 @@ DroidFS use some parts of the original gocryptfs code, which is designed to run
# Build
Most of the original gocryptfs code was used as is (written in Go) and compiled to native code. That's why you need [Go](https://golang.org) and the [Android Native Development Kit (NDK)](https://developer.android.com/ndk/) to build DroidFS from source.
#### Install Requirements
- [Android Studio](https://developer.android.com/studio/)
- [Android NDK and CMake](https://developer.android.com/studio/projects/install-ndk)
- [Go](https://golang.org/doc/install) (on debian: `$ sudo apt-get install golang-go`)
#### Download Sources
#### Install dependencies
On debian:
```
$ git clone https://github.com/hardcore-sushi/DroidFS.git
$ sudo apt-get install build-essential pkg-config libssl-dev
```
Download [libgocryptfs](https://forge.chapril.org/hardcoresushi/libgocryptfs):
Install [Go](https://golang.org/doc/install):
```
$ sudo apt-get install golang-go
```
You also need to install the Android SDK build tools and the [Android NDK](https://developer.android.com/studio/projects/install-ndk).
#### Download Sources
```
$ git clone --recurse-submodules https://github.com/hardcore-sushi/DroidFS.git
$ cd DroidFS
$ git submodule update --init
```
libgocryptfs needs OpenSSL:
[libgocryptfs](https://forge.chapril.org/hardcoresushi/libgocryptfs) needs OpenSSL:
```
$ cd app/libgocryptfs
$ wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz
$ wget https://www.openssl.org/source/openssl-1.1.1n.tar.gz
```
Verify OpenSSL signature:
```
$ wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz.asc
$ gpg --verify openssl-1.1.1k.tar.gz.asc openssl-1.1.1k.tar.gz
$ wget https://www.openssl.org/source/openssl-1.1.1n.tar.gz.asc
$ gpg --verify openssl-1.1.1n.tar.gz.asc openssl-1.1.1n.tar.gz
```
Continue **ONLY** if the signature is **VALID**.
```
$ tar -xvzf openssl-1.1.1k.tar.gz
$ tar -xvzf openssl-1.1.1n.tar.gz
```
#### Build
First, we need to install some dependencies:
DroidFS also need [FFmpeg](https://ffmpeg.org) to record encrypted video:
```
$ sudo apt-get install libcrypto++-dev libssl-dev pkg-config
$ cd app/ffmpeg
$ git clone --depth=1 https://git.ffmpeg.org/ffmpeg.git
```
And also Go dependencies:
#### Generate a keystore
APKs must be signed to be installed on an Android device. If you don't already have a keystore, you can generate one by running:
```
$ go get golang.org/x/sys/unix golang.org/x/sys/cpu golang.org/x/crypto/hkdf
$ keytool -genkey -keystore <output file> -alias <key alias> -keyalg EC -validity 10000
```
Then, retrieve your Android NDK installation path, usually someting like "/home/\<user\>/Android/SDK/ndk/\<NDK version\>". We can now build libgocryptfs:
#### Build
Retrieve your Android NDK installation path, usually something like "/home/\<user\>/Android/SDK/ndk/\<NDK version\>". Now you can build libgocryptfs:
```
$ cd DroidFS/app/libgocryptfs
$ env ANDROID_NDK_HOME="<your ndk path>" OPENSSL_PATH="./openssl-1.1.1k" ./build.sh
$ env ANDROID_NDK_HOME="<your ndk path>" OPENSSL_PATH="./openssl-1.1.1n" ./build.sh
```
Then, open the DroidFS project with Android Studio. \
If a device (virtual or physical) is connected, just click on "Run". \
If you want to generate a signed APK, you can follow this [post](https://stackoverflow.com/a/28938286).
Then FFmpeg:
```
$ cd app/ffmpeg
$ env ANDROID_NDK_HOME="<your ndk path>" ./build.sh ffmpeg
```
Finally, compile the app:
```
$ ./gradlew assembleRelease
```
If the build succeeds, you will find the unsigned APKs in `app/build/outputs/apk/release/`. You need to sign them in order to install the app:
```
$ apksigner sign --out droidfs.apk -v --ks <keystore> app/build/outputs/apk/release/<unsigned apk file>
```
Now you can install `droidfs.apk` on your device.
# Third party code
Thanks to these open source projects that DroidFS uses:
### Modified code:
- [gocryptfs](https://github.com/rfjakob/gocryptfs) to encrypt your data
- [libgocryptfs](https://forge.chapril.org/hardcoresushi/libgocryptfs) (forked from [gocryptfs](https://github.com/rfjakob/gocryptfs)) to encrypt your data
- [libpdfviewer](https://forge.chapril.org/hardcoresushi/libpdfviewer) (forked from [PdfViewer](https://github.com/GrapheneOS/PdfViewer)) to open PDF files
- [DoubleTapPlayerView](https://github.com/vkay94/DoubleTapPlayerView) to add double-click controls to the video player
### Borrowed code:
- [MaterialFiles](https://github.com/zhanghai/MaterialFiles) for kotlin natural sorting implementation
### Libraries:
- [Cyanea](https://github.com/jaredrummler/Cyanea) to customize UI
- [Glide](https://github.com/bumptech/glide/) to display pictures
- [ExoPlayer](https://github.com/google/ExoPlayer) to play media files

56
app/CMakeLists.txt

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.4.1)
cmake_minimum_required(VERSION 3.10)
add_library(
gocryptfs
@ -23,6 +23,56 @@ target_link_libraries(
gocryptfs
)
include_directories(
${PROJECT_SOURCE_DIR}/libgocryptfs/build/${ANDROID_ABI}/
add_library(
avformat
SHARED
IMPORTED
)
set_target_properties(
avformat
PROPERTIES IMPORTED_LOCATION
${PROJECT_SOURCE_DIR}/ffmpeg/build/${ANDROID_ABI}/libavformat/libavformat.so
)
add_library(
avcodec
SHARED
IMPORTED
)
set_target_properties(
avcodec
PROPERTIES IMPORTED_LOCATION
${PROJECT_SOURCE_DIR}/ffmpeg/build/${ANDROID_ABI}/libavcodec/libavcodec.so
)
add_library(
avutil
SHARED
IMPORTED
)
set_target_properties(
avutil
PROPERTIES IMPORTED_LOCATION
${PROJECT_SOURCE_DIR}/ffmpeg/build/${ANDROID_ABI}/libavutil/libavutil.so
)
add_library(
mux
SHARED
src/main/native/libmux.c
)
target_link_libraries(
mux
avformat
avcodec
avutil
)
include_directories(
${PROJECT_SOURCE_DIR}/libgocryptfs/build/${ANDROID_ABI}
${PROJECT_SOURCE_DIR}/ffmpeg/build/${ANDROID_ABI}
)

51
app/build.gradle

@ -2,9 +2,9 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 29
buildToolsVersion "30.0.3"
ndkVersion "21.4.7075529"
compileSdkVersion 31
buildToolsVersion "31"
ndkVersion "23.1.7779620"
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
@ -13,19 +13,22 @@ android {
defaultConfig {
applicationId "sushi.hardcore.droidfs"
minSdkVersion 21
//noinspection ExpiredTargetSdkVersion
targetSdkVersion 29
versionCode 14
versionName "1.5.0"
versionCode 27
versionName "1.10.1"
ndk {
abiFilters "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
}
}
splits {
abi {
enable true
universalApk true
if (!file("fdroid").exists()) {
splits {
abi {
enable true
universalApk true
}
}
}
@ -53,27 +56,29 @@ android {
}
dependencies {
implementation project(":libpdfviewer:app")
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "androidx.core:core-ktx:1.5.0"
implementation "androidx.appcompat:appcompat:1.3.0"
implementation "androidx.constraintlayout:constraintlayout:2.0.4"
implementation 'androidx.core:core-ktx:1.7.0'
implementation "androidx.appcompat:appcompat:1.4.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.3"
implementation "androidx.sqlite:sqlite-ktx:2.1.0"
implementation "androidx.preference:preference-ktx:1.1.1"
implementation "androidx.sqlite:sqlite-ktx:2.2.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
implementation "com.jaredrummler:cyanea:1.0.2"
implementation 'com.google.android.material:material:1.5.0'
implementation "com.github.bumptech.glide:glide:4.12.0"
implementation "androidx.biometric:biometric:1.1.0"
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
def exoplayer_version = "2.14.1"
def exoplayer_version = "2.17.1"
implementation "com.google.android.exoplayer:exoplayer-core:$exoplayer_version"
implementation "com.google.android.exoplayer:exoplayer-ui:$exoplayer_version"
def camerax_v1 = "1.1.0-alpha05"
implementation "androidx.camera:camera-camera2:$camerax_v1"
implementation "androidx.camera:camera-lifecycle:$camerax_v1"
def camerax_v2 = "1.0.0-alpha25"
implementation "androidx.camera:camera-view:$camerax_v2"
implementation "androidx.camera:camera-extensions:$camerax_v2"
implementation "androidx.concurrent:concurrent-futures:1.1.0"
def camerax_version = "1.1.0-beta03"
implementation "androidx.camera:camera-camera2:$camerax_version"
implementation "androidx.camera:camera-lifecycle:$camerax_version"
implementation "androidx.camera:camera-view:$camerax_version"
implementation "androidx.camera:camera-extensions:$camerax_version"
}

2
app/ffmpeg/.gitignore vendored

@ -0,0 +1,2 @@
ffmpeg
build

94
app/ffmpeg/build.sh

@ -0,0 +1,94 @@
#!/bin/bash
if [ -z ${ANDROID_NDK_HOME+x} ]; then
echo "Error: \$ANDROID_NDK_HOME is not defined." >&2
exit 1
elif [ $# -lt 1 ]; then
echo "Usage: $0 <FFmpeg source directory> [<ABI>]" >&2
exit 1
else
FFMPEG_DIR=$1
compile_for_arch() {
echo "Compiling for $1..."
case $1 in
"x86_64")
CFN="x86_64-linux-android21-clang"
ARCH="x86_64"
;;
"x86")
CFN="i686-linux-android21-clang"
ARCH="i686"
EXTRA_FLAGS="--disable-asm"
;;
"arm64-v8a")
CFN="aarch64-linux-android21-clang"
ARCH="aarch64"
;;
"armeabi-v7a")
CFN="armv7a-linux-androideabi19-clang"
ARCH="arm"
;;
esac
(cd $FFMPEG_DIR && make clean;
./configure \
--cc="$CFN" \
--cxx="$CFN++" \
--arch="$ARCH" \
$EXTRA_FLAGS \
--target-os=android \
--enable-cross-compile \
--enable-version3 \
--disable-programs \
--disable-static \
--enable-shared \
--disable-bsfs \
--disable-parsers \
--disable-demuxers \
--disable-muxers \
--enable-muxer="mp4" \
--disable-decoders \
--disable-encoders \
--enable-encoder="aac" \
--disable-avdevice \
--disable-swresample \
--disable-swscale \
--disable-postproc \
--disable-avfilter \
--disable-network \
--disable-doc \
--disable-htmlpages \
--disable-manpages \
--disable-podpages \
--disable-txtpages \
--disable-sndio \
--disable-schannel \
--disable-securetransport \
--disable-xlib \
--disable-zlib \
--disable-cuvid \
--disable-nvenc \
--disable-vdpau \
--disable-videotoolbox \
--disable-audiotoolbox \
--disable-appkit \
--disable-alsa \
--disable-debug \
>/dev/null &&
make -j $(nproc --all) >/dev/null) &&
mkdir -p build/$1/libavformat build/$1/libavcodec build/$1/libavutil &&
cp $FFMPEG_DIR/libavformat/*.h $FFMPEG_DIR/libavformat/libavformat.so build/$1/libavformat &&
cp $FFMPEG_DIR/libavcodec/*.h $FFMPEG_DIR/libavcodec/libavcodec.so build/$1/libavcodec &&
cp $FFMPEG_DIR/libavutil/*.h $FFMPEG_DIR/libavutil/libavutil.so build/$1/libavutil ||
exit 1
}
export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH
if [ $# -eq 2 ]; then
compile_for_arch $2
else
declare -a ABIs=("x86_64" "x86" "arm64-v8a" "armeabi-v7a")
for abi in ${ABIs[@]}; do
compile_for_arch $abi
done
fi
fi

2
app/libgocryptfs

@ -1 +1 @@
Subproject commit 847d4fa7817c84fe1b78726f031172ea508dab19
Subproject commit 9e98192442b08362660b45f4e2e50221ba7bc65b

12
app/proguard-rules.pro vendored

@ -20,8 +20,12 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepattributes InnerClasses
-keep class sushi.hardcore.droidfs.SettingsActivity$** {
*;
-keep class sushi.hardcore.droidfs.SettingsActivity$**
-keep class sushi.hardcore.droidfs.explorers.ExplorerElement
-keepclassmembers class sushi.hardcore.droidfs.explorers.ExplorerElement {
static sushi.hardcore.droidfs.explorers.ExplorerElement new(...);
}
-keep class sushi.hardcore.droidfs.explorers.ExplorerElement
-keepclassmembers class sushi.hardcore.droidfs.video_recording.MediaMuxer {
void writePacket(byte[]);
void seek(long);
}

68
app/src/main/AndroidManifest.xml

@ -11,6 +11,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature
android:name="android.hardware.camera.any"
@ -24,67 +25,36 @@
tools:node="remove" /> <!--removing this permission automatically added by exoplayer-->
<application
android:name=".ColoredApplication"
android:allowBackup="false"
android:icon="@mipmap/icon_launcher"
android:label="@string/app_name"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".CameraActivity"
android:screenOrientation="nosensor" />
<activity
android:name=".SettingsActivity"
android:label="@string/title_activity_settings"
android:parentActivityName=".MainActivity" />
<activity android:name=".explorers.ExplorerActivity" />
<activity android:name=".explorers.ExplorerActivityPick" />
<activity android:name=".explorers.ExplorerActivityDrop" />
<activity
android:name=".OpenActivity"
android:parentActivityName=".MainActivity"
android:screenOrientation="nosensor"
android:windowSoftInputMode="adjustPan">
android:theme="@style/BaseTheme">
<activity android:name=".MainActivity" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter android:label="@string/share_menu_label">
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<activity
android:name=".CreateActivity"
android:parentActivityName=".MainActivity"
android:screenOrientation="nosensor" />
<activity
android:name=".ChangePasswordActivity"
android:parentActivityName=".MainActivity"
android:screenOrientation="nosensor"
android:windowSoftInputMode="adjustPan" />
<activity
android:name=".MainActivity"
android:screenOrientation="nosensor">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".file_viewers.ImageViewer"
android:configChanges="screenSize|orientation" /> <!-- don't reload content on configuration change -->
<activity
android:name=".file_viewers.VideoPlayer"
android:configChanges="screenSize|orientation" />
<activity
android:name=".file_viewers.AudioPlayer"
android:configChanges="screenSize|orientation" />
<activity
android:name=".file_viewers.TextEditor"
android:configChanges="screenSize|orientation" />
<activity android:name=".SettingsActivity" android:label="@string/title_activity_settings"/>
<activity android:name=".add_volume.AddVolumeActivity" android:windowSoftInputMode="adjustResize"/>
<activity android:name=".ChangePasswordActivity" android:windowSoftInputMode="adjustResize"/>
<activity android:name=".explorers.ExplorerActivity"/>
<activity android:name=".explorers.ExplorerActivityPick"/>
<activity android:name=".explorers.ExplorerActivityDrop"/>
<activity android:name=".file_viewers.ImageViewer" android:configChanges="screenSize|orientation" /> <!-- don't reload content on configuration change -->
<activity android:name=".file_viewers.VideoPlayer" android:configChanges="screenSize|orientation" />
<activity android:name=".file_viewers.PdfViewer" android:configChanges="screenSize|orientation" />
<activity android:name=".file_viewers.AudioPlayer" android:configChanges="screenSize|orientation" />
<activity android:name=".file_viewers.TextEditor" android:configChanges="screenSize|orientation" />
<activity android:name=".CameraActivity" android:screenOrientation="nosensor" />
<service android:name=".file_operations.FileOperationService" android:exported="false"/>

57
app/src/main/java/sushi/hardcore/droidfs/BaseActivity.kt

@ -3,36 +3,51 @@ package sushi.hardcore.droidfs
import android.content.SharedPreferences
import android.os.Bundle
import android.view.WindowManager
import androidx.core.content.ContextCompat
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager
import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity
import sushi.hardcore.droidfs.widgets.ThemeColor
open class BaseActivity: CyaneaAppCompatActivity() {
open class BaseActivity: AppCompatActivity() {
protected lateinit var sharedPrefs: SharedPreferences
protected var isRecreating = false
lateinit var themeValue: String
private var shouldCheckTheme = true
override fun onCreate(savedInstanceState: Bundle?) {
val themeColor = ThemeColor.getThemeColor(this)
if (cyanea.accent != themeColor){
changeThemeColor(themeColor)
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
if (shouldCheckTheme) {
themeValue = sharedPrefs.getString("theme", ConstValues.DEFAULT_THEME_VALUE)!!
when (themeValue) {
"black_green" -> setTheme(R.style.BlackGreen)
"dark_red" -> setTheme(R.style.DarkRed)
"black_red" -> setTheme(R.style.BlackRed)
"dark_blue" -> setTheme(R.style.DarkBlue)
"black_blue" -> setTheme(R.style.BlackBlue)
"dark_yellow" -> setTheme(R.style.DarkYellow)
"black_yellow" -> setTheme(R.style.BlackYellow)
"dark_orange" -> setTheme(R.style.DarkOrange)
"black_orange" -> setTheme(R.style.BlackOrange)
"dark_purple" -> setTheme(R.style.DarkPurple)
"black_purple" -> setTheme(R.style.BlackPurple)
}
} else {
shouldCheckTheme = true
}
super.onCreate(savedInstanceState)
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
if (!sharedPrefs.getBoolean("usf_screenshot", false)){
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE)
}
}
fun changeThemeColor(themeColor: Int? = null){
val accentColor = themeColor ?: ThemeColor.getThemeColor(this)
val backgroundColor = ContextCompat.getColor(this, R.color.backgroundColor)
isRecreating = true
cyanea.edit{
accent(accentColor)
//accentDark(themeColor)
//accentLight(themeColor)
background(backgroundColor)
//backgroundDark(backgroundColor)
//backgroundLight(backgroundColor)
}.recreate(this)
override fun onStart() {
super.onStart()
val newThemeValue = sharedPrefs.getString("theme", "dark_green")!!
onThemeChanged(newThemeValue)
}
fun onThemeChanged(newThemeValue: String) {
if (newThemeValue != themeValue) {
themeValue = newThemeValue
shouldCheckTheme = false
recreate()
}
}
}

484
app/src/main/java/sushi/hardcore/droidfs/CameraActivity.kt

@ -1,6 +1,7 @@
package sushi.hardcore.droidfs
import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.PackageManager
import android.hardware.camera2.CameraCharacteristics
@ -8,39 +9,42 @@ import android.hardware.camera2.CameraManager
import android.os.Build
import android.os.Bundle
import android.text.InputType
import android.util.DisplayMetrics
import android.util.Size
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.view.WindowManager
import android.view.*
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.RotateAnimation
import android.widget.EditText
import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.camera.camera2.interop.Camera2CameraInfo
import androidx.camera.core.*
import androidx.camera.extensions.HdrImageCaptureExtender
import androidx.camera.extensions.ExtensionMode
import androidx.camera.extensions.ExtensionsManager
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import sushi.hardcore.droidfs.adapters.DialogSingleChoiceAdapter
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import sushi.hardcore.droidfs.content_providers.RestrictedFileProvider
import sushi.hardcore.droidfs.databinding.ActivityCameraBinding
import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ColoredAlertDialogBuilder
import sushi.hardcore.droidfs.video_recording.SeekableWriter
import sushi.hardcore.droidfs.video_recording.VideoCapture
import sushi.hardcore.droidfs.widgets.CustomAlertDialogBuilder
import sushi.hardcore.droidfs.widgets.EditTextDialog
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.Executor
class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
companion object {
private const val CAMERA_PERMISSION_REQUEST_CODE = 1
private const val CAMERA_PERMISSION_REQUEST_CODE = 0
private const val AUDIO_PERMISSION_REQUEST_CODE = 1
private const val fileNameRandomMin = 100000
private const val fileNameRandomMax = 999999
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US)
@ -62,13 +66,25 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
private lateinit var orientedIcons: List<ImageView>
private lateinit var gocryptfsVolume: GocryptfsVolume
private lateinit var outputDirectory: String
private lateinit var fileName: String
private var isFinishingIntentionally = false
private lateinit var cameraExecutor: ExecutorService
private var isAskingPermissions = false
private var permissionsGranted = false
private lateinit var executor: Executor
private lateinit var cameraProvider: ProcessCameraProvider
private lateinit var extensionsManager: ExtensionsManager
private lateinit var cameraSelector: CameraSelector
private val cameraPreview = Preview.Builder().build()
private var imageCapture: ImageCapture? = null
private var resolutions: Array<Size>? = null
private var videoCapture: VideoCapture? = null
private var camera: Camera? = null
private var resolutions: List<Size>? = null
private var currentResolutionIndex: Int = 0
private var currentResolution: Size? = null
private var captureMode = ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
private var isBackCamera = true
private var isInVideoMode = false
private var isRecording = false
private var isWaitingForTimer = false
private lateinit var binding: ActivityCameraBinding
override fun onCreate(savedInstanceState: Bundle?) {
@ -76,97 +92,173 @@ class CameraActivity : BaseActivity(), SensorOrientationListener.Listener {
usf_keep_open = sharedPrefs.getBoolean("usf_keep_open", false)
binding = ActivityCameraBinding.inflate(layoutInflater)
setContentView(binding.root)
gocryptfsVolume = GocryptfsVolume(intent.getIntExtra("sessionID", -1))
supportActionBar?.hide()
gocryptfsVolume = GocryptfsVolume(applicationContext, intent.getIntExtra("sessionID", -1))
outputDirectory = intent.getStringExtra("path")!!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED){
setupCamera()
permissionsGranted = true
} else {
isAskingPermissions = true
requestPermissions(arrayOf(Manifest.permission.CAMERA), CAMERA_PERMISSION_REQUEST_CODE)
}
} else {
setupCamera()
permissionsGranted = true
}
cameraExecutor = Executors.newSingleThreadExecutor()
executor = ContextCompat.getMainExecutor(this)
cameraPreview.setSurfaceProvider(binding.cameraPreview.surfaceProvider)
ProcessCameraProvider.getInstance(this).apply {
addListener({
cameraProvider = get()
ExtensionsManager.getInstanceAsync(this@CameraActivity, cameraProvider).apply {
addListener({
extensionsManager = get()
setupCamera()
}, executor)
}
}, executor)
}
binding.imageCaptureMode.setOnClickListener {
val currentIndex = if (captureMode == ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) {
0
} else {
1
}
CustomAlertDialogBuilder(this, themeValue)
.setTitle(R.string.camera_optimization)
.setSingleChoiceItems(arrayOf(getString(R.string.maximize_quality), getString(R.string.minimize_latency)), currentIndex) { dialog, which ->
val resId: Int
val newCaptureMode = if (which == 0) {
resId = R.drawable.icon_high_quality
ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY
} else {
resId = R.drawable.icon_speed
ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY
}
if (newCaptureMode != captureMode) {
captureMode = newCaptureMode
binding.imageCaptureMode.setImageResource(resId)
if (!isInVideoMode) {
cameraProvider.unbind(imageCapture)
refreshImageCapture()
cameraProvider.bindToLifecycle(this, cameraSelector, imageCapture)
}
}
dialog.dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
binding.imageRatio.setOnClickListener {
resolutions?.let {
ColoredAlertDialogBuilder(this)
CustomAlertDialogBuilder(this, themeValue)
.setTitle(R.string.choose_resolution)
.setSingleChoiceItems(DialogSingleChoiceAdapter(this, it.map { size -> size.toString() }.toTypedArray()), currentResolutionIndex) { dialog, which ->
setupCamera(resolutions!![which])
dialog.dismiss()
.setSingleChoiceItems(it.map { size -> size.toString() }.toTypedArray(), currentResolutionIndex) { dialog, which ->
currentResolution = resolutions!![which]
currentResolutionIndex = which
setupCamera()
dialog.dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
}
binding.imageTimer.setOnClickListener {
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER
val dialog = ColoredAlertDialogBuilder(this)
.setView(dialogEditTextView)
.setTitle(getString(R.string.enter_timer_duration))
.setPositiveButton(R.string.ok) { _, _ ->
val enteredValue = dialogEditText.text.toString()
if (enteredValue.isEmpty()){
Toast.makeText(this, getString(R.string.timer_empty_error_msg), Toast.LENGTH_SHORT).show()
} else {
timerDuration = enteredValue.toInt()
}
with (EditTextDialog(this, R.string.enter_timer_duration) {
try {
timerDuration = it.toInt()
} catch (e: NumberFormatException) {
Toast.makeText(this, R.string.invalid_number, Toast.LENGTH_SHORT).show()
}