From 0bc5673e825deef99cacbfe274fb5d91caee7cc3 Mon Sep 17 00:00:00 2001 From: Andrii Chubko Date: Fri, 27 Aug 2021 13:08:02 +0100 Subject: [PATCH 01/12] Remove unnecessary permission --- app/src/main/AndroidManifest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 56d144c8..5242cbe4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,8 +11,6 @@ android:name="android.hardware.faketouch" android:required="false" /> - - Date: Fri, 27 Aug 2021 13:08:22 +0100 Subject: [PATCH 02/12] Update commons library version --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 67870bf0..ff0cb43f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:dc3f4b619e' + implementation 'com.github.SimpleMobileTools:Simple-Commons:8979ca8187' implementation 'androidx.constraintlayout:constraintlayout:2.1.0' implementation 'androidx.documentfile:documentfile:1.0.1' From a2faa7107f23bb1c7ff38ae2ecff8c3c3dca3030 Mon Sep 17 00:00:00 2001 From: Andrii Chubko Date: Fri, 27 Aug 2021 16:38:59 +0300 Subject: [PATCH 03/12] Remove note protection if biometric id is no longer available This check is done to avoid user not being able to unlock the note if he removes biometric id from phone settings. --- .../notes/pro/activities/MainActivity.kt | 27 +++++++++++-------- .../pro/activities/WidgetConfigureActivity.kt | 20 +++++++------- .../notes/pro/fragments/ChecklistFragment.kt | 14 ++++++---- .../notes/pro/fragments/TextFragment.kt | 26 +++++++++++------- .../notes/pro/models/Note.kt | 9 ++++++- 5 files changed, 60 insertions(+), 36 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt index dd42450e..a6644313 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt @@ -316,8 +316,11 @@ class MainActivity : SimpleActivity() { } private fun initViewPager(wantedNoteId: Long? = null) { - NotesHelper(this).getNotes { - mNotes = it + NotesHelper(this).getNotes { notes -> + notes.filter { it.isBiometricLockUnavailable(this) } + .forEach(::removeProtection) + + mNotes = notes invalidateOptionsMenu() mCurrentNote = mNotes[0] mAdapter = NotesPagerAdapter(supportFragmentManager, mNotes, this) @@ -1084,19 +1087,21 @@ class MainActivity : SimpleActivity() { performSecurityCheck( protectionType = mCurrentNote.protectionType, requiredHash = mCurrentNote.protectionHash, - successCallback = { _, _ -> removeProtection() } + successCallback = { _, _ -> removeProtection(mCurrentNote) } ) } - private fun removeProtection() { - mCurrentNote.protectionHash = "" - mCurrentNote.protectionType = PROTECTION_NONE - NotesHelper(this).insertOrUpdateNote(mCurrentNote) { - getCurrentFragment()?.apply { - shouldShowLockedContent = true - checkLockState() + private fun removeProtection(note: Note) { + note.protectionHash = "" + note.protectionType = PROTECTION_NONE + NotesHelper(this).insertOrUpdateNote(note) { + if (note == mCurrentNote) { + getCurrentFragment()?.apply { + shouldShowLockedContent = true + checkLockState() + } + invalidateOptionsMenu() } - invalidateOptionsMenu() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt index 3e88f15a..6d46dad2 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt @@ -104,16 +104,18 @@ class WidgetConfigureActivity : SimpleActivity() { if (mNotes.size == 1 && note == null) { note = mNotes.first() - performSecurityCheck( - protectionType = note.protectionType, - requiredHash = note.protectionHash, - successCallback = { _, _ -> updateCurrentNote(note) }, - failureCallback = { finish() } - ) - } else { - if (note != null) { + if (note.isBiometricLockUnavailable(this)) { updateCurrentNote(note) + } else { + performSecurityCheck( + protectionType = note.protectionType, + requiredHash = note.protectionHash, + successCallback = { _, _ -> updateCurrentNote(note) }, + failureCallback = { finish() } + ) } + } else if (note != null) { + updateCurrentNote(note) } } } @@ -127,7 +129,7 @@ class WidgetConfigureActivity : SimpleActivity() { RadioGroupDialog(this, items, mCurrentNoteId.toInt()) { val selectedId = it as Int val note = mNotes.firstOrNull { it.id!!.toInt() == selectedId } ?: return@RadioGroupDialog - if (note.protectionType == PROTECTION_NONE) { + if (note.protectionType == PROTECTION_NONE || note.isBiometricLockUnavailable(this)) { updateCurrentNote(note) } else { performSecurityCheck( diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt index 86b7aed5..7506c0c0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt @@ -78,11 +78,13 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener { items.clear() note.value.split("\n").map { it.trim() }.filter { it.isNotBlank() }.forEachIndexed { index, value -> - items.add(ChecklistItem( - id = index, - title = value, - isDone = false - )) + items.add( + ChecklistItem( + id = index, + title = value, + isDone = false + ) + ) } saveChecklist() @@ -120,6 +122,8 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener { } override fun checkLockState() { + if (note == null) return + view.apply { checklist_content_holder.beVisibleIf(!note!!.isLocked() || shouldShowLockedContent) checklist_fab.beVisibleIf(!note!!.isLocked() || shouldShowLockedContent) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt index 3cf5991f..7d280cfd 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt @@ -176,6 +176,8 @@ class TextFragment : NoteFragment() { fun removeTextWatcher() = view.text_note_view.removeTextChangedListener(textWatcher) override fun checkLockState() { + if (note == null) return + view.apply { notes_counter.beVisibleIf((!note!!.isLocked() || shouldShowLockedContent) && config!!.showWordCount) notes_scrollview.beVisibleIf(!note!!.isLocked() || shouldShowLockedContent) @@ -263,11 +265,13 @@ class TextFragment : NoteFragment() { text.removeSpan(span) } - Selection.setSelection(text, if (edit.before == null) { - start - } else { - start + edit.before.length - }) + Selection.setSelection( + text, if (edit.before == null) { + start + } else { + start + edit.before.length + } + ) } fun redo() { @@ -285,11 +289,13 @@ class TextFragment : NoteFragment() { text.removeSpan(o) } - Selection.setSelection(text, if (edit.after == null) { - start - } else { - start + edit.after.length - }) + Selection.setSelection( + text, if (edit.after == null) { + start + } else { + start + edit.after.length + } + ) } fun isUndoAvailable() = textHistory.position > 0 diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt index f9dae3dc..37697816 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt @@ -6,6 +6,8 @@ import androidx.room.ColumnInfo import androidx.room.Entity import androidx.room.Index import androidx.room.PrimaryKey +import com.simplemobiletools.commons.extensions.isBiometricIdAvailable +import com.simplemobiletools.commons.helpers.PROTECTION_FINGERPRINT import com.simplemobiletools.commons.helpers.PROTECTION_NONE import java.io.File @@ -17,7 +19,8 @@ data class Note( @ColumnInfo(name = "type") var type: Int, @ColumnInfo(name = "path") var path: String, @ColumnInfo(name = "protection_type") var protectionType: Int, - @ColumnInfo(name = "protection_hash") var protectionHash: String) { + @ColumnInfo(name = "protection_hash") var protectionHash: String +) { fun getNoteStoredValue(context: Context): String? { return if (path.isNotEmpty()) { @@ -37,4 +40,8 @@ data class Note( } fun isLocked() = protectionType != PROTECTION_NONE + + fun isBiometricLockUnavailable(context: Context): Boolean { + return protectionType == PROTECTION_FINGERPRINT && !context.isBiometricIdAvailable() + } } From 5e5576a0e09e746bbbce7b8f465da7cf65d110ee Mon Sep 17 00:00:00 2001 From: Andrii Chubko Date: Fri, 27 Aug 2021 20:24:36 +0300 Subject: [PATCH 04/12] Remove one-line if expressions --- .../notes/pro/fragments/ChecklistFragment.kt | 4 +++- .../com/simplemobiletools/notes/pro/fragments/TextFragment.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt index 7506c0c0..06248352 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/ChecklistFragment.kt @@ -122,7 +122,9 @@ class ChecklistFragment : NoteFragment(), ChecklistItemsListener { } override fun checkLockState() { - if (note == null) return + if (note == null) { + return + } view.apply { checklist_content_holder.beVisibleIf(!note!!.isLocked() || shouldShowLockedContent) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt index 7d280cfd..a53b293d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/fragments/TextFragment.kt @@ -176,7 +176,9 @@ class TextFragment : NoteFragment() { fun removeTextWatcher() = view.text_note_view.removeTextChangedListener(textWatcher) override fun checkLockState() { - if (note == null) return + if (note == null) { + return + } view.apply { notes_counter.beVisibleIf((!note!!.isLocked() || shouldShowLockedContent) && config!!.showWordCount) From ff7e114264d339bf4d7e308e7f5383194c172e40 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 8 Sep 2021 09:53:04 +0200 Subject: [PATCH 05/12] Update Note.kt --- .../main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt index 37697816..7a5170b7 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/models/Note.kt @@ -41,7 +41,7 @@ data class Note( fun isLocked() = protectionType != PROTECTION_NONE - fun isBiometricLockUnavailable(context: Context): Boolean { + fun shouldBeUnlocked(context: Context): Boolean { return protectionType == PROTECTION_FINGERPRINT && !context.isBiometricIdAvailable() } } From 99abbdabcc3060c0e442a7abb499c6da68b3d909 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 8 Sep 2021 09:53:22 +0200 Subject: [PATCH 06/12] Update MainActivity.kt --- .../com/simplemobiletools/notes/pro/activities/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt index a6644313..752ece6f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt @@ -317,7 +317,7 @@ class MainActivity : SimpleActivity() { private fun initViewPager(wantedNoteId: Long? = null) { NotesHelper(this).getNotes { notes -> - notes.filter { it.isBiometricLockUnavailable(this) } + notes.filter { it.shouldBeUnlocked(this) } .forEach(::removeProtection) mNotes = notes From e099ba62a66affa8b44a7a52f633868239b6a012 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Wed, 8 Sep 2021 09:53:38 +0200 Subject: [PATCH 07/12] Update WidgetConfigureActivity.kt --- .../notes/pro/activities/WidgetConfigureActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt index 6d46dad2..be3f203f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/WidgetConfigureActivity.kt @@ -104,7 +104,7 @@ class WidgetConfigureActivity : SimpleActivity() { if (mNotes.size == 1 && note == null) { note = mNotes.first() - if (note.isBiometricLockUnavailable(this)) { + if (note.shouldBeUnlocked(this)) { updateCurrentNote(note) } else { performSecurityCheck( @@ -129,7 +129,7 @@ class WidgetConfigureActivity : SimpleActivity() { RadioGroupDialog(this, items, mCurrentNoteId.toInt()) { val selectedId = it as Int val note = mNotes.firstOrNull { it.id!!.toInt() == selectedId } ?: return@RadioGroupDialog - if (note.protectionType == PROTECTION_NONE || note.isBiometricLockUnavailable(this)) { + if (note.protectionType == PROTECTION_NONE || note.shouldBeUnlocked(this)) { updateCurrentNote(note) } else { performSecurityCheck( From cbba53b7984215f1bdff8b747705b49dbe939a2e Mon Sep 17 00:00:00 2001 From: Andrii Chubko Date: Mon, 13 Sep 2021 05:07:56 +0300 Subject: [PATCH 08/12] Fix error when exporting notes to Google Drive Use "rwt" mode instead of "wt" as the "wt" seems to not work with Google Drive. See this: https://github.com/itinance/react-native-fs/pull/837#issuecomment-776677509 --- .../com/simplemobiletools/notes/pro/activities/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt index 752ece6f..f8ea9629 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt @@ -880,7 +880,7 @@ class MainActivity : SimpleActivity() { private fun exportNoteValueToUri(uri: Uri, content: String, callback: ((success: Boolean) -> Unit)? = null) { try { - val outputStream = contentResolver.openOutputStream(uri, "wt") + val outputStream = contentResolver.openOutputStream(uri, "rwt") outputStream!!.bufferedWriter().use { out -> out.write(content) } From ab0d7a5666920fee31d08c24c468d0d26acc4aff Mon Sep 17 00:00:00 2001 From: Andrii Chubko Date: Mon, 13 Sep 2021 05:18:45 +0300 Subject: [PATCH 09/12] Don't update note info if export failed --- .../notes/pro/activities/MainActivity.kt | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt index f8ea9629..f6618754 100644 --- a/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/notes/pro/activities/MainActivity.kt @@ -750,17 +750,19 @@ class MainActivity : SimpleActivity() { RadioGroupDialog(this, items) { val syncFile = it as Int == EXPORT_FILE_SYNC - tryExportNoteValueToFile(exportPath, textToExport, true) { - if (syncFile) { - mCurrentNote.path = exportPath - mCurrentNote.value = "" - } else { - mCurrentNote.path = "" - mCurrentNote.value = textToExport - } + tryExportNoteValueToFile(exportPath, textToExport, true) { exportedSuccessfully -> + if (exportedSuccessfully) { + if (syncFile) { + mCurrentNote.path = exportPath + mCurrentNote.value = "" + } else { + mCurrentNote.path = "" + mCurrentNote.value = textToExport + } - getPagerAdapter().updateCurrentNoteData(view_pager.currentItem, mCurrentNote.path, mCurrentNote.value) - NotesHelper(this).insertOrUpdateNote(mCurrentNote) + getPagerAdapter().updateCurrentNoteData(view_pager.currentItem, mCurrentNote.path, mCurrentNote.value) + NotesHelper(this).insertOrUpdateNote(mCurrentNote) + } } } } @@ -792,23 +794,26 @@ class MainActivity : SimpleActivity() { toast(String.format(getString(R.string.filename_invalid_characters_placeholder, filename))) } else { val noteStoredValue = note.getNoteStoredValue(this) ?: "" - tryExportNoteValueToFile(file.absolutePath, note.value, false) { - if (syncFile) { - note.path = file.absolutePath - note.value = "" - } else { - note.path = "" - note.value = noteStoredValue + tryExportNoteValueToFile(file.absolutePath, note.value, false) { exportedSuccessfully -> + if (exportedSuccessfully) { + if (syncFile) { + note.path = file.absolutePath + note.value = "" + } else { + note.path = "" + note.value = noteStoredValue + } + + NotesHelper(this).insertOrUpdateNote(note) } - NotesHelper(this).insertOrUpdateNote(note) if (mCurrentNote.id == note.id) { mCurrentNote.value = note.value mCurrentNote.path = note.path getPagerAdapter().updateCurrentNoteData(view_pager.currentItem, mCurrentNote.path, mCurrentNote.value) } - if (!it) { + if (!exportedSuccessfully) { failCount++ } From 9a53d8aca4d3fb3b1e2efcbf85d5f3f6d816d00b Mon Sep 17 00:00:00 2001 From: tibbi Date: Mon, 13 Sep 2021 21:18:58 +0200 Subject: [PATCH 10/12] updating commons --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index ff0cb43f..ae8d07b8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ android { } dependencies { - implementation 'com.github.SimpleMobileTools:Simple-Commons:8979ca8187' + implementation 'com.github.SimpleMobileTools:Simple-Commons:7c0a8d628e' implementation 'androidx.constraintlayout:constraintlayout:2.1.0' implementation 'androidx.documentfile:documentfile:1.0.1' From 4f33b6482cd4c6fee335928ecd3db2355e031395 Mon Sep 17 00:00:00 2001 From: tibbi Date: Mon, 13 Sep 2021 21:28:15 +0200 Subject: [PATCH 11/12] update version to 6.8.2 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index ae8d07b8..c2d099ea 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "com.simplemobiletools.notes.pro" minSdkVersion 21 targetSdkVersion 30 - versionCode 84 - versionName "6.8.1" + versionCode 85 + versionName "6.8.2" setProperty("archivesBaseName", "notes") } From dd70cfe9a9be1a01eb96f37baccd254bc266f09f Mon Sep 17 00:00:00 2001 From: tibbi Date: Mon, 13 Sep 2021 21:28:22 +0200 Subject: [PATCH 12/12] updating changelog --- CHANGELOG.md | 6 ++++++ fastlane/metadata/android/en-US/changelogs/85.txt | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/85.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 141a1886..1fa864f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ Changelog ========== +Version 6.8.2 *(2021-09-13)* +---------------------------- + + * Added biometric protection on Android 11+ + * Fixed a glitch with note content vanishing on export error + Version 6.8.1 *(2021-08-23)* ---------------------------- diff --git a/fastlane/metadata/android/en-US/changelogs/85.txt b/fastlane/metadata/android/en-US/changelogs/85.txt new file mode 100644 index 00000000..891be4ea --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/85.txt @@ -0,0 +1,2 @@ + * Added biometric protection on Android 11+ + * Fixed a glitch with note content vanishing on export error