Skip to content

Commit aed0eb0

Browse files
committed
project: persist source descriptors for imports
1 parent bd42266 commit aed0eb0

5 files changed

Lines changed: 122 additions & 10 deletions

File tree

app/src/main/java/com/kyhsgeekcode/disassembler/project/ProjectManager.kt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import android.util.Log
55
import com.kyhsgeekcode.disassembler.Logger
66
import com.kyhsgeekcode.disassembler.copyDirectory
77
import com.kyhsgeekcode.disassembler.project.models.ProjectModel
8+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceDescriptor
9+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceKind
810
import com.kyhsgeekcode.extractZip
911
import com.kyhsgeekcode.isAccessible
1012
import com.kyhsgeekcode.saveAsZip
@@ -85,7 +87,11 @@ object ProjectManager {
8587
targetFileOrFolder: File,
8688
projectType: String,
8789
projectName: String,
88-
copy: Boolean = true
90+
copy: Boolean = true,
91+
sourceDescriptor: ProjectSourceDescriptor = ProjectSourceDescriptor(
92+
ProjectSourceKind.FILE_PATH,
93+
targetFileOrFolder.absolutePath
94+
)
8995
): ProjectModel {
9096
// require(if (useDefault) true else file.isDirectory)
9197
val projectModel: ProjectModel
@@ -113,7 +119,13 @@ object ProjectManager {
113119
}
114120

115121
projectModel =
116-
ProjectModel(projectName, genFolder.path, projectType, determinedSourceFolder.path)
122+
ProjectModel(
123+
name = projectName,
124+
generatedFolder = genFolder.path,
125+
projectType = projectType,
126+
sourceFilePath = determinedSourceFolder.path,
127+
sourceDescriptor = sourceDescriptor
128+
)
117129

118130
projectModels[projectInfoFile.path] = projectModel
119131
projectPaths.add(projectInfoFile.absolutePath)

app/src/main/java/com/kyhsgeekcode/disassembler/project/models/ProjectModel.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,33 @@ import kotlinx.serialization.SerialName
44
import kotlinx.serialization.Serializable
55
import java.io.File
66

7+
@Serializable
8+
enum class ProjectSourceKind {
9+
@SerialName("file-path")
10+
FILE_PATH,
11+
12+
@SerialName("content-uri")
13+
CONTENT_URI,
14+
15+
@SerialName("app-private-file")
16+
APP_PRIVATE_FILE,
17+
18+
@SerialName("extracted-cache-file")
19+
EXTRACTED_CACHE_FILE
20+
}
21+
22+
@Serializable
23+
data class ProjectSourceDescriptor(
24+
@SerialName("kind")
25+
val kind: ProjectSourceKind,
26+
@SerialName("location")
27+
val location: String
28+
)
29+
30+
fun legacyProjectSourceDescriptor(sourceFilePath: String): ProjectSourceDescriptor {
31+
return ProjectSourceDescriptor(ProjectSourceKind.FILE_PATH, sourceFilePath)
32+
}
33+
734
@Serializable
835
data class ProjectModel(
936
@SerialName("projectName")
@@ -20,9 +47,14 @@ data class ProjectModel(
2047
*/
2148
@SerialName("sourceFilePath")
2249
var sourceFilePath: String,
50+
@SerialName("sourceDescriptor")
51+
var sourceDescriptor: ProjectSourceDescriptor? = null,
2352
@SerialName("info")
2453
val info: ArrayList<ProjectFileModel> = ArrayList()
2554
) {
2655
val rootFile: File
27-
get() = File(generatedFolder).parentFile
56+
get() = requireNotNull(File(generatedFolder).parentFile)
57+
58+
val resolvedSourceDescriptor: ProjectSourceDescriptor
59+
get() = sourceDescriptor ?: legacyProjectSourceDescriptor(sourceFilePath)
2860
}

app/src/main/java/com/kyhsgeekcode/disassembler/viewmodel/MainViewModel.kt

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import android.app.Application
44
import android.content.Intent
55
import android.graphics.BitmapFactory
66
import android.net.Uri
7+
import android.os.Build
8+
import android.os.Bundle
9+
import android.os.Parcelable
710
import android.provider.OpenableColumns
811
import androidx.lifecycle.AndroidViewModel
912
import androidx.lifecycle.viewModelScope
@@ -16,6 +19,8 @@ import com.kyhsgeekcode.disassembler.*
1619
import com.kyhsgeekcode.disassembler.project.ProjectDataStorage
1720
import com.kyhsgeekcode.disassembler.project.ProjectManager
1821
import com.kyhsgeekcode.disassembler.project.models.ProjectModel
22+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceDescriptor
23+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceKind
1924
import com.kyhsgeekcode.disassembler.project.models.ProjectType
2025
import com.kyhsgeekcode.disassembler.ui.FileDrawerTreeItem
2126
import com.kyhsgeekcode.disassembler.ui.TabData
@@ -109,13 +114,13 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
109114
fun onSelectIntent(intent: Intent) {
110115
Timber.d("onActivityResultOk")
111116
_openAsProject.value = intent.getBooleanExtra("openProject", false)
112-
val fi = intent.getSerializableExtra("fileItem") as? FileItem
117+
val fi = intent.serializableExtraCompat<FileItem>("fileItem")
113118
if (fi != null) {
114119
onSelectFileItem(fi)
115120
} else {
116121
val displayName = intent.getStringExtra("displayName")
117-
val uri = intent.getParcelableExtra("uri") as Uri?
118-
?: intent.getBundleExtra("extras")?.get(Intent.EXTRA_STREAM) as Uri?
122+
val uri = intent.parcelableExtraCompat<Uri>("uri")
123+
?: intent.extras.parcelableExtraCompat(Intent.EXTRA_STREAM)
119124
?: return
120125
onSelectUri(uri, displayName)
121126
}
@@ -146,8 +151,13 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
146151
file.outputStream().use { fileOut ->
147152
inStream?.copyTo(fileOut)
148153
}
149-
val project =
150-
ProjectManager.newProject(file, ProjectType.UNKNOWN, file.name, true)
154+
val project = ProjectManager.newProject(
155+
file,
156+
ProjectType.UNKNOWN,
157+
file.name,
158+
true,
159+
ProjectSourceDescriptor(ProjectSourceKind.CONTENT_URI, uri.toString())
160+
)
151161
_selectedFilePath.value = project.sourceFilePath
152162
_currentProject.value = project
153163
}
@@ -351,6 +361,35 @@ private fun resolveImportedFileName(
351361
return sanitizeImportedFileName(displayName)
352362
}
353363

364+
private inline fun <reified T : Parcelable> Intent.parcelableExtraCompat(key: String): T? {
365+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
366+
getParcelableExtra(key, T::class.java)
367+
} else {
368+
@Suppress("DEPRECATION")
369+
getParcelableExtra(key)
370+
}
371+
}
372+
373+
private inline fun <reified T : Parcelable> Bundle?.parcelableExtraCompat(key: String): T? {
374+
return if (this == null) {
375+
null
376+
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
377+
getParcelable(key, T::class.java)
378+
} else {
379+
@Suppress("DEPRECATION")
380+
getParcelable(key)
381+
}
382+
}
383+
384+
private inline fun <reified T : java.io.Serializable> Intent.serializableExtraCompat(key: String): T? {
385+
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
386+
getSerializableExtra(key, T::class.java)
387+
} else {
388+
@Suppress("DEPRECATION")
389+
getSerializableExtra(key) as? T
390+
}
391+
}
392+
354393

