Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix export permissions for API >= 33 #158

Merged
merged 1 commit into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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