Skip to content

Commit

Permalink
Add option to also intercept ACTION_VIEW intents
Browse files Browse the repository at this point in the history
Fixes #19
  • Loading branch information
MateusRodCosta committed Mar 27, 2024
1 parent 0414882 commit 26e3000
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 26 deletions.
1 change: 1 addition & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 0 additions & 8 deletions .idea/kotlinScripting.xml

This file was deleted.

23 changes: 22 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">

<application
android:allowBackup="true"
Expand Down Expand Up @@ -37,6 +38,26 @@

</activity>

<activity-alias
android:name=".DetailsActivityActionViewIntentInterceptor"
android:targetActivity=".DetailsActivity"
android:exported="true"
android:enabled="false">

<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />

<data android:mimeType="image/*" />
<data android:mimeType="audio/*" />
<data android:mimeType="video/*" />
<data android:mimeType="text/*" />
<data android:mimeType="application/*" />
</intent-filter>

</activity-alias>

</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ class DetailsActivity : ComponentActivity() {
private fun getPreferences() {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
skipFileDetails =
sharedPreferences.getBoolean(SharedPreferenceKeys.skipFileDetailsKey, false)
sharedPreferences.getBoolean(SharedPreferenceKeys.SKIP_FILE_DETAILS_KEY, false)
val defaultSaveLocationRaw =
sharedPreferences.getString(SharedPreferenceKeys.defaultSaveLocationKey, null)
sharedPreferences.getString(SharedPreferenceKeys.DEFAULT_SAVE_LOCATION_KEY, null)
Log.d("details] defaultSaveLocationRaw", defaultSaveLocationRaw.toString())
defaultSaveLocation = if (defaultSaveLocationRaw != null) Uri.parse(defaultSaveLocationRaw)
else null
Expand All @@ -84,8 +84,7 @@ class DetailsActivity : ComponentActivity() {
if (intent.action == Intent.ACTION_SEND) {
val fileUri: Uri? =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) intent.getParcelableExtra(
Intent.EXTRA_STREAM,
Uri::class.java
Intent.EXTRA_STREAM, Uri::class.java
)
else @Suppress("DEPRECATION") intent.getParcelableExtra(Intent.EXTRA_STREAM)
Log.d("fileUri", fileUri.toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class MainActivity : ComponentActivity() {
enableEdgeToEdge()
super.onCreate(savedInstanceState)

settingsViewModel.receiveContext(applicationContext)
settingsViewModel.initializeWithContext(applicationContext)
settingsViewModel.assignSaveLocationDirIntent(getSaveLocationDirIntent)
settingsViewModel.initPreferences()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@

package com.mateusrodcosta.apps.share2storage

import android.content.ComponentName
import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED
import android.content.pm.PackageManager.DONT_KILL_APP
import android.net.Uri
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
Expand All @@ -34,15 +39,21 @@ import kotlinx.coroutines.flow.StateFlow
class SettingsViewModel : ViewModel() {

private lateinit var sharedPreferences: SharedPreferences
private lateinit var packageManager: PackageManager
private lateinit var contentResolver: ContentResolver
private lateinit var getSaveLocationDirIntent: ActivityResultLauncher<Uri?>
private lateinit var packageName: String

private val _defaultSaveLocation = MutableStateFlow<Uri?>(null)
val defaultSaveLocation: StateFlow<Uri?> = _defaultSaveLocation

private val _skipFileDetails = MutableStateFlow(false)
val skipFileDetails: StateFlow<Boolean> = _skipFileDetails


private val _interceptActionViewIntents = MutableStateFlow(false)
val interceptActionViewIntents: StateFlow<Boolean> = _interceptActionViewIntents

fun assignSaveLocationDirIntent(intent: ActivityResultLauncher<Uri?>) {
getSaveLocationDirIntent = intent
}
Expand All @@ -51,14 +62,16 @@ class SettingsViewModel : ViewModel() {
return getSaveLocationDirIntent
}

fun receiveContext(context: Context) {
fun initializeWithContext(context: Context) {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
contentResolver = context.contentResolver
packageManager = context.packageManager
packageName = context.packageName
}

fun initPreferences() {
val spDefaultSaveLocationRaw =
sharedPreferences.getString(SharedPreferenceKeys.defaultSaveLocationKey, null)
sharedPreferences.getString(SharedPreferenceKeys.DEFAULT_SAVE_LOCATION_KEY, null)
val spDefaultSaveLocation = if (spDefaultSaveLocationRaw != null) try {
val uri = Uri.parse(spDefaultSaveLocationRaw)

Expand All @@ -72,22 +85,30 @@ class SettingsViewModel : ViewModel() {
else null

val spSkipFileDetails =
sharedPreferences.getBoolean(SharedPreferenceKeys.skipFileDetailsKey, false)
sharedPreferences.getBoolean(SharedPreferenceKeys.SKIP_FILE_DETAILS_KEY, false)
Log.d("settings] initSharedPreferences] skipFileDetails", spSkipFileDetails.toString())
val spInterceptActionViewIntents = sharedPreferences.getBoolean(
SharedPreferenceKeys.INTERCEPT_ACTION_VIEW_INTENTS_KEY, false
)
Log.d(
"settings] initSharedPreferences] interceptActionViewIntents",
spInterceptActionViewIntents.toString()
)

_defaultSaveLocation.value = spDefaultSaveLocation
_skipFileDetails.value = spSkipFileDetails
_interceptActionViewIntents.value = spInterceptActionViewIntents
}

fun updateDefaultSaveLocation(value: Uri?) {
val currentSaveLocationRaw =
sharedPreferences.getString(SharedPreferenceKeys.defaultSaveLocationKey, null)
sharedPreferences.getString(SharedPreferenceKeys.DEFAULT_SAVE_LOCATION_KEY, null)

sharedPreferences.edit(commit = true) {
if (value != null) putString(
SharedPreferenceKeys.defaultSaveLocationKey, value.toString()
SharedPreferenceKeys.DEFAULT_SAVE_LOCATION_KEY, value.toString()
)
else remove(SharedPreferenceKeys.defaultSaveLocationKey)
else remove(SharedPreferenceKeys.DEFAULT_SAVE_LOCATION_KEY)

}

Expand Down Expand Up @@ -126,9 +147,32 @@ class SettingsViewModel : ViewModel() {

fun updateSkipFileDetails(value: Boolean) {
sharedPreferences.edit(commit = true) {
putBoolean(SharedPreferenceKeys.skipFileDetailsKey, value)
putBoolean(SharedPreferenceKeys.SKIP_FILE_DETAILS_KEY, value)
}

_skipFileDetails.value = value
}

fun updateInterceptActionViewIntents(value: Boolean) {
sharedPreferences.edit(commit = true) {
putBoolean(SharedPreferenceKeys.INTERCEPT_ACTION_VIEW_INTENTS_KEY, value)
Log.e("settings] updateInterceptActionViewIntents", value.toString())

try {
val component = ComponentName(
packageName,
"com.mateusrodcosta.apps.share2storage.DetailsActivityActionViewIntentInterceptor"
)
packageManager.setComponentEnabledSetting(
component,
if (value) COMPONENT_ENABLED_STATE_ENABLED else COMPONENT_ENABLED_STATE_DISABLED,
DONT_KILL_APP
)

_interceptActionViewIntents.value = value
} catch (e: Exception) {
Log.e("settings] updateInterceptActionViewIntents", e.toString())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,29 @@ import kotlinx.coroutines.flow.StateFlow
fun SettingsScreenPreview() {
val mockDefaultSaveLocation = MutableStateFlow(null)
val mockSkipFileDetails = MutableStateFlow(false)
val mockInterceptActionViewIntents = MutableStateFlow(false)

SettingsScreenContent(
spDefaultSaveLocation = mockDefaultSaveLocation,
spSkipFileDetails = mockSkipFileDetails,
spInterceptActionViewIntents = mockInterceptActionViewIntents,
)
}

@Composable
fun SettingsScreen(navController: NavController, settingsViewModel: SettingsViewModel) {
SettingsScreenContent(
navController = navController,
SettingsScreenContent(navController = navController,
spDefaultSaveLocation = settingsViewModel.defaultSaveLocation,
spSkipFileDetails = settingsViewModel.skipFileDetails,
spInterceptActionViewIntents = settingsViewModel.interceptActionViewIntents,
launchFilePicker = { settingsViewModel.getSaveLocationDirIntent().launch(null) },
clearSaveDirectory = { settingsViewModel.clearSaveDirectory() },
updateSkipFileDetails = { value: Boolean ->
settingsViewModel.updateSkipFileDetails(value)
},
)
updateInterceptActionViewIntents = { value: Boolean ->
settingsViewModel.updateInterceptActionViewIntents(value)
})
}

@OptIn(ExperimentalMaterial3Api::class)
Expand All @@ -90,9 +94,11 @@ fun SettingsScreenContent(
navController: NavController? = null,
spDefaultSaveLocation: StateFlow<Uri?>,
spSkipFileDetails: StateFlow<Boolean>,
spInterceptActionViewIntents: StateFlow<Boolean>,
launchFilePicker: () -> Unit = {},
clearSaveDirectory: () -> Unit = {},
updateSkipFileDetails: (Boolean) -> Unit = {},
updateInterceptActionViewIntents: (Boolean) -> Unit = {},
) {
val settingsPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)

Expand Down Expand Up @@ -123,6 +129,12 @@ fun SettingsScreenContent(
paddingValues = settingsPadding,
)
AppBasicDivider()
InterceptActionViewIntentsSetting(
updateInterceptActionViewIntents = updateInterceptActionViewIntents,
spInterceptActionViewIntents = spInterceptActionViewIntents,
paddingValues = settingsPadding,
)
AppBasicDivider()
DefaultSaveLocationSetting(
launchFilePicker = launchFilePicker,
clearSaveDirectory = clearSaveDirectory,
Expand Down Expand Up @@ -167,6 +179,39 @@ fun SkipFileDetailsSetting(
}
}


@Composable
fun InterceptActionViewIntentsSetting(
updateInterceptActionViewIntents: (Boolean) -> Unit,
spInterceptActionViewIntents: StateFlow<Boolean>,
paddingValues: PaddingValues,
) {

val interceptActionViewIntents by spInterceptActionViewIntents.collectAsState()


Row(modifier = Modifier
.clickable { updateInterceptActionViewIntents(!interceptActionViewIntents) }
.padding(paddingValues)
.heightIn(min = 48.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1.0f)) {
Text(
stringResource(id = R.string.settings_intercept_action_view_intents),
style = MaterialTheme.typography.titleLarge,
)
Text(
stringResource(R.string.settings_intercept_action_view_intents_info),
style = MaterialTheme.typography.bodyLarge
)
}
Spacer(modifier = Modifier.width(8.dp))
Switch(checked = interceptActionViewIntents, onCheckedChange = { value ->
updateInterceptActionViewIntents(value)
})
}
}

@Composable
fun DefaultSaveLocationSetting(
launchFilePicker: () -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.mateusrodcosta.apps.share2storage.utils

object SharedPreferenceKeys {
const val skipFileDetailsKey: String = "skip_file_details"
const val defaultSaveLocationKey: String = "default_save_location"
const val SKIP_FILE_DETAILS_KEY: String = "skip_file_details"
const val DEFAULT_SAVE_LOCATION_KEY: String = "default_save_location"
const val INTERCEPT_ACTION_VIEW_INTENTS_KEY: String = "intercept_action_view_intents"
}
2 changes: 2 additions & 0 deletions app/src/main/res/values-pt-rBR/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
<string name="settings">Configurações</string>
<string name="settings_skip_file_details_page">Pular página de Detalhes do arquivo</string>
<string name="settings_skip_file_details_page_info">Abrir seletor de arquivos assim que receber arquivo</string>
<string name="settings_intercept_action_view_intents">Intercepta intents do tipo ACTION_VIEW</string>
<string name="settings_intercept_action_view_intents_info">Permite registrar como uma opção quando aplicativos tentam automaticamente abrir um visualizador de arquivos</string>
<string name="settings_default_save_location">Local de salvamento padrão</string>
<string name="settings_default_save_location_last_used">Última pasta usada</string>
<string name="clear_button">Limpar</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
<string name="settings">Settings</string>
<string name="settings_skip_file_details_page">Skip File Details page</string>
<string name="settings_skip_file_details_page_info">Open file picker as soon as file is received</string>
<string name="settings_intercept_action_view_intents">Intercept ACTION_VIEW intents</string>
<string name="settings_intercept_action_view_intents_info">Allow registering as an option when apps try to automatically open a file viewer</string>
<string name="settings_default_save_location">Default save location</string>
<string name="settings_default_save_location_last_used">Last used folder</string>
<string name="clear_button">Clear</string>
Expand Down

0 comments on commit 26e3000

Please sign in to comment.