Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
.externalNativeBuild
.cxx
local.properties
.kotlin
4 changes: 4 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,8 @@ dependencies {
implementation(libs.zoomable)
implementation(libs.androidx.media3.exoplayer)
implementation(libs.androidx.media3.ui)

// APKEditor
implementation(files("libs/APKEditor.jar"))
implementation(libs.apksig)
}
Binary file added app/libs/APKEditor.jar
Binary file not shown.
5 changes: 4 additions & 1 deletion app/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@

-keep class com.raival.compose.file.explorer.** { *; }
-keep class org.eclipse.tm4e.** { *; }
-keep class org.joni.** { *; }
-keep class org.joni.** { *; }
-keep class android.content.** { *; }

-keepnames interface * { *; }
Binary file added app/src/main/assets/keystore/testkey.pk8
Binary file not shown.
27 changes: 27 additions & 0 deletions app/src/main/assets/keystore/testkey.x509.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN CERTIFICATE-----
MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE
AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe
Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET
MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G
A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p
ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI
hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM
qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4
wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy
4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU
RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s
zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw
HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ
AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE
CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH
QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG
CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud
EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa
J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y
LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe
+ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX
31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr
sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.res.AssetManager
import android.net.Uri
import android.os.Environment
import androidx.compose.foundation.lazy.LazyListState
Expand Down Expand Up @@ -86,6 +87,8 @@ class FilesTab(
val currentPathSegments = mutableStateListOf<DocumentHolder>()
val currentPathSegmentsListState = LazyListState()

val assetManager: AssetManager = globalClass.assets

val selectedFiles = linkedMapOf<String, DocumentHolder>()
var lastSelectedFileIndex = -1

Expand Down Expand Up @@ -219,7 +222,7 @@ class FilesTab(
}

fun openFile(context: Context, item: DocumentHolder) {
if (item.isApk) {
if (item.isApk || item.isApks) {
ApkDialog.show(item)
} else {
item.openFile(context, anonymous = false, skipSupportedExtensions = false)
Expand Down Expand Up @@ -533,10 +536,13 @@ class FilesTab(
private set
var apkFile: DocumentHolder? = null
private set
var ApksArchive = false
private set

fun show(file: DocumentHolder) {
apkFile = file
showApkDialog = true
ApksArchive = file.isApks
}

fun hide() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import coil3.request.Options
import com.raival.compose.file.explorer.R
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder.Companion.FILE_TYPE_AI
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder.Companion.FILE_TYPE_APK
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder.Companion.FILE_TYPE_ARCHIVE
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder.Companion.FILE_TYPE_AUDIO
import com.raival.compose.file.explorer.screen.main.tab.files.modal.DocumentHolder.Companion.FILE_TYPE_CODE
Expand Down Expand Up @@ -46,6 +47,7 @@ class DocumentFileMapper : Mapper<DocumentHolder, Any> {
data.getFileIconType() == FILE_TYPE_CODE -> R.drawable.css_file_extension
data.getFileIconType() == FILE_TYPE_TEXT -> R.drawable.txt_file_extension
data.getFileIconType() == FILE_TYPE_ARCHIVE -> R.drawable.zip_file_extension
data.getFileIconResource() == FILE_TYPE_APK -> R.drawable.apk_file_extension
canUseCoil(data) -> data.uri
else -> R.drawable.unknown_file_extension
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,62 +39,63 @@ import com.raival.compose.file.explorer.common.compose.Space
import com.raival.compose.file.explorer.common.extension.emptyString
import com.raival.compose.file.explorer.common.extension.toFormattedSize
import com.raival.compose.file.explorer.screen.main.tab.files.FilesTab
import com.raival.compose.file.explorer.screen.preferences.PreferencesManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

@Composable
fun ApkPreviewDialog(tab: FilesTab) {
val apkDialog = tab.apkDialog
val isApksArchive: Boolean = apkDialog.ApksArchive

if (tab.apkDialog.showApkDialog && apkDialog.apkFile != null) {
val packageManager = globalClass.packageManager
val context = LocalContext.current
val apkFile = apkDialog.apkFile!!

val apkInfo by remember {
mutableStateOf(packageManager.getPackageArchiveInfo(apkFile.path, 0))
}
var icon by remember { mutableStateOf<Drawable?>(null) }
val details = remember { mutableStateListOf<Pair<String, String>>() }
var appName by remember { mutableStateOf(emptyString) }

var icon by remember {
mutableStateOf<Drawable?>(null)
}
val doSign = PreferencesManager.GeneralPrefs.signApk

val details = remember {
mutableStateListOf<Pair<String, String>>()
}

var appName by remember {
mutableStateOf(emptyString)
}
if (!isApksArchive) {
val packageManager = globalClass.packageManager
val apkInfo =
remember { mutableStateOf(packageManager.getPackageArchiveInfo(apkFile.path, 0)) }

LaunchedEffect(Unit) {
apkInfo?.let {
it.applicationInfo?.sourceDir = apkFile.path
it.applicationInfo?.publicSourceDir = apkFile.path
LaunchedEffect(Unit) {
apkInfo.value?.let { info ->
info.applicationInfo?.sourceDir = apkFile.path
info.applicationInfo?.publicSourceDir = apkFile.path

icon = it.applicationInfo?.loadIcon(packageManager)
appName = it.applicationInfo?.loadLabel(packageManager).toString()
icon = info.applicationInfo?.loadIcon(packageManager)
appName = info.applicationInfo?.loadLabel(packageManager).toString()

details.add(Pair(globalClass.getString(R.string.package_name), it.packageName))
it.versionName?.let {
details.add(Pair(globalClass.getString(R.string.version_name), it))
}
details.add(
Pair(
globalClass.getString(R.string.version_code),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) it.longVersionCode.toString() else it.versionCode.toString()
details.add(
Pair(
globalClass.getString(R.string.package_name),
info.packageName
)
)
)
details.add(
Pair(
globalClass.getString(R.string.size),
apkFile.fileSize.toFormattedSize()
info.versionName?.let {
details.add(Pair(globalClass.getString(R.string.version_name), it))
}
details.add(
Pair(
globalClass.getString(R.string.version_code),
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) info.longVersionCode.toString() else info.versionCode.toString()
)
)
)
}
}
}
details.add(
Pair(globalClass.getString(R.string.size), apkFile.fileSize.toFormattedSize())
)

BottomSheetDialog(
onDismissRequest = { apkDialog.hide() }
) {
BottomSheetDialog(onDismissRequest = { apkDialog.hide() }) {
Column(
modifier = Modifier
.fillMaxWidth()
Expand Down Expand Up @@ -122,11 +123,7 @@ fun ApkPreviewDialog(tab: FilesTab) {
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Text(
text = appName,
fontSize = 18.sp,
fontWeight = FontWeight.Bold
)
Text(text = appName, fontSize = 18.sp, fontWeight = FontWeight.Bold)
}

Space(size = 8.dp)
Expand All @@ -138,7 +135,8 @@ fun ApkPreviewDialog(tab: FilesTab) {
Text(
modifier = Modifier.alpha(0.5f),
text = it.second,
maxLines = 1
softWrap = true,
maxLines = 2
)
}
}
Expand All @@ -147,31 +145,57 @@ fun ApkPreviewDialog(tab: FilesTab) {
Space(size = 8.dp)

Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(
onClick = {
apkDialog.hide()
apkFile.openFile(
context = context,
anonymous = false,
skipSupportedExtensions = true,
customMimeType = "application/zip"
)
}
) {
TextButton(onClick = {
apkDialog.hide()
apkFile.openFile(
context = context,
anonymous = false,
skipSupportedExtensions = true,
customMimeType = "application/zip"
)
}) {
Text(text = stringResource(R.string.explore))
}

TextButton(
onClick = {
if (isApksArchive) {
TextButton(onClick = {
apkDialog.hide()
val mergeHandler = MergeHandler(context)
mergeHandler.mergeApks(
tab, apkFile, doSign,
onSuccess = {
CoroutineScope(Dispatchers.Main).launch {
tab.taskDialog.taskDialogInfo =
context.getString(R.string.merge_successful)
tab.taskDialog.taskDialogSubtitle =
context.getString(R.string.merge_completed)
tab.taskDialog.taskDialogProgress = 1f
delay(500)
tab.taskDialog.showTaskDialog = false
}
},
onError = { errorMessage ->
CoroutineScope(Dispatchers.Main).launch {
tab.taskDialog.taskDialogInfo = errorMessage
tab.taskDialog.taskDialogSubtitle =
context.getString(R.string.failed)
}
}
)
}) {
Text(text = stringResource(R.string.merge))
}
} else {
TextButton(onClick = {
apkDialog.hide()
apkFile.openFile(
context = context,
context,
anonymous = false,
skipSupportedExtensions = true
)
}) {
Text(text = stringResource(R.string.install))
}
) {
Text(text = stringResource(R.string.install))
}
}
}
Expand Down
Loading