Skip to content

Commit

Permalink
Fix export permissions for API >= 33
Browse files Browse the repository at this point in the history
Fixes #154
  • Loading branch information
udenr committed Dec 20, 2023
1 parent f3269b0 commit 3414cdc
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 208 deletions.
35 changes: 17 additions & 18 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,38 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

<application
android:name="NotesApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name="NotesApplication"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
tools:node="remove">
</provider>
tools:node="remove" />

<activity
android:name=".ui.SplashActivity"
android:theme="@style/SplashTheme"
android:exported="true">
android:exported="true"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".ui.main.MainActivity"
android:theme="@style/AppTheme.NoActionBar">
</activity>
android:theme="@style/AppTheme.NoActionBar" />
<activity
android:name=".ui.notes.TextNoteActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
Expand All @@ -61,18 +58,19 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/title_audionote"
android:parentActivityName=".ui.main.MainActivity" />
<activity android:name=".ui.notes.SketchActivity"
<activity
android:name=".ui.notes.SketchActivity"
android:label="@string/title_sketchnote"
android:parentActivityName=".ui.main.MainActivity"
android:screenOrientation="portrait"/>
android:screenOrientation="portrait" />
<activity
android:name=".ui.SettingsActivity"
android:parentActivityName=".ui.main.MainActivity"
android:label="@string/title_settings"/>
android:label="@string/title_settings"
android:parentActivityName=".ui.main.MainActivity" />
<activity
android:name=".ui.HelpActivity"
android:parentActivityName=".ui.main.MainActivity"
android:label="@string/title_help" />
android:label="@string/title_help"
android:parentActivityName=".ui.main.MainActivity" />
<activity
android:name=".ui.AboutActivity"
android:label="@string/title_about"
Expand All @@ -81,12 +79,13 @@
android:name=".ui.TutorialActivity"
android:label="@string/title_tutorial"
android:parentActivityName=".ui.main.MainActivity"
android:theme="@style/AppTheme.NoActionBar"/>
android:theme="@style/AppTheme.NoActionBar" />


<service android:name=".service.NotificationService" />

<receiver android:name=".receiver.NotificationEventsReceiver"
<receiver
android:name=".receiver.NotificationEventsReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import android.content.pm.PackageManager
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.MediaRecorder
import android.media.MediaScannerConnection
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.util.Log
Expand All @@ -31,7 +31,6 @@ import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
Expand All @@ -40,17 +39,16 @@ import org.secuso.privacyfriendlynotes.room.DbContract
import org.secuso.privacyfriendlynotes.room.model.Note
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.nio.channels.FileChannel
import java.io.OutputStream

/**
* Activity that allows to add, edit and delete audio notes.
*/
class AudioNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_AUDIO) {
private val btnPlayPause: ImageButton by lazy { findViewById(R.id.btn_play_pause) }
private val btnRecord: ImageButton by lazy { findViewById(R.id.btn_record) }
private val tvRecordingTime: TextView by lazy { findViewById(R.id.recording_time) }
private val tvRecordingTime: TextView by lazy { findViewById(R.id.recording_time) }
private val seekBar: SeekBar by lazy { findViewById(R.id.seekbar) }

private var mRecorder: MediaRecorder? = null
Expand Down Expand Up @@ -147,11 +145,13 @@ class AudioNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_AUDIO) {
} else {
stopRecording()
}

R.id.btn_play_pause -> if (!playing) {
startPlaying()
} else {
pausePlaying()
}

else -> {}
}
}
Expand Down Expand Up @@ -271,40 +271,20 @@ class AudioNoteActivity : BaseNoteActivity(DbContract.NoteEntry.TYPE_AUDIO) {
return ActionResult(true, Note(name, mFileName, DbContract.NoteEntry.TYPE_AUDIO, category))
}

