Skip to content

Commit e07ed22

Browse files
committed
storage: persist incoming document uri grants
1 parent f2e42e9 commit e07ed22

4 files changed

Lines changed: 85 additions & 6 deletions

File tree

app/src/main/java/com/kyhsgeekcode/disassembler/MainActivity.kt

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ package com.kyhsgeekcode.disassembler
55
import android.content.Context
66
import android.content.Intent
77
import android.content.pm.PackageManager
8+
import android.net.Uri
9+
import android.os.Build
810
import android.os.Bundle
911
import android.os.Process
1012
import android.util.Log
@@ -79,13 +81,22 @@ class MainActivity : AppCompatActivity() {
7981
}
8082

8183
private fun handleViewActionIntent() {
82-
// https://www.androidpub.com/1351553
8384
val intent = intent ?: return
84-
if (intent.action == Intent.ACTION_VIEW) { // User opened this app from file browser
85-
intent.data?.let {
86-
intent.putExtra("uri", it)
87-
viewModel.onSelectIntent(intent)
88-
}
85+
val incomingUri = extractIncomingUri(intent) ?: return
86+
takePersistableReadPermissionIfPossible(incomingUri, intent.flags)
87+
intent.putExtra("uri", incomingUri)
88+
viewModel.onSelectIntent(intent)
89+
}
90+
91+
private fun takePersistableReadPermissionIfPossible(uri: Uri, intentFlags: Int) {
92+
val persistFlags = persistableUriPermissionFlags(uri, intentFlags)
93+
if (persistFlags == 0) {
94+
return
95+
}
96+
try {
97+
contentResolver.takePersistableUriPermission(uri, persistFlags)
98+
} catch (e: SecurityException) {
99+
Timber.w(e, "Persistable URI permission not available for %s", uri)
89100
}
90101
}
91102

@@ -160,3 +171,13 @@ class MainActivity : AppCompatActivity() {
160171

161172
external fun Init(): Int
162173
}
174+
175+
private fun extractIncomingUri(intent: Intent): Uri? {
176+
return intent.data
177+
?: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
178+
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
179+
} else {
180+
@Suppress("DEPRECATION")
181+
intent.getParcelableExtra(Intent.EXTRA_STREAM)
182+
}
183+
}

app/src/main/java/com/kyhsgeekcode/disassembler/PermissionUtils.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import android.Manifest
44
import android.app.Activity
55
import android.content.Context
66
import android.content.DialogInterface
7+
import android.content.Intent
78
import android.content.pm.PackageManager
9+
import android.net.Uri
810
import android.os.Build
911
import android.util.Log
1012
import androidx.annotation.RequiresApi
@@ -93,3 +95,22 @@ fun storagePermissionsForSdk(sdkInt: Int): Array<String> {
9395
emptyArray()
9496
}
9597
}
98+
99+
fun persistableUriPermissionFlags(uri: Uri?, intentFlags: Int): Int {
100+
return persistableUriPermissionFlags(uri?.scheme, intentFlags)
101+
}
102+
103+
fun persistableUriPermissionFlags(uriScheme: String?, intentFlags: Int): Int {
104+
if (uriScheme != "content") {
105+
return 0
106+
}
107+
108+
if (intentFlags and Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION == 0) {
109+
return 0
110+
}
111+
112+
return intentFlags and (
113+
Intent.FLAG_GRANT_READ_URI_PERMISSION or
114+
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
115+
)
116+
}

app/src/test/java/com/kyhsgeekcode/disassembler/PermissionUtilsTest.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.kyhsgeekcode.disassembler
22

3+
import android.content.Intent
34
import org.junit.jupiter.api.Assertions.assertArrayEquals
5+
import org.junit.jupiter.api.Assertions.assertEquals
46
import org.junit.jupiter.api.Test
57

68
class PermissionUtilsTest {
@@ -20,4 +22,37 @@ class PermissionUtilsTest {
2022
assertArrayEquals(emptyArray(), storagePermissionsForSdk(29))
2123
assertArrayEquals(emptyArray(), storagePermissionsForSdk(35))
2224
}
25+
26+
@Test
27+
fun `persistableUriPermissionFlags keeps read grant for content uri with persistable access`() {
28+
assertEquals(
29+
Intent.FLAG_GRANT_READ_URI_PERMISSION,
30+
persistableUriPermissionFlags(
31+
"content",
32+
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
33+
)
34+
)
35+
}
36+
37+
@Test
38+
fun `persistableUriPermissionFlags returns zero when persistable access is missing`() {
39+
assertEquals(
40+
0,
41+
persistableUriPermissionFlags(
42+
"content",
43+
Intent.FLAG_GRANT_READ_URI_PERMISSION
44+
)
45+
)
46+
}
47+
48+
@Test
49+
fun `persistableUriPermissionFlags returns zero for non content uri`() {
50+
assertEquals(
51+
0,
52+
persistableUriPermissionFlags(
53+
"file",
54+
Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
55+
)
56+
)
57+
}
2358
}