355394
private fun createTabData(item: FileDrawerTreeItem): TabData {
356395
var title = "${item.caption} as ${item.type}"

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

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

33
import com.kyhsgeekcode.disassembler.project.computeProjectRelativePath
4+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceDescriptor
5+
import com.kyhsgeekcode.disassembler.project.models.ProjectSourceKind
46
import com.kyhsgeekcode.disassembler.project.models.ProjectModel
57
import org.junit.jupiter.api.Assertions.assertEquals
68
import org.junit.jupiter.api.Test
@@ -42,12 +44,38 @@ class ProjectManagerTest {
4244
assertEquals("sample/classes.dex.txt", relPath)
4345
}
4446

45-
private fun projectModelFor(sourceName: String): ProjectModel {
47+
@Test
48+
fun `resolvedSourceDescriptor falls back to legacy file path`() {
49+
val project = projectModelFor("sample")
50+
51+
assertEquals(ProjectSourceKind.FILE_PATH, project.resolvedSourceDescriptor.kind)
52+
assertEquals("sample", project.resolvedSourceDescriptor.location)
53+
}
54+
55+
@Test
56+
fun `resolvedSourceDescriptor prefers explicit descriptor`() {
57+
val project = projectModelFor(
58+
sourceName = "sample",
59+
sourceDescriptor = ProjectSourceDescriptor(
60+
ProjectSourceKind.CONTENT_URI,
61+
"content://samples/app.apk"
62+
)
63+
)
64+
65+
assertEquals(ProjectSourceKind.CONTENT_URI, project.resolvedSourceDescriptor.kind)
66+
assertEquals("content://samples/app.apk", project.resolvedSourceDescriptor.location)
67+
}
68+
69+
private fun projectModelFor(
70+
sourceName: String,
71+
sourceDescriptor: ProjectSourceDescriptor? = null
72+
): ProjectModel {
4673
return ProjectModel(
4774
name = "Sample",
4875
generatedFolder = projectRoot().resolve("generated").path,
4976
projectType = "UNKNOWN",
50-
sourceFilePath = sourceName
77+
sourceFilePath = sourceName,
78+
sourceDescriptor = sourceDescriptor
5179
)
5280
}
5381

docs/maintenance/implementation-log.ko.md

Lines changed: 1 addition & 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
| 저장소 정책 현대화 착수, 이슈 `#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` | 진행 중 |
1212
| 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` | 완료 |
13+
| 프로젝트 저장 모델 확장 | `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` | 완료 |
1314
| 구형 저장소 권한 정리 | `READ_EXTERNAL_STORAGE`, `WRITE_EXTERNAL_STORAGE``maxSdkVersion=28`로 제한하고 `requestLegacyExternalStorage` 제거 | 최신 Android에서 불필요한 legacy 외부 저장소 모델 의존성을 줄였다 | `app/src/main/AndroidManifest.xml` | 완료 |
1415
| 패키징 경고 정리 | manifest의 `extractNativeLibs` 선언을 제거하고 Gradle `jniLibs.useLegacyPackaging = false`로 이동 | native packaging 관련 경고를 Gradle 구성 위치로 정리했다 | `app/build.gradle`, `app/src/main/AndroidManifest.xml` | 완료 |
1516
| 이슈 `#670` 앱 런처 미노출 | `MainActivity``android:enabled="true"`를 명시 | 일부 기기/설정에서 런처 진입점이 빠지는 문제를 명시적으로 막았다 | `app/src/main/AndroidManifest.xml` | 완료 |

0 commit comments

Comments
 (0)