override fun onSaveExternalStorage(basePath: File, name: String) {
val file = File(basePath, "/$name.aac")
try {
// Make sure the directory exists.
if (basePath.exists() || basePath.mkdirs()) {
var source: FileChannel? = null
var destination: FileChannel? = null
try {
source = FileInputStream(File(mFilePath)).channel
destination = FileOutputStream(file).channel
destination.transferFrom(source, 0, source.size())
} finally {
source?.close()
destination?.close()
}
override fun getFileExtension() = ".aac"
override fun getMimeType() = "audio/mp4a-latm"

// Tell the media scanner about the new file so that it is
// immediately available to the user.
MediaScannerConnection.scanFile(
this, arrayOf(file.toString()), null
) { path, uri ->
Log.i("ExternalStorage", "Scanned $path:")
Log.i("ExternalStorage", "-> uri=$uri")
override fun onSaveExternalStorage(outputStream: OutputStream) {
FileInputStream(File(mFilePath)).use {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.transferTo(outputStream)
} else {
val buffer = ByteArray(8192)
var length: Int
while (it.read(buffer).also { length = it } != -1) {
outputStream.write(buffer, 0, length)
}
Toast.makeText(
applicationContext,
String.format(getString(R.string.toast_file_exported_to), file.absolutePath),
Toast.LENGTH_LONG
).show()
}
} catch (e: IOException) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing $file", e)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.preference.PreferenceManager
import android.provider.Settings
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.WindowManager
import android.widget.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
Expand All @@ -51,7 +51,7 @@ import org.secuso.privacyfriendlynotes.ui.helper.NotificationHelper.addNotificat
import org.secuso.privacyfriendlynotes.ui.helper.NotificationHelper.removeNotificationFromAlarmManager
import org.secuso.privacyfriendlynotes.ui.helper.NotificationHelper.showAlertScheduledToast
import org.secuso.privacyfriendlynotes.ui.manageCategories.ManageCategoriesActivity
import java.io.File
import java.io.OutputStream
import java.util.*


Expand Down Expand Up @@ -96,7 +96,10 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli
protected abstract fun noteToSave(name: String, category: Int): ActionResult<Note, Int>
protected abstract fun updateNoteToSave(name: String, category: Int): ActionResult<Note, Int>
protected abstract fun onLoadActivity()
protected abstract fun onSaveExternalStorage(basePath: File, name: String)
protected abstract fun onSaveExternalStorage(outputStream: OutputStream)

protected abstract fun getFileExtension(): String
protected abstract fun getMimeType(): String
protected abstract fun shareNote(name: String): ActionResult<Intent, Int>
protected abstract fun onNoteLoadedFromDB(note: Note)
protected abstract fun onNewNote()
Expand Down Expand Up @@ -293,17 +296,7 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli
R.id.action_export -> {
saveOrUpdateNote()

if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
REQUEST_CODE_EXTERNAL_STORAGE
)
} else {
saveToExternalStorage()
}
saveToExternalStorage()
return true
}

Expand Down Expand Up @@ -388,17 +381,6 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
REQUEST_CODE_EXTERNAL_STORAGE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Save the file
saveToExternalStorage()
} else {
Toast.makeText(
applicationContext,
R.string.toast_need_permission_write_external,
Toast.LENGTH_LONG
).show()
}

REQUEST_CODE_AUDIO -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Do nothing. App should work
} else {
Expand Down Expand Up @@ -525,23 +507,31 @@ abstract class BaseNoteActivity(noteType: Int) : AppCompatActivity(), View.OnCli
}
}

private fun saveToExternalStorage() {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state) {
val path = File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS),
"/PrivacyFriendlyNotes"
)
onSaveExternalStorage(path, etName.text.toString())
} else {
Toast.makeText(
applicationContext,
R.string.toast_external_storage_not_mounted,
Toast.LENGTH_LONG
).show()
val saveToExternalStorageResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.data?.let {uri ->
val fileOutputStream: OutputStream? = contentResolver.openOutputStream(uri)
fileOutputStream?.let {
onSaveExternalStorage(it)
Toast.makeText(
applicationContext,
String.format(getString(R.string.toast_file_exported_to), uri.toString()),
Toast.LENGTH_LONG
).show()
}
fileOutputStream?.close()
}
}
}

private fun saveToExternalStorage() {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.putExtra(Intent.EXTRA_TITLE, etName.text.toString() + getFileExtension())
intent.type = getMimeType()
saveToExternalStorageResultLauncher.launch(intent)
}

private fun generateStandardName(): String {
val sp = getSharedPreferences(PreferenceKeys.SP_VALUES, MODE_PRIVATE)
val counter = sp.getInt(PreferenceKeys.SP_VALUES_NAMECOUNTER, 1)
Expand Down
Loading

0 comments on commit 3414cdc

Please sign in to comment.