docs/maintenance/implementation-log.ko.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
| 최신 Android 타게팅 필요 | `compileSdk``targetSdkVersion`을 35로 상향 | Play 최신 요구사항에 맞는 방향으로 기준선을 끌어올렸다. 아직 AGP 자체 업그레이드는 후속 작업이다 | `app/build.gradle`, `gradle.properties` | 완료 |
1111
| 이슈 `#719`, PR `#726` 릴리스 경로 부재 | tag push와 manual dispatch를 지원하는 `release.yml`을 추가하고 기존 CI를 최신 action 버전으로 정리 | 최신 브랜치에서 unsigned/signed APK를 GitHub Actions로 다시 만들고 배포할 수 있는 운영 경로를 복구했다 | `.github/workflows/ci.yml`, `.github/workflows/release.yml` | 완료 |
1212
| 저장소 정책 현대화 착수, 이슈 `#95` 대응 기반 | SAF 기반 선택 경로를 도입하고 `content://` 입력을 앱 내부 import 파일로 저장 | 외부 절대경로 전제를 줄이고, 재시작 이후에도 다시 열 수 있는 URI 권한 흐름을 시작했다 | `app/src/main/java/com/kyhsgeekcode/filechooser/NewFileChooserActivity.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/viewmodel/MainViewModel.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/PermissionUtils.kt` | 진행 중 |
13+
| 이슈 `#95` 외부 문서 인텐트 권한 누락 | 앱이 `ACTION_VIEW``EXTRA_STREAM`으로 열린 경우에도 persistable grant 가능 여부를 계산하고 `content://` URI 권한을 선제적으로 유지 | SAF picker 밖에서 들어온 문서도 같은 storage 정책 흐름으로 흡수해서, provider가 허용하는 경우 앱 재실행 이후에도 접근이 끊길 가능성을 줄였다 | `app/src/main/java/com/kyhsgeekcode/disassembler/MainActivity.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/PermissionUtils.kt`, `app/src/test/java/com/kyhsgeekcode/disassembler/PermissionUtilsTest.kt` | 완료 |
1314
| broad storage 우회 경로 정리 | 더 이상 쓰지 않는 legacy picker 코드와 Android 11+의 `MANAGE_ALL_FILES_ACCESS` 유도 설정을 제거 | SAF 기반 경로를 기본 흐름으로 고정하고, 정책상 불리한 all-files access 진입점을 줄였다 | `app/src/main/java/com/kyhsgeekcode/disassembler/MainActivity.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/preference/SettingsFragment.kt`, `app/src/main/res/xml/pref_settings.xml`, `app/src/main/res/xml-v30/pref_settings.xml`, `app/src/main/res/values/array.xml` | 완료 |
1415
| 프로젝트 저장 모델 확장 | `sourceDescriptor`를 추가하고 새 프로젝트 생성 시 원본 유형을 함께 기록 | 기존 `sourceFilePath` 호환성은 유지하면서 이후 `Uri | file path | cache` 구분으로 넘어갈 발판을 만들었다 | `app/src/main/java/com/kyhsgeekcode/disassembler/project/models/ProjectModel.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/project/ProjectManager.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/viewmodel/MainViewModel.kt` | 완료 |
1516
| SAF와 파워유저 경로 분리 | 기본 import는 SAF 직행으로 두고, settings에서 power-user mode를 켰을 때만 `Advanced import`를 노출 | 기본 사용자 경로와 비정책적/고급 경로를 같은 UI에서 섞지 않고 분리했다 | `app/src/main/java/com/kyhsgeekcode/disassembler/importing/ImportEntryPointCatalog.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/preference/PowerUserModeSettings.kt`, `app/src/main/java/com/kyhsgeekcode/disassembler/ui/MainTab.kt`, `app/src/main/java/com/kyhsgeekcode/filechooser/NewFileChooserActivity.kt`, `app/src/main/java/com/kyhsgeekcode/filechooser/NewFileChooserAdapter.kt`, `app/src/main/java/com/kyhsgeekcode/filechooser/model/FileItem.kt`, `app/src/main/res/xml/pref_settings.xml`, `app/src/main/res/xml-v30/pref_settings.xml` | 완료 |
@@ -32,6 +33,7 @@
3233
| 문서 비식별화 점검 | 통과 | 새 문서에는 저장소 상대 경로만 기록 |
3334
| 파워유저 import entry-point 테스트 | 통과 | standard mode는 SAF only, power-user mode는 advanced import 추가 |
3435
| 파워유저 advanced source catalog 테스트 | 통과 | power-user 비활성 시 advanced source 없음, 활성 시 선택된 source group만 노출 |
36+
| persistable URI permission helper 테스트 | 통과 | content scheme + persistable/read 플래그 조합만 유지 대상으로 판정 |
3537
| workflow YAML 파싱 | 통과 | `.github/workflows/ci.yml`, `.github/workflows/release.yml` 모두 Ruby YAML 파서 기준 확인 |
3638

3739
## 다음 웨이브 후보

0 commit comments

Comments
 (0)