Merge remote-tracking branch 'origin/master'

# Conflicts:
#	app/build.gradle.kts
#	app/src/main/java/org/autojs/autojs/ui/project/BuildActivity.java
This commit is contained in:
SuperMonster003
2025-01-01 10:23:31 +08:00
40 changed files with 2981 additions and 5 deletions

View File

@@ -174,9 +174,6 @@ dependencies /* Unclassified */ {
// Rhino
implementation(files("$rootDir/libs/org.mozilla.rhino-1.7.16-snapshot.jar"))
// Tiny Sign
implementation(files("$rootDir/libs/tiny-sign-0.9.jar"))
// Tasker Plugin
implementation(project(":libs:android-spackle-9.0.0"))
implementation(project(":libs:android-assertion-9.0.0"))
@@ -205,6 +202,16 @@ dependencies /* Unclassified */ {
// implementation("com.huaban:jieba-analysis:1.0.2")
implementation(project(":jieba-analysis"))
// Tiny Sign
implementation(files("$rootDir/libs/tiny-sign-0.9.jar"))
// ApkSigner
implementation("com.github.TimScriptov:apksigner:1.2.0")
// Room
implementation("androidx.room:room-runtime:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
ksp("androidx.room:room-compiler:2.6.1")
}
dependencies /* MIME */ {

View File

@@ -258,6 +258,9 @@
<activity android:name="org.autojs.autojs.ui.project.ProjectConfigActivity" />
<activity
android:name="org.autojs.autojs.ui.keystore.ManageKeyStoreActivity" />
<activity
android:name="org.autojs.autojs.ui.log.LogActivity"
android:exported="true"

Binary file not shown.

View File

@@ -8,7 +8,11 @@ import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Build
import android.util.Log
import com.mcal.apksigner.ApkSigner
import com.reandroid.arsc.chunk.TableBlock
import org.apache.commons.io.FileUtils.copyFile
import org.apache.commons.io.FileUtils.copyInputStreamToFile
import org.autojs.autojs.apkbuilder.keystore.AESUtils
import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.engine.encryption.AdvancedEncryptionStandard
import org.autojs.autojs.pio.PFiles
@@ -16,6 +20,7 @@ import org.autojs.autojs.project.BuildInfo
import org.autojs.autojs.project.ProjectConfig
import org.autojs.autojs.script.EncryptedScriptFileHeader.writeHeader
import org.autojs.autojs.script.JavaScriptFileSource
import org.autojs.autojs.apkbuilder.keystore.KeyStore
import org.autojs.autojs.util.FileUtils.TYPE.JAVASCRIPT
import org.autojs.autojs.util.MD5Utils
import org.autojs.autojs6.BuildConfig
@@ -269,6 +274,40 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
val fos = FileOutputStream(outApkFile)
TinySign.sign(File(workspacePath), fos)
fos.close()
val defaultKeyStoreFile = File(workspacePath, "default_key_store.bks")
val tmpOutputApk = File(workspacePath, "temp.apk")
copyInputStreamToFile(GlobalAppContext.get().assets.open("default_key_store.bks"), defaultKeyStoreFile)
val signer = ApkSigner(outApkFile, tmpOutputApk)
signer.useDefaultSignatureVersion = false
signer.v1SigningEnabled = mAppConfig.signatureSchemes.contains("V1")
signer.v2SigningEnabled = mAppConfig.signatureSchemes.contains("V2")
signer.v3SigningEnabled = mAppConfig.signatureSchemes.contains("V3")
signer.v4SigningEnabled = mAppConfig.signatureSchemes.contains("V4")
var keyStoreFile = defaultKeyStoreFile
var password = "AutoJs6"
var alias = "AutoJs6"
var aliasPassword = "AutoJs6"
mAppConfig.keyStore?.let {
keyStoreFile = File(it.absolutePath)
password = AESUtils.decrypt(it.password)
alias = it.alias
aliasPassword = AESUtils.decrypt(it.aliasPassword)
}
// 使用 ApkSigner 重新签名
if (!signer.signRelease(keyStoreFile, password, alias, aliasPassword)) {
throw java.lang.RuntimeException("Failed to re-sign using ApkSigner")
}
try {
copyFile(tmpOutputApk, outApkFile)
} catch (e: java.lang.Exception) {
throw java.lang.RuntimeException(e)
}
}
fun cleanWorkspace() = also {
@@ -321,6 +360,12 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
private set
var libs: List<String> = emptyList()
private set
var keyStore: KeyStore? = null
private set
var signatureSchemes: String = "V1 + V2"
private set
var permissions: List<String> = emptyList()
private set
fun ignoreDir(dir: File) = also { ignoredDirs.add(dir) }
@@ -342,6 +387,12 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
fun setLibs(libs: List<String>) = also { this.libs = libs }
fun setKeyStore(keyStore: KeyStore?) = also { this.keyStore = keyStore }
fun setSignatureSchemes(signatureSchemes: String) = also { this.signatureSchemes = signatureSchemes }
fun setPermissions(permissions: List<String>) = also { this.permissions = permissions }
companion object {
@JvmStatic
fun fromProjectConfig(projectDir: String?, projectConfig: ProjectConfig) = AppConfig()
@@ -365,6 +416,10 @@ open class ApkBuilder(apkInputStream: InputStream?, private val outApkFile: File
}
}
}
override fun isPermissionRequired(permissionName: String): Boolean {
return mAppConfig.permissions.contains(permissionName)
}
}
private fun copyLibrariesByConfig(config: AppConfig) {

View File

@@ -88,6 +88,10 @@ public class ManifestEditor {
}
}
public boolean isPermissionRequired(String permissionName) {
return true;
}
private class MutableAxmlWriter extends AxmlWriter {
private class MutableNodeImpl extends AxmlWriter.NodeImpl {
@@ -97,6 +101,9 @@ public class ManifestEditor {
@Override
protected void onAttr(AxmlWriter.Attr a) {
if ("uses-permission".equals(this.name.data) && "name".equals(a.name.data) && a.value instanceof StringItem) {
this.ignore = !ManifestEditor.this.isPermissionRequired(((StringItem) a.value).data);
}
ManifestEditor.this.onAttr(a);
super.onAttr(a);
}

View File

@@ -0,0 +1,71 @@
package org.autojs.autojs.apkbuilder.keystore
import android.util.Base64
import javax.crypto.Cipher
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import java.security.KeyStore
import javax.crypto.KeyGenerator
object AESUtils {
private const val TRANSFORMATION = "AES/GCM/NoPadding"
private const val TAG_LENGTH = 128
private const val KEY_ALIAS = "autojs6_key_store_aes_key"
private fun getKey(): SecretKey {
val keyStore = KeyStore.getInstance("AndroidKeyStore")
keyStore.load(null)
val key = keyStore.getKey(KEY_ALIAS, null)
if (key != null) {
return key as SecretKey
}
val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore")
val keyGenParameterSpec = KeyGenParameterSpec.Builder(KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.build()
keyGenerator.init(keyGenParameterSpec)
return keyGenerator.generateKey()
}
// 加密
fun encrypt(data: String): String {
val secretKey: SecretKey = getKey()
val cipher = Cipher.getInstance(TRANSFORMATION)
cipher.init(Cipher.ENCRYPT_MODE, secretKey)
val encryptedData = cipher.doFinal(data.toByteArray())
val encryptedBase64 = Base64.encodeToString(encryptedData, Base64.NO_WRAP)
val ivBase64 = Base64.encodeToString(cipher.iv, Base64.NO_WRAP)
return "$ivBase64:$encryptedBase64"
}
// 解密
fun decrypt(encryptedData: String): String {
val parts = encryptedData.split(":")
val ivBase64 = parts[0]
val encryptedBase64 = parts[1]
val iv = Base64.decode(ivBase64, Base64.NO_WRAP)
val encrypted = Base64.decode(encryptedBase64, Base64.NO_WRAP)
val secretKey: SecretKey = getKey()
val cipher = Cipher.getInstance(TRANSFORMATION)
val gcmSpec = GCMParameterSpec(TAG_LENGTH, iv)
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmSpec)
val decryptedData = cipher.doFinal(encrypted)
return String(decryptedData)
}
}

View File

@@ -0,0 +1,18 @@
package org.autojs.autojs.apkbuilder.keystore
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class KeyStore(
@PrimaryKey val absolutePath: String, // 密钥库绝对路径
@ColumnInfo(name = "filename") val filename: String = "", // 文件名
@ColumnInfo(name = "password") val password: String = "", // 密码
@ColumnInfo(name = "alias") val alias: String = "", // 别名
@ColumnInfo(name = "alias_password") val aliasPassword: String = "", // 别名密码
@ColumnInfo(name = "verified") val verified: Boolean = false, // 验证状态
) {
override fun toString(): String = filename
}

View File

@@ -0,0 +1,29 @@
package org.autojs.autojs.apkbuilder.keystore
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Query
import androidx.room.Upsert
@Dao
interface KeyStoreDao {
@Query("SELECT * FROM keystore WHERE absolutePath = :absolutePath LIMIT 1")
suspend fun getByAbsolutePath(absolutePath: String): KeyStore?
@Upsert
suspend fun upsert(vararg keyStores: KeyStore)
@Query("SELECT * FROM keystore")
suspend fun getAll(): List<KeyStore>
@Delete
suspend fun delete(vararg keyStores: KeyStore)
@Query("DELETE FROM keystore WHERE absolutePath = :absolutePath")
suspend fun deleteByAbsolutePath(absolutePath: String): Int
@Query("DELETE FROM keystore")
suspend fun deleteAll()
}

View File

@@ -0,0 +1,28 @@
package org.autojs.autojs.apkbuilder.keystore
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
@Database(entities = [KeyStore::class], version = 1, exportSchema = false)
abstract class KeyStoreDatabase : RoomDatabase() {
abstract fun keyStoreDao(): KeyStoreDao
companion object {
@Volatile
private var INSTANCE: KeyStoreDatabase? = null
fun getDatabase(context: Context): KeyStoreDatabase {
return INSTANCE ?: synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
KeyStoreDatabase::class.java,
"keystore-database"
).build()
INSTANCE = instance
instance
}
}
}
}

View File

@@ -0,0 +1,50 @@
package org.autojs.autojs.apkbuilder.keystore
import android.content.Context
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
class KeyStoreRepository(context: Context) {
private var dao: KeyStoreDao
init {
val keyStoreDatabase = KeyStoreDatabase.getDatabase(context)
dao = keyStoreDatabase.keyStoreDao()
}
// 获取所有 KeyStore
suspend fun getAllKeyStores(): List<KeyStore> {
return withContext(Dispatchers.IO) {
dao.getAll()
}
}
// 插入或更新 KeyStore
suspend fun upsertKeyStores(vararg keyStores: KeyStore) {
withContext(Dispatchers.IO) {
dao.upsert(*keyStores)
}
}
// 根据绝对路径获取 KeyStore
suspend fun getKeyStoreAbsolutePath(absolutePath: String): KeyStore? {
return withContext(Dispatchers.IO) {
dao.getByAbsolutePath(absolutePath)
}
}
// 删除 KeyStore
suspend fun deleteKeyStores(vararg keyStores: KeyStore) {
withContext(Dispatchers.IO) {
dao.delete(*keyStores)
}
}
// 删除所有 KeyStore
suspend fun deleteAllKeyStores() {
withContext(Dispatchers.IO) {
dao.deleteAll()
}
}
}

View File

@@ -178,7 +178,7 @@ public class ConsoleView extends FrameLayout implements ConsoleImpl.LogListener
return /* default text size */ 14;
}
public void setTextColors(@NotNull Integer[] colors) {
public void setTextColors(Integer[] colors) {
Adapter adapter = (Adapter) mLogListRecyclerView.getAdapter();
if (adapter != null) {
adapter.setTextColors(colors);

View File

@@ -172,6 +172,11 @@ object Pref {
@ScriptInterfaceCompatible
fun getScriptDirPath() = WorkingDirectoryUtils.path
@JvmStatic
fun getKeyStorePath(): String {
return getScriptDirPath() + "/.KeyStore/"
}
@JvmStatic
fun registerOnSharedPreferenceChangeListener(listener: OnSharedPreferenceChangeListener) {
sPref.registerOnSharedPreferenceChangeListener(listener)

View File

@@ -0,0 +1,82 @@
package org.autojs.autojs.ui.keystore
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import org.autojs.autojs.apkbuilder.keystore.KeyStore
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.ItemKeyStoreBinding
class KeyStoreAdaptor(
private val keyStoreAdapterCallback: KeyStoreAdapterCallback,
) : ListAdapter<KeyStore, KeyStoreAdaptor.KeyStoreViewHolder>(KeyStoreDiffCallback()) {
class KeyStoreDiffCallback : DiffUtil.ItemCallback<KeyStore>() {
override fun areItemsTheSame(oldItem: KeyStore, newItem: KeyStore): Boolean {
return oldItem.absolutePath == newItem.absolutePath
}
override fun areContentsTheSame(oldItem: KeyStore, newItem: KeyStore): Boolean {
return oldItem.filename == newItem.filename &&
oldItem.password == newItem.password &&
oldItem.alias == newItem.alias &&
oldItem.aliasPassword == newItem.aliasPassword &&
oldItem.verified == newItem.verified
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): KeyStoreViewHolder {
val binding = ItemKeyStoreBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return KeyStoreViewHolder(binding).apply {
binding.delete.setOnClickListener {
if (bindingAdapterPosition != RecyclerView.NO_POSITION) {
keyStoreAdapterCallback.onDeleteButtonClicked(getItem(bindingAdapterPosition))
}
}
binding.verify.setOnClickListener {
if (bindingAdapterPosition != RecyclerView.NO_POSITION) {
keyStoreAdapterCallback.onVerifyButtonClicked(getItem(bindingAdapterPosition))
}
}
itemView.setOnClickListener {
if (bindingAdapterPosition != RecyclerView.NO_POSITION) {
keyStoreAdapterCallback.onVerifyButtonClicked(getItem(bindingAdapterPosition))
}
}
}
}
override fun onBindViewHolder(holder: KeyStoreViewHolder, position: Int) {
holder.bind(getItem(position))
}
inner class KeyStoreViewHolder(private val binding: ItemKeyStoreBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(item: KeyStore) {
binding.apply {
filename.text = itemView.context.getString(
R.string.text_str_colon_space_str_formatter,
itemView.context.getString(R.string.text_file_name),
item.filename
)
alias.text = itemView.context.getString(
R.string.text_str_colon_space_str_formatter,
itemView.context.getString(R.string.text_key_alias),
item.alias
)
verify.setImageResource(
if (item.verified) R.drawable.ic_key_store_verified else R.drawable.ic_key_store_unverified
)
}
}
}
interface KeyStoreAdapterCallback {
fun onDeleteButtonClicked(keyStore: KeyStore)
fun onVerifyButtonClicked(keyStore: KeyStore)
}
}

View File

@@ -0,0 +1,267 @@
package org.autojs.autojs.ui.keystore
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import com.mcal.apksigner.CertCreator
import com.mcal.apksigner.utils.DistinguishedNameValues
import com.mcal.apksigner.utils.KeyStoreHelper
import org.autojs.autojs.apkbuilder.keystore.AESUtils
import org.autojs.autojs.apkbuilder.keystore.KeyStore
import org.autojs.autojs.core.pref.Pref
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.ActivityManageKeyStoreBinding
import org.autojs.autojs.ui.BaseActivity
import org.autojs.autojs.ui.keystore.NewKeyStoreDialog.NewKeyStoreConfigs
import org.autojs.autojs.ui.viewmodel.KeyStoreViewModel
import java.io.File
import java.io.IOException
class ManageKeyStoreActivity : BaseActivity() {
private lateinit var binding: ActivityManageKeyStoreBinding
private lateinit var keyStoreAdapter: KeyStoreAdaptor
private lateinit var keyStoreViewModel: KeyStoreViewModel
companion object {
fun startActivity(context: Context) {
Intent(context, ManageKeyStoreActivity::class.java).apply {}.also {
ContextCompat.startActivity(context, it, null)
}
}
}
private val newKeyStoreDialogCallback = object : NewKeyStoreDialog.Callback {
override fun onConfirmButtonClicked(configs: NewKeyStoreConfigs) {
createKeyStore(configs)
}
}
private val verifyKeyStoreDialog = object : VerifyKeyStoreDialog.Callback {
override fun onVerifyButtonClicked(
configs: VerifyKeyStoreDialog.VerifyKeyStoreConfigs, keyStore: KeyStore,
) {
verifyKeyStore(configs, keyStore)
}
}
private val keyStoreAdapterCallback = object : KeyStoreAdaptor.KeyStoreAdapterCallback {
override fun onDeleteButtonClicked(keyStore: KeyStore) {
MaterialDialog.Builder(this@ManageKeyStoreActivity)
.title(getString(R.string.text_confirm_to_delete))
.positiveText(R.string.text_ok).negativeText(R.string.text_cancel)
.onPositive { _: MaterialDialog, _: DialogAction ->
deleteKeyStore(keyStore)
}.show()
}
override fun onVerifyButtonClicked(keyStore: KeyStore) {
VerifyKeyStoreDialog(verifyKeyStoreDialog, keyStore).show(supportFragmentManager, null)
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityManageKeyStoreBinding.inflate(layoutInflater)
setContentView(binding.root)
setToolbarAsBack(getString(R.string.text_manage_key_store))
keyStoreViewModel =
ViewModelProvider(this, KeyStoreViewModel.Factory(this))[KeyStoreViewModel::class.java]
binding.fab.setOnClickListener {
NewKeyStoreDialog(newKeyStoreDialogCallback).show(supportFragmentManager, null)
}
keyStoreAdapter = KeyStoreAdaptor(keyStoreAdapterCallback)
binding.recyclerView.apply {
adapter = keyStoreAdapter
layoutManager = LinearLayoutManager(this@ManageKeyStoreActivity)
itemAnimator = DefaultItemAnimator()
}
binding.swipeRefreshLayout.setOnRefreshListener {
loadKeyStores()
binding.recyclerView.postDelayed({
binding.swipeRefreshLayout.isRefreshing = false
}, 800)
}
keyStoreViewModel.allKeyStores.observe(this@ManageKeyStoreActivity) {
keyStoreAdapter.submitList(it.toList())
}
loadKeyStores()
}
override fun onResume() {
super.onResume()
loadKeyStores()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_manage_key_store, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_delete_all -> {
MaterialDialog.Builder(this@ManageKeyStoreActivity)
.title(getString(R.string.text_delete_all))
.positiveText(R.string.text_ok).negativeText(R.string.text_cancel)
.onPositive { _: MaterialDialog, _: DialogAction ->
deleteAllKeyStores()
}.show()
}
else -> {}
}
return super.onOptionsItemSelected(item)
}
private fun loadKeyStores() {
val path = File(Pref.getKeyStorePath())
if (!path.isDirectory) {
return
}
val filteredFiles = path.listFiles { _, name ->
name.endsWith(".bks") || name.endsWith(".jks")
} ?: emptyArray()
keyStoreViewModel.updateAllKeyStoresFromFiles(filteredFiles)
}
fun createKeyStore(configs: NewKeyStoreConfigs) {
val keyStorePath = File(Pref.getKeyStorePath())
keyStorePath.mkdirs()
val file = File(keyStorePath, configs.filename)
val distinguishedNameValues = DistinguishedNameValues().apply {
setCommonName(configs.firstAndLastName)
setOrganization(configs.organization)
setOrganizationalUnit(configs.organizationalUnit)
setCountry(configs.countryCode)
setState(configs.stateOrProvince)
setLocality(configs.cityOrLocality)
setStreet(configs.street)
}
try {
CertCreator.createKeystoreAndKey(
file,
configs.password.toCharArray(),
"RSA",
2048,
configs.alias,
configs.aliasPassword.toCharArray(),
configs.signatureAlgorithm,
configs.validityYears,
distinguishedNameValues
)
val newKeyStore = KeyStore(
absolutePath = file.absolutePath,
filename = file.name,
password = AESUtils.encrypt(configs.password),
alias = configs.alias,
aliasPassword = AESUtils.encrypt(configs.aliasPassword),
verified = true
)
keyStoreViewModel.upsertKeyStore(newKeyStore)
showToast(R.string.text_successfully_created_key_store)
} catch (e: IOException) {
showToast(getString(R.string.text_failed_to_create_key_store) + " " + e.message)
} catch (e: Exception) {
showToast(getString(R.string.text_failed_to_create_key_store) + " " + e.message)
}
}
fun deleteKeyStore(keyStore: KeyStore) {
val keyStorePath = keyStore.absolutePath
val keyStoreFile = File(keyStorePath)
try {
if (keyStoreFile.delete()) {
keyStoreViewModel.deleteKeyStore(keyStore)
showToast(getString(R.string.text_already_deleted) + " " + keyStore.filename)
} else {
showToast(getString(R.string.text_failed_to_delete))
}
} catch (e: Exception) {
showToast(getString(R.string.text_failed_to_delete) + ": " + e.message)
}
}
private fun deleteAllKeyStores() {
val path = File(Pref.getKeyStorePath())
if (!path.isDirectory) return
val files = path.listFiles { _, name -> name.endsWith(".bks") || name.endsWith(".jks") }
files?.forEach { file ->
file.delete()
}
keyStoreViewModel.deleteAllKeyStores()
showToast(getString(R.string.text_already_deleted))
}
fun verifyKeyStore(
configs: VerifyKeyStoreDialog.VerifyKeyStoreConfigs, keyStore: KeyStore,
) {
// 验证密钥库密码
val tmpKeyStore = try {
KeyStoreHelper.loadKeyStore(File(keyStore.absolutePath), configs.password.toCharArray())
} catch (e: Exception) {
null
}
if (tmpKeyStore == null) {
showToast(R.string.text_verify_failed)
return
}
// 验证别名和别名密码
val tmpKey = try {
tmpKeyStore.getKey(configs.alias, configs.aliasPassword.toCharArray())
} catch (e: Exception) {
null
}
if (tmpKey == null) {
showToast(R.string.text_verify_failed)
return
}
val verifiedKeyStore = KeyStore(
absolutePath = keyStore.absolutePath,
filename = keyStore.filename,
password = AESUtils.encrypt(configs.password),
alias = configs.alias,
aliasPassword = AESUtils.encrypt(configs.aliasPassword),
verified = true
)
keyStoreViewModel.upsertKeyStore(verifiedKeyStore)
showToast(R.string.text_verify_success)
}
private fun showToast(@StringRes messageResId: Int) {
Toast.makeText(this, getString(messageResId), Toast.LENGTH_SHORT).show()
}
private fun showToast(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}

View File

@@ -0,0 +1,247 @@
package org.autojs.autojs.ui.keystore
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import androidx.fragment.app.DialogFragment
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.DialogNewKeyStoreBinding
open class NewKeyStoreDialog(
private val callback: Callback,
) : DialogFragment() {
private lateinit var binding: DialogNewKeyStoreBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = DialogNewKeyStoreBinding.inflate(inflater)
return binding.root
}
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog?.window?.setLayout(
(resources.displayMetrics.widthPixels * 0.85f).toInt(),
LinearLayout.LayoutParams.WRAP_CONTENT
)
dialog?.setCanceledOnTouchOutside(true)
val signatureAlgorithms = arrayOf("MD5withRSA", "SHA1withRSA", "SHA256withRSA", "SHA512withRSA")
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, signatureAlgorithms)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
binding.signatureAlgorithms.adapter = adapter
binding.confirm.setOnClickListener {
var error = false
val filename = binding.filename.text.toString()
val password = binding.password.text.toString()
val alias = binding.alias.text.toString()
val aliasPassword = binding.aliasPassword.text.toString()
var valvalidityYears = 25
// 检查文件名是否符合Android命名规格
when {
filename.isEmpty() -> {
binding.filenameTextInputLayout.error = getString(R.string.text_filename_cannot_be_empty)
error = true
}
!containsSpecialCharacters(filename) -> {
binding.filenameTextInputLayout.error = getString(R.string.text_filename_cannot_contain_invalid_character)
error = true
}
filename.length > 255 -> {
binding.filenameTextInputLayout.error = getString(R.string.text_filename_is_too_long)
error = true
}
else -> binding.filenameTextInputLayout.error = null
}
// 检查密码是否符合要求
when {
password.isEmpty() -> {
binding.passwordTextInputLayout.error = getString(R.string.text_password_cannot_be_empty)
error = true
}
password.length < 6 -> {
binding.passwordTextInputLayout.error = getString(R.string.text_password_requires_at_least_n_characters, 6)
error = true
}
else -> binding.passwordTextInputLayout.error = null
}
// 检查别名密码是否符合要求
when {
aliasPassword.isEmpty() -> {
binding.aliasPasswordTextInputLayout.error = getString(R.string.text_password_cannot_be_empty)
error = true
}
aliasPassword.length < 6 -> {
binding.aliasPasswordTextInputLayout.error = getString(R.string.text_password_requires_at_least_n_characters, 6)
error = true
}
else -> binding.aliasPasswordTextInputLayout.error = null
}
// 检查别名是否符合要求
if (alias.isEmpty()) {
binding.aliasTextInputLayout.error = getString(R.string.text_alias_cannot_be_empty)
error = true
} else {
binding.aliasTextInputLayout.error = null
}
// 检查有效期是否符合要求
if (binding.validityYears.text.toString().isEmpty()) {
binding.validityYearsTextInputLayout.error = getString(R.string.text_validity_years_cannot_be_empty)
error = true
} else {
val years = binding.validityYears.text.toString().toInt()
if (years == 0) {
binding.validityYearsTextInputLayout.error = getString(R.string.text_validity_years_cannot_be_zero)
error = true
} else {
binding.validityYearsTextInputLayout.error = null
valvalidityYears = years
}
}
val firstAndLastName = binding.firstAndLastName.text.toString()
val organization = binding.organization.text.toString()
val organizationalUnit = binding.organizationalUnit.text.toString()
val countryCode = binding.countryCode.text.toString()
val stateOrProvince = binding.stateOrProvince.text.toString()
val cityOrLocality = binding.cityOrLocality.text.toString()
val street = binding.street.text.toString()
if (firstAndLastName.isEmpty() && organization.isEmpty() &&
organizationalUnit.isEmpty() && stateOrProvince.isEmpty() &&
cityOrLocality.isEmpty() && street.isEmpty() && countryCode.isEmpty()
) {
binding.firstAndLastNameTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.organizationTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.organizationalUnitTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.countryCodeTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.stateOrProvinceTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.cityOrLocalityTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
binding.streetTextInputLayout.error = getString(R.string.text_at_least_one_certificate_issuer_field_is_not_empty)
error = true
} else {
binding.firstAndLastNameTextInputLayout.error = null
binding.organizationTextInputLayout.error = null
binding.organizationalUnitTextInputLayout.error = null
binding.countryCodeTextInputLayout.error = null
binding.stateOrProvinceTextInputLayout.error = null
binding.cityOrLocalityTextInputLayout.error = null
binding.streetTextInputLayout.error = null
}
// 检查国家代码是否符合要求 (ISO3166-1-Alpha-2: https://countrycodedata.com/)
val countryCodeRegex = "^[A-Z]{2}$".toRegex()
if (countryCode.isNotEmpty() && !countryCodeRegex.matches(countryCode)) {
binding.countryCodeTextInputLayout.error = getString(R.string.text_country_code_must_be_two_capital_letters)
error = true
}
if (error) return@setOnClickListener
val suffix = getString(
if (binding.typeJks.isChecked) R.string.text_jks
else R.string.text_bks
).lowercase()
val signatureAlgorithm = binding.signatureAlgorithms.selectedItem.toString()
val configs = NewKeyStoreConfigs(
filename = "$filename.$suffix",
password = password,
alias = alias,
aliasPassword = aliasPassword,
signatureAlgorithm = signatureAlgorithm,
validityYears = valvalidityYears,
firstAndLastName = firstAndLastName,
organization = organization,
organizationalUnit = organizationalUnit,
countryCode = countryCode,
stateOrProvince = stateOrProvince,
cityOrLocality = cityOrLocality,
street = street
)
callback.onConfirmButtonClicked(configs)
dismiss()
}
binding.cancel.setOnClickListener {
dismiss()
}
binding.moreOptions.setOnCheckedChangeListener { _, isChecked ->
binding.moreOptionsContainer.visibility = if (isChecked) View.VISIBLE else View.GONE
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
}
}
}
private fun containsSpecialCharacters(fileName: String): Boolean {
// 定义不允许的字符
val invalidCharacters = listOf("\\", "/", ":", "*", "?", "\"", "<", ">", "|")
// 检查文件名是否包含无效字符
for (char in invalidCharacters) {
if (fileName.contains(char)) {
return false
}
}
return true
}
data class NewKeyStoreConfigs(
val filename: String,
val password: String,
val alias: String,
val aliasPassword: String,
val signatureAlgorithm: String,
val validityYears: Int,
val firstAndLastName: String,
val organizationalUnit: String,
val organization: String,
val countryCode: String,
val stateOrProvince: String,
val cityOrLocality: String,
val street: String,
)
interface Callback {
fun onConfirmButtonClicked(configs: NewKeyStoreConfigs)
}
}

View File

@@ -0,0 +1,134 @@
package org.autojs.autojs.ui.keystore
import android.annotation.SuppressLint
import android.app.Dialog
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.LinearLayout
import androidx.fragment.app.DialogFragment
import org.autojs.autojs.apkbuilder.keystore.AESUtils
import org.autojs.autojs.apkbuilder.keystore.KeyStore
import org.autojs.autojs6.R
import org.autojs.autojs6.databinding.DialogVerifyKeyStoreBinding
open class VerifyKeyStoreDialog(
private val callback: Callback,
private val keyStore: KeyStore,
) : DialogFragment() {
private lateinit var binding: DialogVerifyKeyStoreBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View {
binding = DialogVerifyKeyStoreBinding.inflate(inflater)
return binding.root
}
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dialog?.window?.setLayout(
(resources.displayMetrics.widthPixels * 0.85f).toInt(),
LinearLayout.LayoutParams.WRAP_CONTENT
)
dialog?.setCanceledOnTouchOutside(true)
binding.filePath.text = keyStore.absolutePath
if (keyStore.verified) {
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_verified)
binding.textVerifyState.text = getString(R.string.text_verified)
binding.password.setText(AESUtils.decrypt(keyStore.password))
binding.alias.setText(keyStore.alias)
binding.aliasPassword.setText(AESUtils.decrypt(keyStore.aliasPassword))
} else {
binding.imgVerifyState.setImageResource(R.drawable.ic_key_store_unverified)
binding.textVerifyState.text = getString(R.string.text_unverified)
}
binding.verify.setOnClickListener {
var error = false
val password = binding.password.text.toString()
val alias = binding.alias.text.toString()
val aliasPassword = binding.aliasPassword.text.toString()
// 检查密码是否符合要求
when {
password.isEmpty() -> {
binding.passwordTextInputLayout.error = getString(R.string.text_password_cannot_be_empty)
error = true
}
password.length < 6 -> {
binding.passwordTextInputLayout.error = getString(R.string.text_password_requires_at_least_n_characters, 6)
error = true
}
else -> binding.passwordTextInputLayout.error = null
}
// 检查别名密码是否符合要求
when {
aliasPassword.isEmpty() -> {
binding.aliasPasswordTextInputLayout.error = getString(R.string.text_password_cannot_be_empty)
error = true
}
aliasPassword.length < 6 -> {
binding.aliasPasswordTextInputLayout.error = getString(R.string.text_password_requires_at_least_n_characters, 6)
error = true
}
else -> binding.aliasPasswordTextInputLayout.error = null
}
// 检查别名是否符合要求
if (alias.isEmpty()) {
binding.aliasTextInputLayout.error = getString(R.string.text_alias_cannot_be_empty)
error = true
} else {
binding.aliasTextInputLayout.error = null
}
if (error) return@setOnClickListener
val configs = VerifyKeyStoreConfigs(
password = password,
alias = alias,
aliasPassword = aliasPassword,
)
callback.onVerifyButtonClicked(configs, keyStore)
dismiss()
}
binding.cancel.setOnClickListener {
dismiss()
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return super.onCreateDialog(savedInstanceState).apply {
window?.apply {
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
}
}
}
data class VerifyKeyStoreConfigs(
val password: String,
val alias: String,
val aliasPassword: String,
)
interface Callback {
fun onVerifyButtonClicked(configs: VerifyKeyStoreConfigs, keyStore: KeyStore)
}
}

View File

@@ -9,14 +9,20 @@ import android.text.Editable;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.widget.CheckBox;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import com.afollestad.materialdialogs.MaterialDialog;
import com.google.android.flexbox.FlexboxLayout;
import com.google.android.material.textfield.TextInputLayout;
@@ -35,6 +41,9 @@ import org.autojs.autojs.runtime.api.augment.pinyin.Pinyin;
import org.autojs.autojs.ui.BaseActivity;
import org.autojs.autojs.ui.common.NotAskAgainDialog;
import org.autojs.autojs.ui.filechooser.FileChooserDialogBuilder;
import org.autojs.autojs.apkbuilder.keystore.KeyStore;
import org.autojs.autojs.ui.viewmodel.KeyStoreViewModel;
import org.autojs.autojs.ui.keystore.ManageKeyStoreActivity;
import org.autojs.autojs.ui.shortcut.AppsIconSelectActivity;
import org.autojs.autojs.ui.widget.RoundCheckboxWithText;
import org.autojs.autojs.util.AndroidUtils;
@@ -56,6 +65,8 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.regex.Pattern;
@@ -109,6 +120,61 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
put(ApkBuilder.Constants.MLKIT_BARCODE, /* MLKit Barcode */ List.of("barcode", "mlkit-barcode", "mlkit_barcode"));
}};
private static final ArrayList<String> SIGNATURE_SCHEMES = new ArrayList<>() {{
add("V1 + V2");
add("V1 + V3");
add("V1 + V2 + V3");
add("V1");
add("V2 + V3 (Android 7.0+)");
add("V2 (Android 7.0+)");
add("V3 (Android 9.0+)");
}};
private final Map<String, Integer> SUPPORTED_PERMISSIONS = new TreeMap<>() {{
put("android.permission.ACCESS_COARSE_LOCATION", R.string.text_permission_access_coarse_location);
put("android.permission.ACCESS_FINE_LOCATION", R.string.text_permission_access_fine_location);
put("android.permission.ACCESS_NETWORK_STATE", R.string.text_permission_access_network_state);
put("android.permission.ACCESS_WIFI_STATE", R.string.text_permission_access_wifi_state);
put("android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS", R.string.text_permission_broadcast_close_system_dialogs);
put("android.permission.CAPTURE_VIDEO_OUTPUT", R.string.text_permission_capture_video_output);
put("android.permission.DUMP", R.string.text_permission_dump);
put("android.permission.FOREGROUND_SERVICE", R.string.text_permission_foreground_service);
put("android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION", R.string.text_permission_foreground_service_media_projection);
put("android.permission.FOREGROUND_SERVICE_SPECIAL_USE", R.string.text_permission_foreground_service_special_use);
put("android.permission.INTERNET", R.string.text_permission_internet);
put("android.permission.INTERACT_ACROSS_USERS_FULL", R.string.text_permission_interact_across_users_full);
put("android.permission.MANAGE_EXTERNAL_STORAGE", R.string.text_permission_manage_external_storage);
put("android.permission.MANAGE_USERS", R.string.text_permission_manage_users);
put("android.permission.POST_NOTIFICATIONS", R.string.text_permission_post_notifications);
put("android.permission.QUERY_ALL_PACKAGES", R.string.text_permission_query_all_packages);
put("android.permission.READ_EXTERNAL_STORAGE", R.string.text_permission_read_external_storage);
put("android.permission.READ_MEDIA_AUDIO", R.string.text_permission_read_media_audio);
put("android.permission.READ_MEDIA_IMAGES", R.string.text_permission_read_media_images);
put("android.permission.READ_MEDIA_VIDEO", R.string.text_permission_read_media_video);
put("android.permission.READ_PHONE_STATE", R.string.text_permission_read_phone_state);
put("android.permission.READ_PRIVILEGED_PHONE_STATE", R.string.text_permission_read_privileged_phone_state);
put("android.permission.READ_SMS", R.string.text_permission_read_sms);
put("android.permission.RECEIVE_BOOT_COMPLETED", R.string.text_permission_receive_boot_completed);
put("android.permission.RECORD_AUDIO", R.string.text_permission_record_audio);
put("android.permission.REORDER_TASKS", R.string.text_permission_reorder_tasks);
put("android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS", R.string.text_permission_request_ignore_battery_optimizations);
put("android.permission.REQUEST_INSTALL_PACKAGES", R.string.text_permission_request_install_packages);
put("android.permission.SCHEDULE_EXACT_ALARM", R.string.text_permission_schedule_exact_alarm);
put("android.permission.SYSTEM_ALERT_WINDOW", R.string.text_permission_system_alert_window);
put("android.permission.UNLIMITED_TOASTS", R.string.text_permission_unlimited_toasts);
put("android.permission.UNINSTALL_SHORTCUT", R.string.text_permission_uninstall_shortcut);
put("android.permission.USE_EXACT_ALARM", R.string.text_permission_use_exact_alarm);
put("android.permission.VIBRATE", R.string.text_permission_vibrate);
put("android.permission.WAKE_LOCK", R.string.text_permission_wake_lock);
put("android.permission.WRITE_EXTERNAL_STORAGE", R.string.text_permission_write_external_storage);
put("android.permission.WRITE_SECURE_SETTINGS", R.string.text_permission_write_secure_settings);
put("android.permission.WRITE_SETTINGS", R.string.text_permission_write_settings);
put("com.android.launcher.permission.INSTALL_SHORTCUT", R.string.text_permission_install_shortcut);
put("com.android.launcher.permission.UNINSTALL_SHORTCUT", R.string.text_permission_uninstall_shortcut);
put("com.termux.permission.RUN_COMMAND", R.string.text_permission_run_command);
put("moe.shizuku.manager.permission.API_V23", R.string.text_permission_shizuku);
}};
EditText mSourcePath;
View mSourcePathContainer;
EditText mOutputPath;
@@ -129,6 +195,9 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
private boolean mIsProjectLevelBuilding;
private FlexboxLayout mFlexboxAbis;
private FlexboxLayout mFlexboxLibs;
private Spinner mSignatureSchemes;
private Spinner mVerifiedKeyStores;
private FlexboxLayout mFlexboxPermissions;
private final ArrayList<String> mInvalidAbis = new ArrayList<>();
private final ArrayList<String> mUnavailableAbis = new ArrayList<>();
@@ -136,6 +205,8 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
private final ArrayList<String> mInvalidLibs = new ArrayList<>();
private final ArrayList<String> mUnavailableLibs = new ArrayList<>();
private KeyStoreViewModel mKeyStoreViewModel;
@SuppressLint("SetTextI18n")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
@@ -202,6 +273,18 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
mFlexboxLibs = binding.flexboxLibraries;
initLibsChildren();
mKeyStoreViewModel = new ViewModelProvider(this, new KeyStoreViewModel.Factory(getApplicationContext())).get(KeyStoreViewModel.class);
mKeyStoreViewModel.updateVerifiedKeyStores();
mSignatureSchemes = binding.spinnerSignatureSchemes;
initSignatureSchemeSpinner();
mVerifiedKeyStores = binding.spinnerVerifiedKeyStores;
initVerifiedKeyStoresSpinner();
mFlexboxPermissions = binding.flexboxPermissions;
initPermissionsChildren();
binding.fab.setOnClickListener(v -> buildApk());
binding.selectSource.setOnClickListener(v -> selectSourceFilePath());
binding.selectOutput.setOnClickListener(v -> selectOutputDirPath());
@@ -211,6 +294,8 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
return true;
});
binding.textLibs.setOnClickListener(v -> toggleAllFlexboxChildren(mFlexboxLibs));
binding.manageKeyStore.setOnClickListener(v -> ManageKeyStoreActivity.Companion.startActivity(this));
binding.textPermissions.setOnClickListener(v -> toggleAllFlexboxChildren(mFlexboxPermissions));
setToolbarAsBack(R.string.text_build_apk);
mSource = getIntent().getStringExtra(EXTRA_SOURCE);
@@ -224,6 +309,12 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
showHintDialogIfNeeded();
}
@Override
protected void onResume() {
super.onResume();
mKeyStoreViewModel.updateVerifiedKeyStores();
}
private void toggleAllFlexboxChildren(FlexboxLayout mFlexboxLibs) {
boolean isAllChecked = true;
for (int i = 0; i < mFlexboxLibs.getChildCount(); i += 1) {
@@ -236,6 +327,14 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
isAllChecked = false;
break;
}
} else if (child instanceof CheckBox) {
if (!child.isEnabled()) {
continue;
}
if (!((CheckBox) child).isChecked()) {
isAllChecked = false;
break;
}
}
}
for (int i = 0; i < mFlexboxLibs.getChildCount(); i += 1) {
@@ -245,6 +344,11 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
continue;
}
((RoundCheckboxWithText) child).setChecked(!isAllChecked);
} else if (child instanceof CheckBox) {
if (!child.isEnabled()) {
continue;
}
((CheckBox) child).setChecked(!isAllChecked);
}
}
}
@@ -348,6 +452,51 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
mInvalidLibs.addAll(candidates);
}
private void initSignatureSchemeSpinner() {
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, SIGNATURE_SCHEMES);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSignatureSchemes.setAdapter(adapter);
}
private void initVerifiedKeyStoresSpinner() {
ArrayList<KeyStore> verifiedKeyStores = new ArrayList<>();
// 添加 默认密钥库 下拉选项
KeyStore defaultKeyStore = new KeyStore("", getString(R.string.text_default_key_store), "", "", "", false); // 仅用于显示下拉列表
verifiedKeyStores.add(defaultKeyStore);
ArrayAdapter<KeyStore> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, verifiedKeyStores);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mVerifiedKeyStores.setAdapter(adapter);
mKeyStoreViewModel.getVerifiedKeyStores().observe(this, keyStores -> {
// 清空现有的选项,但保留第一个元素,即默认密钥库
if (verifiedKeyStores.size() > 1) {
verifiedKeyStores.subList(1, verifiedKeyStores.size()).clear();
}
verifiedKeyStores.addAll(keyStores);
adapter.notifyDataSetChanged();
});
}
@SuppressLint("SetTextI18n")
private void initPermissionsChildren() {
SUPPORTED_PERMISSIONS.forEach((permission, descriptionResId) -> {
CheckBox checkBox = new CheckBox(this);
checkBox.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
checkBox.setAlpha(0.87f);
checkBox.setText(permission + "\n" + getString(descriptionResId));
checkBox.setButtonDrawable(R.drawable.round_checkbox);
checkBox.setGravity(Gravity.CENTER_VERTICAL);
checkBox.setTextSize(12);
int marginInPixels = (int) (8 * getResources().getDisplayMetrics().density);
checkBox.setPadding(marginInPixels, 0, 0, 0);
checkBox.setChecked(false);
mFlexboxPermissions.addView(checkBox);
});
}
private boolean isAliasMatching(Map<String, List<String>> aliases, String aliasKey, List<String> candidates) {
AtomicBoolean result = new AtomicBoolean(false);
var aliasList = aliases.getOrDefault(aliasKey, Collections.emptyList());
@@ -650,6 +799,7 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
private ApkBuilder.AppConfig createAppConfig() {
ArrayList<String> abis = collectCheckedItems(mFlexboxAbis);
ArrayList<String> libs = collectCheckedItems(mFlexboxLibs);
ArrayList<String> permissions = collectCheckedItems(mFlexboxPermissions);
ApkBuilder.AppConfig appConfig = mProjectConfig != null
? ApkBuilder.AppConfig.fromProjectConfig(mSource, mProjectConfig)
@@ -663,6 +813,13 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
appConfig.setAbis(abis);
appConfig.setLibs(libs);
appConfig.setSignatureSchemes(mSignatureSchemes.getSelectedItem().toString());
if (mVerifiedKeyStores.getSelectedItemPosition() > 0) {
appConfig.setKeyStore((KeyStore) mVerifiedKeyStores.getSelectedItem());
} else {
appConfig.setKeyStore(null);
}
appConfig.setPermissions(permissions);
return appConfig;
}
@@ -680,6 +837,13 @@ public class BuildActivity extends BaseActivity implements ApkBuilder.ProgressCa
libs.add(charSequence.toString());
}
}
} else if (child instanceof CheckBox) {
if (((CheckBox) child).isChecked()) {
CharSequence charSequence = ((CheckBox) child).getText();
if (charSequence != null) {
libs.add(charSequence.toString().split("\n")[0]);
}
}
}
}
return libs;

View File

@@ -0,0 +1,104 @@
package org.autojs.autojs.ui.viewmodel
import android.content.Context
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import org.autojs.autojs.apkbuilder.keystore.KeyStore
import org.autojs.autojs.apkbuilder.keystore.KeyStoreRepository
import java.io.File
class KeyStoreViewModel(context: Context) : ViewModel() {
private val keyStoreRepository: KeyStoreRepository = KeyStoreRepository(context)
private val _allKeyStores = MutableLiveData<List<KeyStore>>()
val allKeyStores: LiveData<List<KeyStore>> get() = _allKeyStores
private val _verifiedKeyStores = MutableLiveData<List<KeyStore>>()
val verifiedKeyStores: LiveData<List<KeyStore>> get() = _verifiedKeyStores
init {
updateVerifiedKeyStores()
}
fun updateVerifiedKeyStores() {
viewModelScope.launch {
val keyStores = keyStoreRepository.getAllKeyStores()
val validKeyStores = mutableListOf<KeyStore>()
keyStores.forEach { keyStore ->
val file = File(keyStore.absolutePath)
if (file.exists()) {
validKeyStores.add(keyStore)
} else {
keyStoreRepository.deleteKeyStores(keyStore)
}
}
_verifiedKeyStores.value = validKeyStores
}
}
fun updateAllKeyStoresFromFiles(files: Array<File>) {
viewModelScope.launch {
val updatedKeyStores = files.map { file ->
keyStoreRepository.getKeyStoreAbsolutePath(file.absolutePath) ?: KeyStore(
absolutePath = file.absolutePath,
filename = file.name
)
}
_allKeyStores.value = updatedKeyStores
}
}
fun upsertKeyStore(keyStore: KeyStore) {
viewModelScope.launch {
keyStoreRepository.upsertKeyStores(keyStore)
val currentKeyStores = _allKeyStores.value ?: emptyList()
val updatedKeyStores =
if (currentKeyStores.any { it.absolutePath == keyStore.absolutePath }) {
currentKeyStores.map {
if (keyStore.absolutePath == it.absolutePath) {
keyStore
} else {
it
}
}
} else {
currentKeyStores + keyStore
}
_allKeyStores.value = updatedKeyStores
}
}
fun deleteKeyStore(keyStore: KeyStore) {
viewModelScope.launch {
keyStoreRepository.deleteKeyStores(keyStore)
val currentKeyStores = _allKeyStores.value ?: emptyList()
val updatedKeyStores = currentKeyStores.filter { it != keyStore }
_allKeyStores.value = updatedKeyStores
}
}
fun deleteAllKeyStores() {
viewModelScope.launch {
keyStoreRepository.deleteAllKeyStores()
_allKeyStores.value = emptyList()
}
}
@Suppress("UNCHECKED_CAST")
class Factory(private val context: Context) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return KeyStoreViewModel(context) as T
}
}
}

View File

@@ -94,6 +94,9 @@ public class AxmlWriter extends AxmlVisitor {
int size = 0;
for (NodeImpl first : firsts) {
if (first.ignore) {
continue;
}
size += first.prepare(this);
}
int a = 0;
@@ -163,6 +166,9 @@ public class AxmlWriter extends AxmlVisitor {
}
for (NodeImpl first : firsts) {
if (first.ignore) {
continue;
}
first.write(out);
}
@@ -259,10 +265,11 @@ public class AxmlWriter extends AxmlVisitor {
Attr clz;
protected List<NodeImpl> children = new ArrayList<NodeImpl>();
private int line;
private StringItem name;
protected StringItem name;
private StringItem ns;
private StringItem text;
private int textLineNumber;
protected boolean ignore = false;
public NodeImpl(String ns, String name) {
super(null);
@@ -344,6 +351,9 @@ public class AxmlWriter extends AxmlVisitor {
int size = 24 + 36 + attrs.size() * 20;// 24 for end tag,36+x*20 for
// start tag
for (NodeImpl child : children) {
if (child.ignore) {
continue;
}
size += child.prepare(axmlWriter);
}
if (text != null) {
@@ -400,6 +410,9 @@ public class AxmlWriter extends AxmlVisitor {
// children
for (NodeImpl child : children) {
if (child.ignore) {
continue;
}
child.write(out);
}

View File

@@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="48"
android:viewportHeight="48">
<path
android:fillColor="@android:color/white"
android:pathData="M16.9,25.2h0c-0.2,0.8 -0.6,2.1 -1.1,3.6h2.3c-0.6,-1.7 -1,-2.9 -1.2,-3.6Z" />
<path
android:fillColor="@android:color/white"
android:pathData="M32.1,5.5l-2.3,-2.3l-11.6,0l-2.3,2.3l-8.1,0l0,4.6l32.4,0l0,-4.6l-8.1,0z" />
<path
android:fillColor="@android:color/white"
android:pathData="M10.1,40.2c0,2.6 2.1,4.6 4.6,4.6h18.5c2.6,0 4.6,-2.1 4.6,-4.6V12.4H10.1v27.7ZM29.1,23.9h1.8v6.8h4.1l-0.2,1.5h-5.7v-8.3ZM22.1,23.9h1.8v6.8h4.1l-0.2,1.5h-5.7v-8.3ZM15.8,23.9h2.2l2.9,8.3h-1.9l-0.7,-1.9h-3l-0.6,1.9h-1.8l2.8,-8.3Z" />
</vector>

View File

@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="48dp" android:tint="#999999" android:viewportHeight="24" android:viewportWidth="24" android:width="48dp">
<path android:fillColor="@android:color/white" android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M512.2,32L947.2,155.8v261c0,253.3 -162.4,478.7 -404.9,565.1l-17,5.8 -13.2,4.3 -13.2,-4.3c-246.1,-79.9 -414.3,-301.3 -421.8,-553.3L76.8,416.8L76.8,155.8L512.2,32zM506,668.9a56.4,56.4 0,0 0,-41.2 15.6,51.6 51.6,0 0,0 -16.6,39.9c0,15.6 5.6,28.9 16.6,39.9a57,57 0,0 0,41.2 16.4c15.9,0 30.1,-5.5 41.2,-15.7a55.2,55.2 0,0 0,17.4 -40.6,51.6 51.6,0 0,0 -16.6,-39.9c-11.1,-10.9 -25.3,-15.6 -41.9,-15.6zM520.3,211.2c-58.6,0 -104.4,16.4 -137.7,50 -33.3,32.9 -49.9,77.4 -49.9,134.6h83.1c0,-34.4 7.1,-61 21.4,-79.8 15.8,-22.7 41.9,-33.7 77.5,-33.7 28.5,0 51.5,7.9 67.3,23.5 15,15.7 23,36.8 23,64.2 0,20.4 -7.9,39.1 -22.2,57.1l-13.4,14.8C520.3,485.1 490.2,517.1 480,539c-11.1,20.4 -15.8,45.4 -15.8,74.4v13.3h84.7v-13.3c0,-18.8 4,-36 12.7,-51.6 7,-14.1 18.2,-28.2 33.2,-40.7 37.1,-32.1 59.3,-52.4 66.4,-61 19.8,-25.1 30.1,-57.2 30.1,-95.5 0,-46.9 -15.8,-84.5 -47.5,-111.9 -31.6,-28.2 -72.8,-41.5 -123.4,-41.5z"
android:fillColor="#2D9AFF"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M512.2,32L947.2,155.8v261c0,253.3 -162.4,478.7 -404.9,565.1l-17,5.8 -13.2,4.3 -13.2,-4.3c-246.1,-79.9 -414.3,-301.3 -421.8,-553.3L76.8,416.8V155.8L512.2,32zM726.4,320L459.8,582 304,428.9l-60.8,62.2L459.8,704 787.2,382.3 726.4,320z"
android:fillColor="#00C25A"/>
</vector>

View File

@@ -319,6 +319,120 @@
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="0dp"
android:paddingBottom="16dp">
<TextView
android:id="@+id/text_apk_sign_configs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:paddingHorizontal="16dp"
android:text="@string/text_signature_configuration"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="?android:textColorSecondary" />
<GridLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:orientation="horizontal"
android:paddingStart="16dp"
android:paddingEnd="0dp"
android:rowCount="3">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_row="0"
android:layout_column="0"
android:text="@string/text_signature_scheme" />
<Spinner
android:id="@+id/spinner_signature_schemes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_row="0"
android:layout_column="1"
android:layout_columnWeight="1"
android:paddingVertical="4dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_row="1"
android:layout_column="0"
android:text="@string/text_key_store" />
<Spinner
android:id="@+id/spinner_verified_key_stores"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_row="1"
android:layout_column="1"
android:layout_columnWeight="1"
android:paddingVertical="4dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_row="2"
android:layout_column="0"
android:text="@string/text_others" />
<TextView
android:id="@+id/manage_key_store"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_row="2"
android:layout_column="1"
android:layout_columnWeight="1"
android:background="?selectableItemBackground"
android:paddingHorizontal="8dp"
android:paddingVertical="4dp"
android:text="@string/text_manage_key_store"
android:textColor="@color/colorPrimary"
android:textSize="16sp"
android:textStyle="bold" />
</GridLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="0dp"
android:paddingBottom="16dp">
<TextView
android:id="@+id/text_permissions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:paddingHorizontal="16dp"
android:text="@string/text_supported_permissions_short"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="?android:textColorSecondary" />
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/flexbox_permissions"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start|top"
android:layout_marginBottom="4dp"
android:paddingHorizontal="16dp"
app:alignContent="center"
app:dividerDrawable="@drawable/round_checkbox_with_text_divider"
app:flexDirection="column"
app:flexWrap="wrap"
app:showDivider="middle" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="72dp"

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<org.autojs.autojs.theme.widget.ThemeColorToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ToolBarStyle" />
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp">
<org.autojs.autojs.theme.widget.ThemeColorSwipeRefreshLayout
android:id="@+id/swipe_refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</org.autojs.autojs.theme.widget.ThemeColorSwipeRefreshLayout>
<org.autojs.autojs.theme.widget.ThemeColorFloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="16dp"
android:alpha="0.9"
android:src="@drawable/ic_add_white_48dp"
android:tint="@color/toolbar_text"
app:backgroundTint="?attr/colorPrimary"
app:layout_anchor="@id/viewpager"
app:layout_anchorGravity="bottom|end"
app:layout_behavior="org.autojs.autojs.ui.widget.ScrollAwareFABBehavior" />
</FrameLayout>
</LinearLayout>

View File

@@ -0,0 +1,317 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/type_radio_group"
android:text="@string/text_new_key_store"
android:textColor="@color/text_color_primary"
android:textSize="24sp" />
<RadioGroup
android:id="@+id/type_radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="4dp"
android:orientation="horizontal"
tools:ignore="RelativeOverlap">
<RadioButton
android:id="@+id/type_jks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/text_jks"
android:textSize="16sp" />
<RadioButton
android:id="@+id/type_bks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="@string/text_bks"
android:textSize="16sp" />
</RadioGroup>
</RelativeLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/filename_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_file_name">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_key_store_password"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/alias_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_key_alias">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/alias"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_default_alias"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/alias_password_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_alias_password"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/alias_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/more_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:layout_marginBottom="8dp"
android:gravity="center_vertical|start"
android:text="@string/text_more"
android:textAlignment="viewStart" />
<LinearLayout
android:id="@+id/more_options_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginBottom="8dp"
android:text="@string/text_signature_algorithm"
android:textSize="11sp" />
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/signature_algorithms"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="-4dp"
android:textAlignment="viewStart"
android:textColor="@color/text_color_primary"
android:textSize="16sp" />
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/validity_years_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_validity_years">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/validity_years"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:text="@string/text_default_validity_years"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/first_and_last_name_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_first_and_last_name">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/first_and_last_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/organization_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_organization">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/organization"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/organizational_unit_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_organizational_unit">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/organizational_unit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/country_code_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_country_code">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/country_code"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_default_country_code"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/state_or_province_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_state_or_province">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/state_or_province"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/city_or_locality_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_city_or_locality">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/city_or_locality"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/street_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_street">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/street"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="end"
android:orientation="horizontal">
<Button
android:id="@+id/cancel"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:elegantTextHeight="true"
android:text="@string/text_cancel" />
<Button
android:id="@+id/confirm"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:elegantTextHeight="true"
android:text="@string/text_ok" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,163 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:layout_toStartOf="@+id/container_verify_state"
android:text="@string/text_verify_key_store"
android:textColor="@color/text_color_primary"
android:textSize="24sp" />
<LinearLayout
android:id="@+id/container_verify_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:gravity="center_horizontal"
android:orientation="vertical"
tools:ignore="RelativeOverlap,UseCompoundDrawables">
<ImageView
android:id="@+id/img_verify_state"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/text_verify_key_store"
android:padding="4dp"
android:src="@drawable/ic_key_store_unverified"
tools:src="@drawable/ic_key_store_verified" />
<TextView
android:id="@+id/text_verify_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_unverified"
android:textColor="@color/text_color_primary"
android:textSize="12sp" />
</LinearLayout>
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginBottom="8dp"
android:text="@string/text_file_path"
android:textSize="11sp" />
<TextView
android:id="@+id/file_path"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:textSize="16sp"
tools:text="/storage/emulated/0/脚本/.KeyStore/default_key_store.jks" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_key_store_password"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/alias_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_key_alias">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/alias"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_default_alias"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/alias_password_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/text_alias_password"
app:endIconMode="password_toggle">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/alias_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="@color/text_color_primary" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="end"
android:orientation="horizontal">
<Button
android:id="@+id/cancel"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:elegantTextHeight="true"
android:text="@string/text_cancel" />
<Button
android:id="@+id/verify"
style="@style/Base.Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginTop="8dp"
android:elegantTextHeight="true"
android:text="@string/text_verify" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:layout_marginTop="3dp"
android:layout_marginEnd="6dp"
android:layout_marginBottom="3dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardCornerRadius="4dp"
app:cardElevation="1dp"
app:cardUseCompatPadding="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:orientation="vertical"
tools:ignore="RelativeOverlap">
<TextView
android:id="@+id/filename"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary"
tools:text="filename" />
<TextView
android:id="@+id/alias"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/text_color_primary"
tools:text="filename" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/verify"
android:layout_width="32dp"
android:layout_height="32dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/text_verify_key_store"
android:focusable="true"
android:padding="6dp"
android:src="@drawable/ic_key_store_unverified"
tools:src="@drawable/ic_key_store_verified" />
<ImageView
android:id="@+id/delete"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="8dp"
android:background="?selectableItemBackgroundBorderless"
android:clickable="true"
android:contentDescription="@string/text_delete"
android:focusable="true"
android:padding="4dp"
android:src="@drawable/ic_key_store_delete"
app:tint="@color/md_red_500" />
</LinearLayout>
</RelativeLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_delete_all"
android:icon="@drawable/ic_delete_all"
android:title="@string/text_delete_all"
app:showAsAction="always" />
</menu>

View File

@@ -759,6 +759,88 @@
<string name="text_supported_abis_short_32bit">ABIs (32 بت)</string>
<string name="text_supported_abis_short_64bit">ABIs (64 بت)</string>
<string name="text_supported_libraries_short">المكتبات</string>
<string name="text_signature_configuration">تكوين التوقيع</string>
<string name="text_key_store">مخزن المفاتيح</string>
<string name="text_default_key_store">مخزن المفاتيح الافتراضي</string>
<string name="text_manage_key_store">إدارة مخزن المفاتيح</string>
<string name="text_signature_scheme">خطة التوقيع</string>
<string name="text_new_key_store">إنشاء مفتاح التوقيع</string>
<string name="text_key_store_password">كلمة مرور مخزن المفاتيح</string>
<string name="text_key_alias">الاسم المستعار</string>
<string name="text_alias_password">كلمة مرور الاسم المستعار</string>
<string name="text_signature_algorithm">خوارزمية التوقيع</string>
<string name="text_validity_years">المدة (سنوات)</string>
<string name="text_first_and_last_name">الاسم</string>
<string name="text_organization">اسم المنظمة</string>
<string name="text_organizational_unit">وحدة التنظيم</string>
<string name="text_country_code">رمز الدولة (XX)</string>
<string name="text_state_or_province">الولاية أو المقاطعة</string>
<string name="text_city_or_locality">المدينة أو المنطقة</string>
<string name="text_street">الشارع</string>
<string name="text_filename_cannot_be_empty">اسم الملف لا يمكن أن يكون فارغًا</string>
<string name="text_filename_cannot_contain_invalid_character">اسم الملف لا يمكن أن يحتوي على أي من الأحرف التالية: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">اسم الملف طويل جدًا</string>
<string name="text_password_requires_at_least_n_characters">يجب أن يحتوي كلمة المرور على %d على الأقل من الأحرف</string>
<string name="text_alias_cannot_be_empty">الاسم المستعار لا يمكن أن يكون فارغًا</string>
<string name="text_validity_years_cannot_be_empty">مدة الصلاحية لا يمكن أن تكون فارغة</string>
<string name="text_validity_years_cannot_be_zero">مدة الصلاحية لا يمكن أن تكون صفرًا</string>
<string name="text_country_code_must_be_two_capital_letters">رمز الدولة يجب أن يكون حرفين كبيرين</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">يجب ملء حقل واحد على الأقل من "الاسم، اسم المنظمة، وحدة التنظيم، رمز الدولة، الولاية أو المقاطعة، المدينة أو المنطقة، الشارع"</string>
<string name="text_successfully_created_key_store">تم إنشاء مفتاح التوقيع بنجاح</string>
<string name="text_failed_to_create_key_store">فشل في إنشاء مفتاح التوقيع</string>
<string name="text_key_store_has_not_been_verified">لم يتم التحقق من المخزن</string>
<string name="text_key_store_has_been_verified">تم التحقق من المخزن</string>
<string name="text_verify">التحقق</string>
<string name="text_delete_all">حذف الكل</string>
<string name="text_unverified">لم يتم التحقق</string>
<string name="text_verified">تم التحقق</string>
<string name="text_verify_key_store">التحقق من مخزن المفاتيح</string>
<string name="text_verify_success">تم التحقق بنجاح</string>
<string name="text_verify_failed">فشل التحقق</string>
<string name="text_file_path">مسار الملف</string>
<string name="text_supported_permissions_short">الأذونات المطلوبة</string>
<string name="text_permission_access_wifi_state">السماح للتطبيق بالوصول إلى حالة الواي فاي</string>
<string name="text_permission_write_external_storage">السماح للتطبيق بكتابة البيانات إلى التخزين الخارجي</string>
<string name="text_permission_read_external_storage">السماح للتطبيق بقراءة البيانات من التخزين الخارجي</string>
<string name="text_permission_read_media_images">السماح للتطبيق بقراءة ملفات الصور من التخزين المشترك</string>
<string name="text_permission_read_media_video">السماح للتطبيق بقراءة ملفات الفيديو من التخزين المشترك</string>
<string name="text_permission_read_media_audio">السماح للتطبيق بقراءة ملفات الصوت من التخزين المشترك</string>
<string name="text_permission_manage_external_storage">السماح للتطبيق بإدارة جميع الملفات في التخزين الخارجي</string>
<string name="text_permission_broadcast_close_system_dialogs">السماح للتطبيق بإرسال نية لإغلاق حوارات النظام</string>
<string name="text_permission_read_privileged_phone_state">السماح للتطبيق بالوصول إلى جميع معلومات حالة الهاتف</string>
<string name="text_permission_install_shortcut">السماح للتطبيق بتثبيت اختصار</string>
<string name="text_permission_uninstall_shortcut">السماح للتطبيق بإلغاء تثبيت الاختصار</string>
<string name="text_permission_request_install_packages">السماح للتطبيق بطلب تثبيت تطبيقات أخرى</string>
<string name="text_permission_wake_lock">السماح للتطبيق بمنع الهاتف من الدخول في وضع السكون</string>
<string name="text_permission_use_exact_alarm">السماح للتطبيق بجدولة المنبهات الدقيقة أو التنبيهات</string>
<string name="text_permission_schedule_exact_alarm">السماح للتطبيق بجدولة عمليات دقيقة بالوقت</string>
<string name="text_permission_vibrate">السماح للتطبيق بالتحكم في اهتزاز الهاتف</string>
<string name="text_permission_internet">السماح للتطبيق بالوصول إلى الإنترنت</string>
<string name="text_permission_access_network_state">السماح للتطبيق بمعرفة حالة الاتصال بالشبكة</string>
<string name="text_permission_system_alert_window">السماح للتطبيق بالظهور فوق التطبيقات الأخرى</string>
<string name="text_permission_reorder_tasks">السماح للتطبيق بإعادة ترتيب التطبيقات التي تعمل حالياً</string>
<string name="text_permission_request_ignore_battery_optimizations">السماح للتطبيق بطلب تجاهل تحسينات البطارية</string>
<string name="text_permission_receive_boot_completed">السماح للتطبيق بتلقي إشعارات عند اكتمال إقلاع الجهاز</string>
<string name="text_permission_post_notifications">السماح للتطبيق بعرض الإشعارات</string>
<string name="text_permission_foreground_service">السماح للتطبيق بتشغيل خدمة في المقدمة</string>
<string name="text_permission_foreground_service_media_projection">السماح للتطبيق باستخدام تسجيل الشاشة وإسقاط الوسائط في خدمة أمامية</string>
<string name="text_permission_foreground_service_special_use">السماح للتطبيق بإجراء عمليات خاصة في خدمة أمامية</string>
<string name="text_permission_unlimited_toasts">السماح للتطبيق بعرض عدد غير محدود من إشعارات التوست</string>
<string name="text_permission_capture_video_output">السماح للتطبيق بالتقاط إخراج الفيديو</string>
<string name="text_permission_dump">السماح للتطبيق بتفريغ معلومات النظام</string>
<string name="text_permission_query_all_packages">السماح للتطبيق بالاستعلام عن جميع الحزم</string>
<string name="text_permission_package_usage_stats">السماح للتطبيق بالوصول إلى بيانات استخدام التطبيقات الأخرى</string>
<string name="text_permission_write_settings">السماح للتطبيق بتعديل إعدادات النظام</string>
<string name="text_permission_write_secure_settings">السماح للتطبيق بقراءة وكتابة إعدادات النظام الحساسة</string>
<string name="text_permission_manage_users">السماح للتطبيق بإدارة المستخدمين</string>
<string name="text_permission_interact_across_users_full">السماح للتطبيق بالتفاعل عبر المستخدمين</string>
<string name="text_permission_access_coarse_location">السماح للتطبيق بالوصول إلى الموقع التقريبي عبر الشبكة</string>
<string name="text_permission_access_fine_location">السماح للتطبيق بالحصول على الموقع الدقيق عبر GPS</string>
<string name="text_permission_record_audio">السماح للتطبيق بتسجيل الصوت</string>
<string name="text_permission_run_command">مخصص لتطبيق Termux، السماح بتنفيذ الأوامر</string>
<string name="text_permission_read_phone_state">السماح للتطبيق بقراءة حالة الهاتف والهوية</string>
<string name="text_permission_read_sms">السماح للتطبيق بقراءة الرسائل النصية</string>
<string name="text_permission_shizuku">السماح للتطبيق بالتفاعل مع النظام من خلال خدمة Shizuku للحصول على صلاحيات أعلى</string>
<string name="text_switch_window">تبديل النافذة</string>
<string name="text_symbols_settings">إعدادات الرموز</string>
<string name="text_tailor_made_developer">مطور مصممة خصيصا</string>

View File

@@ -755,6 +755,88 @@
<string name="text_supported_abis_short_32bit">ABIs (32-bit)</string>
<string name="text_supported_abis_short_64bit">ABIs (64-bit)</string>
<string name="text_supported_libraries_short">Libraries</string>
<string name="text_signature_configuration">Signature Configuration</string>
<string name="text_key_store">Keystore</string>
<string name="text_default_key_store">Default Keystore</string>
<string name="text_manage_key_store">Manage Keystore</string>
<string name="text_signature_scheme">Signature Scheme</string>
<string name="text_new_key_store">New Key Store</string>
<string name="text_key_store_password">Key Store Password</string>
<string name="text_key_alias">Alias</string>
<string name="text_alias_password">Alias Password</string>
<string name="text_signature_algorithm">Signature Algorithm</string>
<string name="text_validity_years">Validity (Years)</string>
<string name="text_first_and_last_name">Full Name</string>
<string name="text_organization">Organization Name</string>
<string name="text_organizational_unit">Organizational Unit</string>
<string name="text_country_code">Country Code (XX)</string>
<string name="text_state_or_province">State or Province</string>
<string name="text_city_or_locality">City or Locality</string>
<string name="text_street">Street</string>
<string name="text_filename_cannot_be_empty">Filename cannot be empty</string>
<string name="text_filename_cannot_contain_invalid_character">Filename cannot contain the following characters: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">Filename is too long</string>
<string name="text_password_requires_at_least_n_characters">Password must be at least %d characters long</string>
<string name="text_alias_cannot_be_empty">Alias cannot be empty</string>
<string name="text_validity_years_cannot_be_empty">Validity years cannot be empty</string>
<string name="text_validity_years_cannot_be_zero">Validity years cannot be zero</string>
<string name="text_country_code_must_be_two_capital_letters">Country code must be two capital letters</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">At least one field from \"Full Name, Organization Name, Organizational Unit, Country Code, State or Province, City or Locality, Street\" must be filled</string>
<string name="text_successfully_created_key_store">Successfully created signature key</string>
<string name="text_failed_to_create_key_store">Failed to create signature key</string>
<string name="text_key_store_has_not_been_verified">Keystore has not been verified</string>
<string name="text_key_store_has_been_verified">Keystore has been verified</string>
<string name="text_verify">Verify</string>
<string name="text_delete_all">Delete All</string>
<string name="text_unverified">Unverified</string>
<string name="text_verified">Verified</string>
<string name="text_verify_key_store">Verify Keystore</string>
<string name="text_verify_success">Verification successful</string>
<string name="text_verify_failed">Verification failed</string>
<string name="text_file_path">File Path</string>
<string name="text_supported_permissions_short">Permissions</string>
<string name="text_permission_access_wifi_state">Allow the app to access Wi-Fi state</string>
<string name="text_permission_write_external_storage">Allow the app to write to external storage</string>
<string name="text_permission_read_external_storage">Allow the app to read from external storage</string>
<string name="text_permission_read_media_images">Allow the app to read image files from shared storage</string>
<string name="text_permission_read_media_video">Allow the app to read video files from shared storage</string>
<string name="text_permission_read_media_audio">Allow the app to read audio files from shared storage</string>
<string name="text_permission_manage_external_storage">Allow the app to manage all files in external storage</string>
<string name="text_permission_broadcast_close_system_dialogs">Allow the app to send an intent to close system dialogs</string>
<string name="text_permission_read_privileged_phone_state">Allow the app to access all phone state information</string>
<string name="text_permission_install_shortcut">Allow the app to install shortcuts</string>
<string name="text_permission_uninstall_shortcut">Allow the app to uninstall shortcuts</string>
<string name="text_permission_request_install_packages">Allow the app to request installation of other apps</string>
<string name="text_permission_wake_lock">Prevent the phone from going to sleep</string>
<string name="text_permission_use_exact_alarm">Allow the app to schedule exact alarms or event reminders</string>
<string name="text_permission_schedule_exact_alarm">Allow the app to schedule time-precise operations</string>
<string name="text_permission_vibrate">Allow the app to control phone vibration</string>
<string name="text_permission_internet">Allow the app to access the internet</string>
<string name="text_permission_access_network_state">Allow the app to view network connection status</string>
<string name="text_permission_system_alert_window">Allow the app to display over other apps</string>
<string name="text_permission_reorder_tasks">Allow the app to reorder running tasks</string>
<string name="text_permission_request_ignore_battery_optimizations">Allow the app to request ignoring battery optimizations</string>
<string name="text_permission_receive_boot_completed">Allow the app to receive broadcast when device boot completes</string>
<string name="text_permission_post_notifications">Allow the app to post notifications</string>
<string name="text_permission_foreground_service">Allow the app to run foreground services</string>
<string name="text_permission_foreground_service_media_projection">Allow the app to use screen recording and media projection in foreground services</string>
<string name="text_permission_foreground_service_special_use">Allow the app to perform special operations in foreground services</string>
<string name="text_permission_unlimited_toasts">Allow the app to show unlimited Toast notifications</string>
<string name="text_permission_capture_video_output">Allow the app to capture video output</string>
<string name="text_permission_dump">Allow the app to dump system information</string>
<string name="text_permission_query_all_packages">Allow the app to query all packages</string>
<string name="text_permission_package_usage_stats">Allow the app to access usage statistics of other apps</string>
<string name="text_permission_write_settings">Allow the app to modify system settings</string>
<string name="text_permission_write_secure_settings">Allow the app to read/write secure system settings</string>
<string name="text_permission_manage_users">Allow the app to manage users</string>
<string name="text_permission_interact_across_users_full">Allow the app to interact across users</string>
<string name="text_permission_access_coarse_location">Allow the app to access approximate location via network</string>
<string name="text_permission_access_fine_location">Allow the app to access precise location via GPS</string>
<string name="text_permission_record_audio">Allow the app to record audio</string>
<string name="text_permission_run_command">Specific to Termux app, allow running commands</string>
<string name="text_permission_read_phone_state">Allow the app to read phone state and identity</string>
<string name="text_permission_read_sms">Allow the app to read SMS</string>
<string name="text_permission_shizuku">Allow the app to interact with the system with elevated permissions via Shizuku service</string>
<string name="text_switch_window">Switch window</string>
<string name="text_symbols_settings">Symbols settings</string>
<string name="text_tailor_made_developer">Tailor-made developer</string>

View File

@@ -758,6 +758,88 @@
<string name="text_supported_abis_short_32bit">ABIs (32 bits)</string>
<string name="text_supported_abis_short_64bit">ABIs (64 bits)</string>
<string name="text_supported_libraries_short">Bibliotecas</string>
<string name="text_signature_configuration">Configuración de firma</string>
<string name="text_key_store">Almacenamiento de claves</string>
<string name="text_default_key_store">Almacenamiento de claves predeterminado</string>
<string name="text_manage_key_store">Gestionar almacenamiento de claves</string>
<string name="text_signature_scheme">Esquema de firma</string>
<string name="text_new_key_store">Generar clave de firma</string>
<string name="text_key_store_password">Contraseña del almacén de claves</string>
<string name="text_key_alias">Alias</string>
<string name="text_alias_password">Contraseña del alias</string>
<string name="text_signature_algorithm">Algoritmo de firma</string>
<string name="text_validity_years">Validez (años)</string>
<string name="text_first_and_last_name">Nombre completo</string>
<string name="text_organization">Nombre de la organización</string>
<string name="text_organizational_unit">Unidad organizacional</string>
<string name="text_country_code">Código de país (XX)</string>
<string name="text_state_or_province">Estado o provincia</string>
<string name="text_city_or_locality">Ciudad o localidad</string>
<string name="text_street">Calle</string>
<string name="text_filename_cannot_be_empty">El nombre de archivo no puede estar vacío</string>
<string name="text_filename_cannot_contain_invalid_character">El nombre del archivo no puede contener ninguno de los siguientes caracteres: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">El nombre del archivo es demasiado largo</string>
<string name="text_password_requires_at_least_n_characters">La contraseña debe tener al menos %d caracteres</string>
<string name="text_alias_cannot_be_empty">El alias no puede estar vacío</string>
<string name="text_validity_years_cannot_be_empty">El número de años de validez no puede estar vacío</string>
<string name="text_validity_years_cannot_be_zero">El número de años de validez no puede ser cero</string>
<string name="text_country_code_must_be_two_capital_letters">El código del país debe ser de dos letras mayúsculas</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">Al menos uno de los campos “Nombre completo, Nombre de la organización, Unidad organizacional, Código de país, Estado o provincia, Ciudad o localidad, Calle” debe estar lleno</string>
<string name="text_successfully_created_key_store">Clave de firma creada con éxito</string>
<string name="text_failed_to_create_key_store">Error al crear la clave de firma</string>
<string name="text_key_store_has_not_been_verified">El almacén de claves no ha sido verificado</string>
<string name="text_key_store_has_been_verified">El almacén de claves ha sido verificado</string>
<string name="text_verify">Verificar</string>
<string name="text_delete_all">Eliminar todo</string>
<string name="text_unverified">No verificado</string>
<string name="text_verified">Verificado</string>
<string name="text_verify_key_store">Verificar almacén de claves</string>
<string name="text_verify_success">Verificación exitosa</string>
<string name="text_verify_failed">Error en la verificación</string>
<string name="text_file_path">Ruta del archivo</string>
<string name="text_supported_permissions_short">Permisos requeridos</string>
<string name="text_permission_access_wifi_state">Permitir que la aplicación acceda al estado de Wi-Fi</string>
<string name="text_permission_write_external_storage">Permitir que la aplicación escriba en el almacenamiento externo</string>
<string name="text_permission_read_external_storage">Permitir que la aplicación lea desde el almacenamiento externo</string>
<string name="text_permission_read_media_images">Permitir que la aplicación lea archivos de imágenes del almacenamiento compartido</string>
<string name="text_permission_read_media_video">Permitir que la aplicación lea archivos de video del almacenamiento compartido</string>
<string name="text_permission_read_media_audio">Permitir que la aplicación lea archivos de audio del almacenamiento compartido</string>
<string name="text_permission_manage_external_storage">Permitir que la aplicación gestione todos los archivos en el almacenamiento externo</string>
<string name="text_permission_broadcast_close_system_dialogs">Permitir que la aplicación envíe una intención para cerrar los cuadros de diálogo del sistema</string>
<string name="text_permission_read_privileged_phone_state">Permitir que la aplicación acceda a toda la información del estado del teléfono</string>
<string name="text_permission_install_shortcut">Permitir que la aplicación instale accesos directos</string>
<string name="text_permission_uninstall_shortcut">Permitir que la aplicación desinstale accesos directos</string>
<string name="text_permission_request_install_packages">Permitir que la aplicación solicite la instalación de otras aplicaciones</string>
<string name="text_permission_wake_lock">Evitar que el teléfono entre en modo de suspensión</string>
<string name="text_permission_use_exact_alarm">Permitir que la aplicación programe alarmas exactas o recordatorios de eventos</string>
<string name="text_permission_schedule_exact_alarm">Permitir que la aplicación programe operaciones precisas por tiempo</string>
<string name="text_permission_vibrate">Permitir que la aplicación controle la vibración del teléfono</string>
<string name="text_permission_internet">Permitir que la aplicación acceda a Internet</string>
<string name="text_permission_access_network_state">Permitir que la aplicación vea el estado de la conexión de red</string>
<string name="text_permission_system_alert_window">Permitir que la aplicación se muestre encima de otras aplicaciones</string>
<string name="text_permission_reorder_tasks">Permitir que la aplicación reordene tareas en ejecución</string>
<string name="text_permission_request_ignore_battery_optimizations">Permitir que la aplicación solicite ignorar optimizaciones de batería</string>
<string name="text_permission_receive_boot_completed">Permitir que la aplicación reciba la notificación cuando el dispositivo termine de arrancar</string>
<string name="text_permission_post_notifications">Permitir que la aplicación envíe notificaciones</string>
<string name="text_permission_foreground_service">Permitir que la aplicación ejecute servicios en primer plano</string>
<string name="text_permission_foreground_service_media_projection">Permitir que la aplicación use grabación de pantalla y proyección de medios en servicios en primer plano</string>
<string name="text_permission_foreground_service_special_use">Permitir que la aplicación realice operaciones especiales en servicios en primer plano</string>
<string name="text_permission_unlimited_toasts">Permitir que la aplicación muestre notificaciones de Toast ilimitadas</string>
<string name="text_permission_capture_video_output">Permitir que la aplicación capture salida de video</string>
<string name="text_permission_dump">Permitir que la aplicación volcar información del sistema</string>
<string name="text_permission_query_all_packages">Permitir que la aplicación consulte todos los paquetes</string>
<string name="text_permission_package_usage_stats">Permitir que la aplicación acceda a las estadísticas de uso de otras aplicaciones</string>
<string name="text_permission_write_settings">Permitir que la aplicación modifique los ajustes del sistema</string>
<string name="text_permission_write_secure_settings">Permitir que la aplicación lea/escriba configuraciones del sistema seguras</string>
<string name="text_permission_manage_users">Permitir que la aplicación administre usuarios</string>
<string name="text_permission_interact_across_users_full">Permitir que la aplicación interactúe entre usuarios</string>
<string name="text_permission_access_coarse_location">Permitir que la aplicación acceda a la ubicación aproximada a través de la red</string>
<string name="text_permission_access_fine_location">Permitir que la aplicación acceda a la ubicación precisa a través de GPS</string>
<string name="text_permission_record_audio">Permitir que la aplicación grabe audio</string>
<string name="text_permission_run_command">Específico para la aplicación Termux, permitir ejecutar comandos</string>
<string name="text_permission_read_phone_state">Permitir que la aplicación lea el estado y la identidad del teléfono</string>
<string name="text_permission_read_sms">Permitir que la aplicación lea mensajes SMS</string>
<string name="text_permission_shizuku">Permitir que la aplicación interactúe con el sistema mediante el servicio Shizuku para obtener permisos elevados</string>
<string name="text_switch_window">Cambiar ventana</string>
<string name="text_symbols_settings">Config de símbolos</string>
<string name="text_tailor_made_developer">Desarrollador a medida</string>

View File

@@ -758,6 +758,88 @@
<string name="text_supported_abis_short_32bit">ABIs (32-bit)</string>
<string name="text_supported_abis_short_64bit">ABIs (64-bit)</string>
<string name="text_supported_libraries_short">Bibliothèques</string>
<string name="text_signature_configuration">Configuration de la signature</string>
<string name="text_key_store">Magasin de clés</string>
<string name="text_default_key_store">Magasin de clés par défaut</string>
<string name="text_manage_key_store">Gérer le magasin de clés</string>
<string name="text_signature_scheme">Schéma de signature</string>
<string name="text_new_key_store">Générer une clé de signature</string>
<string name="text_key_store_password">Mot de passe du magasin de clés</string>
<string name="text_key_alias">Alias</string>
<string name="text_alias_password">Mot de passe de l\'alias</string>
<string name="text_signature_algorithm">Algorithme de signature</string>
<string name="text_validity_years">Validité (années)</string>
<string name="text_first_and_last_name">Nom complet</string>
<string name="text_organization">Nom de l\'organisation</string>
<string name="text_organizational_unit">Unité organisationnelle</string>
<string name="text_country_code">Code du pays (XX)</string>
<string name="text_state_or_province">État ou province</string>
<string name="text_city_or_locality">Ville ou localité</string>
<string name="text_street">Rue</string>
<string name="text_filename_cannot_be_empty">Le nom de fichier ne peut pas être vide</string>
<string name="text_filename_cannot_contain_invalid_character">Le nom du fichier ne peut pas contenir les caractères suivants : \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">Le nom du fichier est trop long</string>
<string name="text_password_requires_at_least_n_characters">Le mot de passe doit contenir au moins %d caractères</string>
<string name="text_alias_cannot_be_empty">L\'alias ne peut pas être vide</string>
<string name="text_validity_years_cannot_be_empty">Les années de validité ne peuvent pas être vides</string>
<string name="text_validity_years_cannot_be_zero">Les années de validité ne peuvent pas être égales à zéro</string>
<string name="text_country_code_must_be_two_capital_letters">Le code du pays doit être composé de deux lettres majuscules</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">Au moins un champ parmi « Nom complet, Nom de l\'organisation, Unité organisationnelle, Code du pays, État ou province, Ville ou localité, Rue » doit être renseigné</string>
<string name="text_successfully_created_key_store">Clé de signature créée avec succès</string>
<string name="text_failed_to_create_key_store">Échec de la création de la clé de signature</string>
<string name="text_key_store_has_not_been_verified">Le magasin de clés n\'a pas été vérifié</string>
<string name="text_key_store_has_been_verified">Le magasin de clés a été vérifié</string>
<string name="text_verify">Vérifier</string>
<string name="text_delete_all">Tout supprimer</string>
<string name="text_unverified">Non vérifié</string>
<string name="text_verified">Vérifié</string>
<string name="text_verify_key_store">Vérifier le magasin de clés</string>
<string name="text_verify_success">Vérification réussie</string>
<string name="text_verify_failed">Échec de la vérification</string>
<string name="text_file_path">Chemin du fichier</string>
<string name="text_supported_permissions_short">Autorisations nécessaires</string>
<string name="text_permission_access_wifi_state">Autoriser l\'application à accéder à l\'état du Wi-Fi</string>
<string name="text_permission_write_external_storage">Autoriser l\'application à écrire dans le stockage externe</string>
<string name="text_permission_read_external_storage">Autoriser l\'application à lire à partir du stockage externe</string>
<string name="text_permission_read_media_images">Autoriser l\'application à lire les fichiers image depuis le stockage partagé</string>
<string name="text_permission_read_media_video">Autoriser l\'application à lire les fichiers vidéo depuis le stockage partagé</string>
<string name="text_permission_read_media_audio">Autoriser l\'application à lire les fichiers audio depuis le stockage partagé</string>
<string name="text_permission_manage_external_storage">Autoriser l\'application à gérer tous les fichiers dans le stockage externe</string>
<string name="text_permission_broadcast_close_system_dialogs">Autoriser l\'application à envoyer une intention pour fermer les boîtes de dialogue système</string>
<string name="text_permission_read_privileged_phone_state">Autoriser l\'application à accéder à toutes les informations de l\'état du téléphone</string>
<string name="text_permission_install_shortcut">Autoriser l\'application à installer des raccourcis</string>
<string name="text_permission_uninstall_shortcut">Autoriser l\'application à désinstaller des raccourcis</string>
<string name="text_permission_request_install_packages">Autoriser l\'application à demander l\'installation d\'autres applications</string>
<string name="text_permission_wake_lock">Empêcher le téléphone de passer en mode veille</string>
<string name="text_permission_use_exact_alarm">Autoriser l\'application à programmer des alarmes exactes ou des rappels d\'événements</string>
<string name="text_permission_schedule_exact_alarm">Autoriser l\'application à programmer des opérations précises dans le temps</string>
<string name="text_permission_vibrate">Autoriser l\'application à contrôler la vibration du téléphone</string>
<string name="text_permission_internet">Autoriser l\'application à accéder à Internet</string>
<string name="text_permission_access_network_state">Autoriser l\'application à consulter l\'état de la connexion réseau</string>
<string name="text_permission_system_alert_window">Autoriser l\'application à s\'afficher au-dessus d\'autres applications</string>
<string name="text_permission_reorder_tasks">Autoriser l\'application à réorganiser les tâches en cours d\'exécution</string>
<string name="text_permission_request_ignore_battery_optimizations">Autoriser l\'application à demander l\'ignorance des optimisations de la batterie</string>
<string name="text_permission_receive_boot_completed">Autoriser l\'application à recevoir une notification lorsque le démarrage du périphérique est terminé</string>
<string name="text_permission_post_notifications">Autoriser l\'application à afficher des notifications</string>
<string name="text_permission_foreground_service">Autoriser l\'application à exécuter des services en premier plan</string>
<string name="text_permission_foreground_service_media_projection">Autoriser l\'application à utiliser l\'enregistrement d\'écran et la projection multimédia dans des services en premier plan</string>
<string name="text_permission_foreground_service_special_use">Autoriser l\'application à effectuer des opérations spéciales dans des services en premier plan</string>
<string name="text_permission_unlimited_toasts">Autoriser l\'application à afficher un nombre illimité de notifications Toast</string>
<string name="text_permission_capture_video_output">Autoriser l\'application à capturer la sortie vidéo</string>
<string name="text_permission_dump">Autoriser l\'application à vider les informations système</string>
<string name="text_permission_query_all_packages">Autoriser l\'application à interroger tous les packages</string>
<string name="text_permission_package_usage_stats">Autoriser l\'application à accéder aux statistiques d\'utilisation d\'autres applications</string>
<string name="text_permission_write_settings">Autoriser l\'application à modifier les paramètres système</string>
<string name="text_permission_write_secure_settings">Autoriser l\'application à lire/écrire les paramètres sécurisés du système</string>
<string name="text_permission_manage_users">Autoriser l\'application à gérer les utilisateurs</string>
<string name="text_permission_interact_across_users_full">Autoriser l\'application à interagir entre utilisateurs</string>
<string name="text_permission_access_coarse_location">Autoriser l\'application à accéder à une localisation approximative via le réseau</string>
<string name="text_permission_access_fine_location">Autoriser l\'application à accéder à une localisation précise via le GPS</string>
<string name="text_permission_record_audio">Autoriser l\'application à enregistrer de l\'audio</string>
<string name="text_permission_run_command">Spécifique à l\'application Termux, autoriser l\'exécution de commandes</string>
<string name="text_permission_read_phone_state">Autoriser l\'application à lire l\'état du téléphone et l\'identité</string>
<string name="text_permission_read_sms">Autoriser l\'application à lire les SMS</string>
<string name="text_permission_shizuku">Autoriser l\'application à interagir avec le système via le service Shizuku pour obtenir des autorisations élevées</string>
<string name="text_switch_window">Changer de fenêtre</string>
<string name="text_symbols_settings">Param des symboles</string>
<string name="text_tailor_made_developer">Développeur sur mesure</string>

View File

@@ -758,6 +758,88 @@
<string name="text_supported_abis_short_32bit">ABI (32ビット)</string>
<string name="text_supported_abis_short_64bit">ABI (64ビット)</string>
<string name="text_supported_libraries_short">ライブラリー</string>
<string name="text_signature_configuration">署名設定</string>
<string name="text_key_store">キーストア</string>
<string name="text_default_key_store">デフォルトのキーストア</string>
<string name="text_manage_key_store">キーストアを管理</string>
<string name="text_signature_scheme">署名スキーム</string>
<string name="text_new_key_store">署名キーを生成</string>
<string name="text_key_store_password">キーストアのパスワード</string>
<string name="text_key_alias">エイリアス</string>
<string name="text_alias_password">エイリアスのパスワード</string>
<string name="text_signature_algorithm">署名アルゴリズム</string>
<string name="text_validity_years">有効期限(年)</string>
<string name="text_first_and_last_name">氏名</string>
<string name="text_organization">組織名</string>
<string name="text_organizational_unit">組織単位</string>
<string name="text_country_code">国コードXX</string>
<string name="text_state_or_province">州または省</string>
<string name="text_city_or_locality">市区町村</string>
<string name="text_street"></string>
<string name="text_filename_cannot_be_empty">ファイル名は空にできません</string>
<string name="text_filename_cannot_contain_invalid_character">ファイル名に以下の文字を含めることはできません:\\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">ファイル名が長すぎます</string>
<string name="text_password_requires_at_least_n_characters">パスワードは少なくとも%d文字以上である必要があります</string>
<string name="text_alias_cannot_be_empty">エイリアスは空にできません</string>
<string name="text_validity_years_cannot_be_empty">有効期限の年数は空にできません</string>
<string name="text_validity_years_cannot_be_zero">有効期限の年数は0にできません</string>
<string name="text_country_code_must_be_two_capital_letters">国コードは2文字の大文字でなければなりません</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">「氏名、組織名、組織単位、国コード、州または省、市区町村、街」のいずれかの項目を入力する必要があります</string>
<string name="text_successfully_created_key_store">署名キーが正常に作成されました</string>
<string name="text_failed_to_create_key_store">署名キーの作成に失敗しました</string>
<string name="text_key_store_has_not_been_verified">キーストアは確認されていません</string>
<string name="text_key_store_has_been_verified">キーストアは確認されました</string>
<string name="text_verify">確認</string>
<string name="text_delete_all">すべて削除</string>
<string name="text_unverified">未確認</string>
<string name="text_verified">確認済み</string>
<string name="text_verify_key_store">キーストアを確認</string>
<string name="text_verify_success">確認成功</string>
<string name="text_verify_failed">確認失敗</string>
<string name="text_file_path">ファイルパス</string>
<string name="text_supported_permissions_short">必要な権限</string>
<string name="text_permission_access_wifi_state">アプリにWi-Fiの状態へのアクセスを許可する</string>
<string name="text_permission_write_external_storage">アプリに外部ストレージへの書き込みを許可する</string>
<string name="text_permission_read_external_storage">アプリに外部ストレージからの読み取りを許可する</string>
<string name="text_permission_read_media_images">アプリに共有ストレージから画像ファイルの読み取りを許可する</string>
<string name="text_permission_read_media_video">アプリに共有ストレージから動画ファイルの読み取りを許可する</string>
<string name="text_permission_read_media_audio">アプリに共有ストレージから音声ファイルの読み取りを許可する</string>
<string name="text_permission_manage_external_storage">アプリに外部ストレージ内のすべてのファイルを管理する権限を与える</string>
<string name="text_permission_broadcast_close_system_dialogs">アプリにシステムダイアログを閉じるためのインテントを送信する権限を与える</string>
<string name="text_permission_read_privileged_phone_state">アプリにすべての電話状態情報にアクセスする権限を与える</string>
<string name="text_permission_install_shortcut">アプリにショートカットのインストールを許可する</string>
<string name="text_permission_uninstall_shortcut">アプリにショートカットのアンインストールを許可する</string>
<string name="text_permission_request_install_packages">アプリに他のアプリのインストールを要求する権限を与える</string>
<string name="text_permission_wake_lock">アプリに電話をスリープ状態にしないようにする権限を与える</string>
<string name="text_permission_use_exact_alarm">アプリに正確なアラームやイベントリマインダーを設定する権限を与える</string>
<string name="text_permission_schedule_exact_alarm">アプリに時間精度のある操作をスケジュールする権限を与える</string>
<string name="text_permission_vibrate">アプリに電話の振動を制御する権限を与える</string>
<string name="text_permission_internet">アプリにインターネットにアクセスする権限を与える</string>
<string name="text_permission_access_network_state">アプリにネットワーク接続状態を確認する権限を与える</string>
<string name="text_permission_system_alert_window">アプリに他のアプリの上に表示する権限を与える</string>
<string name="text_permission_reorder_tasks">アプリに実行中のタスクを再配置する権限を与える</string>
<string name="text_permission_request_ignore_battery_optimizations">アプリにバッテリー最適化を無視するように要求する権限を与える</string>
<string name="text_permission_receive_boot_completed">アプリにデバイス起動完了の通知を受け取る権限を与える</string>
<string name="text_permission_post_notifications">アプリに通知を表示する権限を与える</string>
<string name="text_permission_foreground_service">アプリにフォアグラウンドサービスを実行する権限を与える</string>
<string name="text_permission_foreground_service_media_projection">アプリにフォアグラウンドサービス内で画面録画とメディアプロジェクションを使用する権限を与える</string>
<string name="text_permission_foreground_service_special_use">アプリにフォアグラウンドサービス内で特別な操作を行う権限を与える</string>
<string name="text_permission_unlimited_toasts">アプリに無制限のToast通知を表示する権限を与える</string>
<string name="text_permission_capture_video_output">アプリにビデオ出力をキャプチャする権限を与える</string>
<string name="text_permission_dump">アプリにシステム情報をダンプする権限を与える</string>
<string name="text_permission_query_all_packages">アプリにすべてのパッケージをクエリする権限を与える</string>
<string name="text_permission_package_usage_stats">アプリに他のアプリの使用統計情報にアクセスする権限を与える</string>
<string name="text_permission_write_settings">アプリにシステム設定を変更する権限を与える</string>
<string name="text_permission_write_secure_settings">アプリにシステムのセキュア設定を読み書きする権限を与える</string>
<string name="text_permission_manage_users">アプリにユーザー管理を行う権限を与える</string>
<string name="text_permission_interact_across_users_full">アプリにユーザー間でのインタラクションを許可する</string>
<string name="text_permission_access_coarse_location">アプリにネットワークを使用して粗い位置情報にアクセスする権限を与える</string>
<string name="text_permission_access_fine_location">アプリにGPSを使用して正確な位置情報にアクセスする権限を与える</string>
<string name="text_permission_record_audio">アプリに音声を録音する権限を与える</string>
<string name="text_permission_run_command">Termuxアプリに特化したコマンド実行権限を与える</string>
<string name="text_permission_read_phone_state">アプリに電話の状態とIDを読み取る権限を与える</string>
<string name="text_permission_read_sms">アプリにSMSを読み取る権限を与える</string>
<string name="text_permission_shizuku">アプリにShizukuサービスを通じてシステムと高い権限でインタラクションする権限を与える</string>
<string name="text_switch_window">ウィンドウの切り替え</string>
<string name="text_symbols_settings">シンボル設定</string>
<string name="text_tailor_made_developer">テーラーメイド開発者</string>

View File

@@ -759,6 +759,88 @@
<string name="text_supported_abis_short_32bit">ABI (32 비트)</string>
<string name="text_supported_abis_short_64bit">ABI (64 비트)</string>
<string name="text_supported_libraries_short">라이브러리</string>
<string name="text_signature_configuration">서명 설정</string>
<string name="text_key_store">키 저장소</string>
<string name="text_default_key_store">기본 키 저장소</string>
<string name="text_manage_key_store">키 저장소 관리</string>
<string name="text_signature_scheme">서명 스킴</string>
<string name="text_new_key_store">서명 키 생성</string>
<string name="text_key_store_password">키 저장소 비밀번호</string>
<string name="text_key_alias">별칭</string>
<string name="text_alias_password">별칭 비밀번호</string>
<string name="text_signature_algorithm">서명 알고리즘</string>
<string name="text_validity_years">유효 기간 (년)</string>
<string name="text_first_and_last_name">성명</string>
<string name="text_organization">조직명</string>
<string name="text_organizational_unit">조직 단위</string>
<string name="text_country_code">국가 코드 (XX)</string>
<string name="text_state_or_province">주 또는 도</string>
<string name="text_city_or_locality">시 또는 지역</string>
<string name="text_street">거리</string>
<string name="text_filename_cannot_be_empty">파일 이름은 비워둘 수 없습니다</string>
<string name="text_filename_cannot_contain_invalid_character">파일 이름에 다음 문자를 포함할 수 없습니다: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">파일 이름이 너무 깁니다</string>
<string name="text_password_requires_at_least_n_characters">비밀번호는 최소 %d자 이상이어야 합니다</string>
<string name="text_alias_cannot_be_empty">별칭은 비워둘 수 없습니다</string>
<string name="text_validity_years_cannot_be_empty">유효 기간을 입력해야 합니다</string>
<string name="text_validity_years_cannot_be_zero">유효 기간은 0일 수 없습니다</string>
<string name="text_country_code_must_be_two_capital_letters">국가 코드는 두 개의 대문자로 입력해야 합니다</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">"성명, 조직명, 조직 단위, 국가 코드, 주 또는 도, 시 또는 지역, 거리" 중 하나 이상을 입력해야 합니다</string>
<string name="text_successfully_created_key_store">서명 키가 성공적으로 생성되었습니다</string>
<string name="text_failed_to_create_key_store">서명 키 생성에 실패했습니다</string>
<string name="text_key_store_has_not_been_verified">키 저장소가 확인되지 않았습니다</string>
<string name="text_key_store_has_been_verified">키 저장소가 확인되었습니다</string>
<string name="text_verify">확인</string>
<string name="text_delete_all">모두 삭제</string>
<string name="text_unverified">미확인</string>
<string name="text_verified">확인됨</string>
<string name="text_verify_key_store">키 저장소 확인</string>
<string name="text_verify_success">확인 성공</string>
<string name="text_verify_failed">확인 실패</string>
<string name="text_file_path">파일 경로</string>
<string name="text_supported_permissions_short">필요한 권한</string>
<string name="text_permission_access_wifi_state">앱이 Wi-Fi 상태에 접근할 수 있도록 허용</string>
<string name="text_permission_write_external_storage">앱이 외부 저장소에 쓸 수 있도록 허용</string>
<string name="text_permission_read_external_storage">앱이 외부 저장소를 읽을 수 있도록 허용</string>
<string name="text_permission_read_media_images">앱이 공유 저장소의 이미지 파일을 읽을 수 있도록 허용</string>
<string name="text_permission_read_media_video">앱이 공유 저장소의 비디오 파일을 읽을 수 있도록 허용</string>
<string name="text_permission_read_media_audio">앱이 공유 저장소의 오디오 파일을 읽을 수 있도록 허용</string>
<string name="text_permission_manage_external_storage">앱이 외부 저장소의 모든 파일을 관리할 수 있도록 허용</string>
<string name="text_permission_broadcast_close_system_dialogs">앱이 시스템 대화상자를 닫기 위한 인텐트를 보낼 수 있도록 허용</string>
<string name="text_permission_read_privileged_phone_state">앱이 모든 전화 상태 정보를 읽을 수 있도록 허용</string>
<string name="text_permission_install_shortcut">앱이 바로가기를 설치할 수 있도록 허용</string>
<string name="text_permission_uninstall_shortcut">앱이 바로가기를 삭제할 수 있도록 허용</string>
<string name="text_permission_request_install_packages">앱이 다른 앱 설치를 요청할 수 있도록 허용</string>
<string name="text_permission_wake_lock">앱이 전화기를 절전 모드로 진입하지 않도록 방지</string>
<string name="text_permission_use_exact_alarm">앱이 정확한 알람이나 이벤트 알림을 설정할 수 있도록 허용</string>
<string name="text_permission_schedule_exact_alarm">앱이 시간 정확한 작업을 예약할 수 있도록 허용</string>
<string name="text_permission_vibrate">앱이 전화기 진동을 제어할 수 있도록 허용</string>
<string name="text_permission_internet">앱이 인터넷에 접근할 수 있도록 허용</string>
<string name="text_permission_access_network_state">앱이 네트워크 상태를 확인할 수 있도록 허용</string>
<string name="text_permission_system_alert_window">앱이 다른 앱 위에 표시될 수 있도록 허용</string>
<string name="text_permission_reorder_tasks">앱이 실행 중인 작업을 재배치할 수 있도록 허용</string>
<string name="text_permission_request_ignore_battery_optimizations">앱이 배터리 최적화를 무시하도록 요청할 수 있도록 허용</string>
<string name="text_permission_receive_boot_completed">앱이 장치 부팅 완료 시 브로드캐스트를 받을 수 있도록 허용</string>
<string name="text_permission_post_notifications">앱이 알림을 게시할 수 있도록 허용</string>
<string name="text_permission_foreground_service">앱이 포그라운드 서비스를 실행할 수 있도록 허용</string>
<string name="text_permission_foreground_service_media_projection">앱이 포그라운드 서비스에서 화면 캡처와 미디어 투영 기능을 사용할 수 있도록 허용</string>
<string name="text_permission_foreground_service_special_use">앱이 포그라운드 서비스에서 특별한 작업을 수행할 수 있도록 허용</string>
<string name="text_permission_unlimited_toasts">앱이 무제한으로 Toast 알림을 표시할 수 있도록 허용</string>
<string name="text_permission_capture_video_output">앱이 비디오 출력을 캡처할 수 있도록 허용</string>
<string name="text_permission_dump">앱이 시스템 정보를 덤프할 수 있도록 허용</string>
<string name="text_permission_query_all_packages">앱이 모든 패키지를 쿼리할 수 있도록 허용</string>
<string name="text_permission_package_usage_stats">앱이 다른 앱의 사용 통계를 볼 수 있도록 허용</string>
<string name="text_permission_write_settings">앱이 시스템 설정을 수정할 수 있도록 허용</string>
<string name="text_permission_write_secure_settings">앱이 시스템 보안 설정을 읽고 쓸 수 있도록 허용</string>
<string name="text_permission_manage_users">앱이 사용자 관리를 할 수 있도록 허용</string>
<string name="text_permission_interact_across_users_full">앱이 사용자 간 상호작용을 할 수 있도록 허용</string>
<string name="text_permission_access_coarse_location">앱이 네트워크를 통해 대략적인 위치에 접근할 수 있도록 허용</string>
<string name="text_permission_access_fine_location">앱이 GPS를 통해 정확한 위치에 접근할 수 있도록 허용</string>
<string name="text_permission_record_audio">앱이 오디오를 녹음할 수 있도록 허용</string>
<string name="text_permission_run_command">Termux 앱에 대해 명령을 실행할 수 있도록 허용</string>
<string name="text_permission_read_phone_state">앱이 전화 상태 및 신원을 읽을 수 있도록 허용</string>
<string name="text_permission_read_sms">앱이 SMS를 읽을 수 있도록 허용</string>
<string name="text_permission_shizuku">앱이 Shizuku 서비스를 통해 시스템과 상호작용할 수 있도록 허용</string>
<string name="text_switch_window">창 전환</string>
<string name="text_symbols_settings">기호 설정</string>
<string name="text_tailor_made_developer">맞춤형 개발자</string>

View File

@@ -758,6 +758,88 @@
<string name="text_supported_abis_short_32bit">ABIs (32-bit)</string>
<string name="text_supported_abis_short_64bit">ABIs (64-bit)</string>
<string name="text_supported_libraries_short">Библиотеки</string>
<string name="text_signature_configuration">Конфигурация подписи</string>
<string name="text_key_store">Хранилище ключей</string>
<string name="text_default_key_store">По умолчанию хранилище ключей</string>
<string name="text_manage_key_store">Управление хранилищем ключей</string>
<string name="text_signature_scheme">Схема подписи</string>
<string name="text_new_key_store">Создать ключ подписи</string>
<string name="text_key_store_password">Пароль хранилища ключей</string>
<string name="text_key_alias">Псевдоним</string>
<string name="text_alias_password">Пароль псевдонима</string>
<string name="text_signature_algorithm">Алгоритм подписи</string>
<string name="text_validity_years">Срок действия (годы)</string>
<string name="text_first_and_last_name">Полное имя</string>
<string name="text_organization">Название организации</string>
<string name="text_organizational_unit">Организационная единица</string>
<string name="text_country_code">Код страны (XX)</string>
<string name="text_state_or_province">Штат или провинция</string>
<string name="text_city_or_locality">Город или населенный пункт</string>
<string name="text_street">Улица</string>
<string name="text_filename_cannot_be_empty">Имя файла не может быть пустым</string>
<string name="text_filename_cannot_contain_invalid_character">Имя файла не может содержать следующие символы: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">Имя файла слишком длинное</string>
<string name="text_password_requires_at_least_n_characters">Пароль должен содержать не менее %d символов</string>
<string name="text_alias_cannot_be_empty">Псевдоним не может быть пустым</string>
<string name="text_validity_years_cannot_be_empty">Срок действия не может быть пустым</string>
<string name="text_validity_years_cannot_be_zero">Срок действия не может быть равен нулю</string>
<string name="text_country_code_must_be_two_capital_letters">Код страны должен состоять из двух заглавных букв</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">Необходимо заполнить хотя бы одно поле из: «Полное имя, Название организации, Организационная единица, Код страны, Штат или провинция, Город или населенный пункт, Улица»</string>
<string name="text_successfully_created_key_store">Ключ подписи успешно создан</string>
<string name="text_failed_to_create_key_store">Не удалось создать ключ подписи</string>
<string name="text_key_store_has_not_been_verified">Хранилище ключей не подтверждено</string>
<string name="text_key_store_has_been_verified">Хранилище ключей подтверждено</string>
<string name="text_verify">Проверить</string>
<string name="text_delete_all">Удалить все</string>
<string name="text_unverified">Не подтверждено</string>
<string name="text_verified">Подтверждено</string>
<string name="text_verify_key_store">Проверить хранилище ключей</string>
<string name="text_verify_success">Проверка успешна</string>
<string name="text_verify_failed">Ошибка проверки</string>
<string name="text_file_path">Путь к файлу</string>
<string name="text_supported_permissions_short">Требуемые разрешения</string>
<string name="text_permission_access_wifi_state">Разрешить приложению доступ к состоянию Wi-Fi</string>
<string name="text_permission_write_external_storage">Разрешить приложению записывать на внешнее хранилище</string>
<string name="text_permission_read_external_storage">Разрешить приложению читать с внешнего хранилища</string>
<string name="text_permission_read_media_images">Разрешить приложению читать изображения из общего хранилища</string>
<string name="text_permission_read_media_video">Разрешить приложению читать видеофайлы из общего хранилища</string>
<string name="text_permission_read_media_audio">Разрешить приложению читать аудиофайлы из общего хранилища</string>
<string name="text_permission_manage_external_storage">Разрешить приложению управлять всеми файлами на внешнем хранилище</string>
<string name="text_permission_broadcast_close_system_dialogs">Разрешить приложению отправить намерение для закрытия системных диалогов</string>
<string name="text_permission_read_privileged_phone_state">Разрешить приложению доступ ко всем данным состояния телефона</string>
<string name="text_permission_install_shortcut">Разрешить приложению устанавливать ярлыки</string>
<string name="text_permission_uninstall_shortcut">Разрешить приложению удалять ярлыки</string>
<string name="text_permission_request_install_packages">Разрешить приложению запрашивать установку других приложений</string>
<string name="text_permission_wake_lock">Предотвратить переход устройства в спящий режим</string>
<string name="text_permission_use_exact_alarm">Разрешить приложению устанавливать точные будильники или напоминания</string>
<string name="text_permission_schedule_exact_alarm">Разрешить приложению планировать точные операции по времени</string>
<string name="text_permission_vibrate">Разрешить приложению управлять вибрацией устройства</string>
<string name="text_permission_internet">Разрешить приложению доступ в Интернет</string>
<string name="text_permission_access_network_state">Разрешить приложению проверять состояние сетевого подключения</string>
<string name="text_permission_system_alert_window">Разрешить приложению отображаться поверх других приложений</string>
<string name="text_permission_reorder_tasks">Разрешить приложению изменять порядок работающих задач</string>
<string name="text_permission_request_ignore_battery_optimizations">Разрешить приложению запросить игнорирование оптимизаций батареи</string>
<string name="text_permission_receive_boot_completed">Разрешить приложению получать уведомления при завершении загрузки устройства</string>
<string name="text_permission_post_notifications">Разрешить приложению отображать уведомления</string>
<string name="text_permission_foreground_service">Разрешить приложению запускать сервисы в фоновом режиме</string>
<string name="text_permission_foreground_service_media_projection">Разрешить приложению использовать запись экрана и медиапроекцию в фоновом сервисе</string>
<string name="text_permission_foreground_service_special_use">Разрешить приложению выполнять специальные операции в фоновом сервисе</string>
<string name="text_permission_unlimited_toasts">Разрешить приложению показывать неограниченное количество уведомлений Toast</string>
<string name="text_permission_capture_video_output">Разрешить приложению захватывать видеовыход</string>
<string name="text_permission_dump">Разрешить приложению выгружать системные данные</string>
<string name="text_permission_query_all_packages">Разрешить приложению запрашивать все пакеты</string>
<string name="text_permission_package_usage_stats">Разрешить приложению доступ к статистике использования других приложений</string>
<string name="text_permission_write_settings">Разрешить приложению изменять настройки системы</string>
<string name="text_permission_write_secure_settings">Разрешить приложению читать/записывать защищенные настройки системы</string>
<string name="text_permission_manage_users">Разрешить приложению управлять пользователями</string>
<string name="text_permission_interact_across_users_full">Разрешить приложению взаимодействовать между пользователями</string>
<string name="text_permission_access_coarse_location">Разрешить приложению доступ к неточной геопозиции через сеть</string>
<string name="text_permission_access_fine_location">Разрешить приложению доступ к точной геопозиции через GPS</string>
<string name="text_permission_record_audio">Разрешить приложению записывать звук</string>
<string name="text_permission_run_command">Для приложения Termux разрешить выполнение команд</string>
<string name="text_permission_read_phone_state">Разрешить приложению читать состояние телефона и его идентификатор</string>
<string name="text_permission_read_sms">Разрешить приложению читать SMS-сообщения</string>
<string name="text_permission_shizuku">Разрешить приложению взаимодействовать с системой через сервис Shizuku для получения повышенных прав</string>
<string name="text_switch_window">Переключить окно</string>
<string name="text_symbols_settings">Настройки символов</string>
<string name="text_tailor_made_developer">Индивидуальный разработчик</string>

View File

@@ -757,6 +757,88 @@
<string name="text_supported_abis_short_32bit">支持 ABI (32 位)</string>
<string name="text_supported_abis_short_64bit">支持 ABI (64 位)</string>
<string name="text_supported_libraries_short">支援庫</string>
<string name="text_signature_configuration">簽名配置</string>
<string name="text_key_store">密鑰庫</string>
<string name="text_default_key_store">預設密鑰庫</string>
<string name="text_manage_key_store">管理密鑰庫</string>
<string name="text_signature_scheme">簽名方案</string>
<string name="text_new_key_store">生成簽名密鑰</string>
<string name="text_key_store_password">密鑰庫密碼</string>
<string name="text_key_alias">別名</string>
<string name="text_alias_password">別名密碼</string>
<string name="text_signature_algorithm">簽名算法</string>
<string name="text_validity_years">有效期 (年)</string>
<string name="text_first_and_last_name">姓名</string>
<string name="text_organization">組織名稱</string>
<string name="text_organizational_unit">組織單位</string>
<string name="text_country_code">國家代碼 (XX)</string>
<string name="text_state_or_province">州或省份</string>
<string name="text_city_or_locality">城市或區域</string>
<string name="text_street">街道</string>
<string name="text_filename_cannot_be_empty">文件名不能為空</string>
<string name="text_filename_cannot_contain_invalid_character">文件名不能包含以下字符: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">文件名太長</string>
<string name="text_password_requires_at_least_n_characters">密碼至少需要%d位字符</string>
<string name="text_alias_cannot_be_empty">別名不能為空</string>
<string name="text_validity_years_cannot_be_empty">有效年份不能為空</string>
<string name="text_validity_years_cannot_be_zero">有效年份不能為0</string>
<string name="text_country_code_must_be_two_capital_letters">國家代碼必須為兩個大寫字母</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">“姓名、組織名稱、組織單位、國家代碼、州或省份、城市或區域、街道”至少填寫一個</string>
<string name="text_successfully_created_key_store">成功生成簽名密鑰</string>
<string name="text_failed_to_create_key_store">生成簽名密鑰失敗</string>
<string name="text_key_store_has_not_been_verified">密鑰尚未驗證</string>
<string name="text_key_store_has_been_verified">密鑰已驗證</string>
<string name="text_verify">驗證</string>
<string name="text_delete_all">刪除全部</string>
<string name="text_unverified">未驗證</string>
<string name="text_verified">已驗證</string>
<string name="text_verify_key_store">驗證簽名密鑰</string>
<string name="text_verify_success">驗證成功</string>
<string name="text_verify_failed">驗證失敗</string>
<string name="text_file_path">文件路徑</string>
<string name="text_supported_permissions_short">所需的權限</string>
<string name="text_permission_access_wifi_state">允許應用程式訪問Wi-Fi狀態</string>
<string name="text_permission_write_external_storage">允許應用程式寫入外部儲存</string>
<string name="text_permission_read_external_storage">允許應用程式讀取外部儲存</string>
<string name="text_permission_read_media_images">允許應用程式讀取共享儲存中的圖片檔案</string>
<string name="text_permission_read_media_video">允許應用程式讀取共享儲存中的視頻檔案</string>
<string name="text_permission_read_media_audio">允許應用程式讀取共享儲存中的音頻檔案</string>
<string name="text_permission_manage_external_storage">允許應用程式管理外部儲存中的所有檔案</string>
<string name="text_permission_broadcast_close_system_dialogs">允許應用程式發送意圖來關閉系統對話框</string>
<string name="text_permission_read_privileged_phone_state">允許應用程式訪問所有電話狀態資訊</string>
<string name="text_permission_install_shortcut">允許應用程式安裝快捷方式</string>
<string name="text_permission_uninstall_shortcut">允許應用程式卸載快捷方式</string>
<string name="text_permission_request_install_packages">允許應用程式請求安裝其他應用程式</string>
<string name="text_permission_wake_lock">防止手機進入休眠狀態</string>
<string name="text_permission_use_exact_alarm">允許應用程式安排精確的鬧鐘或事件提醒</string>
<string name="text_permission_schedule_exact_alarm">允許應用程式安排時間精確的操作</string>
<string name="text_permission_vibrate">控制手機震動</string>
<string name="text_permission_internet">允許應用程式訪問網路</string>
<string name="text_permission_access_network_state">允許應用程式查看網路連接狀態</string>
<string name="text_permission_system_alert_window">允許應用程式在其他應用程式上面顯示</string>
<string name="text_permission_reorder_tasks">允許應用程式對正在運行的應用程式重新排序</string>
<string name="text_permission_request_ignore_battery_optimizations">允許應用程式請求忽略電池優化</string>
<string name="text_permission_receive_boot_completed">允許應用程式在設備啟動時接收廣播</string>
<string name="text_permission_post_notifications">允許應用程式顯示通知</string>
<string name="text_permission_foreground_service">允許應用程式運行前景服務</string>
<string name="text_permission_foreground_service_media_projection">允許應用程式在前景服務中使用螢幕錄製和媒體投影功能</string>
<string name="text_permission_foreground_service_special_use">允許應用程式在前景服務中執行一些特殊操作</string>
<string name="text_permission_unlimited_toasts">允許應用程式顯示無限數量的Toast通知</string>
<string name="text_permission_capture_video_output">允許應用程式捕獲視頻輸出</string>
<string name="text_permission_dump">允許應用程式轉儲系統資訊</string>
<string name="text_permission_query_all_packages">允許應用程式查詢所有軟件包</string>
<string name="text_permission_package_usage_stats">允許應用程式訪問其他應用程式的使用統計數據</string>
<string name="text_permission_write_settings">允許應用程式修改系統設定</string>
<string name="text_permission_write_secure_settings">允許應用程式讀寫系統敏感設定</string>
<string name="text_permission_manage_users">允許應用程式管理使用者</string>
<string name="text_permission_interact_across_users_full">允許應用程式跨使用者互動</string>
<string name="text_permission_access_coarse_location">允許應用程式通過網路訪問粗略的位置信息</string>
<string name="text_permission_access_fine_location">允許應用程式通過GPS獲取精確的位置信息</string>
<string name="text_permission_record_audio">允許應用程式錄音</string>
<string name="text_permission_run_command">特定於Termux應用程式允許執行命令</string>
<string name="text_permission_read_phone_state">允許應用程式讀取手機狀態和身份</string>
<string name="text_permission_read_sms">允許應用程式讀取簡訊</string>
<string name="text_permission_shizuku">允許應用程式通過Shizuku服務與系統進行更高權限的交互</string>
<string name="text_switch_window">切換窗口</string>
<string name="text_symbols_settings">符號設置</string>
<string name="text_tailor_made_developer">二次開發者</string>

View File

@@ -757,6 +757,88 @@
<string name="text_supported_abis_short_32bit">支援 ABI (32 位)</string>
<string name="text_supported_abis_short_64bit">支援 ABI (64 位)</string>
<string name="text_supported_libraries_short">支援庫</string>
<string name="text_signature_configuration">簽名設定</string>
<string name="text_key_store">密鑰庫</string>
<string name="text_default_key_store">預設密鑰庫</string>
<string name="text_manage_key_store">管理密鑰庫</string>
<string name="text_signature_scheme">簽名方案</string>
<string name="text_new_key_store">生成簽名密鑰</string>
<string name="text_key_store_password">密鑰庫密碼</string>
<string name="text_key_alias">別名</string>
<string name="text_alias_password">別名密碼</string>
<string name="text_signature_algorithm">簽名演算法</string>
<string name="text_validity_years">有效期 (年)</string>
<string name="text_first_and_last_name">姓名</string>
<string name="text_organization">組織名稱</string>
<string name="text_organizational_unit">組織單位</string>
<string name="text_country_code">國家代碼 (XX)</string>
<string name="text_state_or_province">州或省份</string>
<string name="text_city_or_locality">城市或區域</string>
<string name="text_street">街道</string>
<string name="text_filename_cannot_be_empty">檔案名稱不能為空</string>
<string name="text_filename_cannot_contain_invalid_character">檔案名稱不能包含以下字符: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">檔案名稱太長</string>
<string name="text_password_requires_at_least_n_characters">密碼至少需要%d個字元</string>
<string name="text_alias_cannot_be_empty">別名不能為空</string>
<string name="text_validity_years_cannot_be_empty">有效年份不能為空</string>
<string name="text_validity_years_cannot_be_zero">有效年份不能為0</string>
<string name="text_country_code_must_be_two_capital_letters">國家代碼必須是兩個大寫字母</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">“姓名、組織名稱、組織單位、國家代碼、州或省份、城市或區域、街道”至少填寫一個</string>
<string name="text_successfully_created_key_store">成功生成簽名密鑰</string>
<string name="text_failed_to_create_key_store">生成簽名密鑰失敗</string>
<string name="text_key_store_has_not_been_verified">密鑰尚未驗證</string>
<string name="text_key_store_has_been_verified">密鑰已驗證</string>
<string name="text_verify">驗證</string>
<string name="text_delete_all">刪除全部</string>
<string name="text_unverified">未驗證</string>
<string name="text_verified">已驗證</string>
<string name="text_verify_key_store">驗證簽名密鑰</string>
<string name="text_verify_success">驗證成功</string>
<string name="text_verify_failed">驗證失敗</string>
<string name="text_file_path">檔案路徑</string>
<string name="text_supported_permissions_short">所需的權限</string>
<string name="text_permission_access_wifi_state">允許應用程式訪問Wi-Fi狀態</string>
<string name="text_permission_write_external_storage">允許應用程式寫入外部儲存</string>
<string name="text_permission_read_external_storage">允許應用程式讀取外部儲存</string>
<string name="text_permission_read_media_images">允許應用程式讀取共享儲存中的圖片檔案</string>
<string name="text_permission_read_media_video">允許應用程式讀取共享儲存中的影片檔案</string>
<string name="text_permission_read_media_audio">允許應用程式讀取共享儲存中的音頻檔案</string>
<string name="text_permission_manage_external_storage">允許應用程式管理外部儲存中的所有檔案</string>
<string name="text_permission_broadcast_close_system_dialogs">允許應用程式發送意圖來關閉系統對話框</string>
<string name="text_permission_read_privileged_phone_state">允許應用程式訪問所有電話狀態資訊</string>
<string name="text_permission_install_shortcut">允許應用程式安裝快捷方式</string>
<string name="text_permission_uninstall_shortcut">允許應用程式卸載快捷方式</string>
<string name="text_permission_request_install_packages">允許應用程式請求安裝其他應用程式</string>
<string name="text_permission_wake_lock">防止手機進入休眠狀態</string>
<string name="text_permission_use_exact_alarm">允許應用程式安排精確的鬧鐘或事件提醒</string>
<string name="text_permission_schedule_exact_alarm">允許應用程式安排時間精確的操作</string>
<string name="text_permission_vibrate">控制手機震動</string>
<string name="text_permission_internet">允許應用程式訪問網路</string>
<string name="text_permission_access_network_state">允許應用程式查看網路連接狀態</string>
<string name="text_permission_system_alert_window">允許應用程式顯示在其他應用程式上層</string>
<string name="text_permission_reorder_tasks">允許應用程式對正在運行的應用程式重新排序</string>
<string name="text_permission_request_ignore_battery_optimizations">允許應用程式請求忽略電池優化</string>
<string name="text_permission_receive_boot_completed">允許應用程式在設備啟動時接收廣播</string>
<string name="text_permission_post_notifications">允許應用程式顯示通知</string>
<string name="text_permission_foreground_service">允許應用程式運行前景服務</string>
<string name="text_permission_foreground_service_media_projection">允許應用程式在前景服務中使用螢幕錄製和媒體投影功能</string>
<string name="text_permission_foreground_service_special_use">允許應用程式在前景服務中執行一些特殊操作</string>
<string name="text_permission_unlimited_toasts">允許應用程式顯示無限數量的Toast通知</string>
<string name="text_permission_capture_video_output">允許應用程式捕獲視頻輸出</string>
<string name="text_permission_dump">允許應用程式轉儲系統資訊</string>
<string name="text_permission_query_all_packages">允許應用程式查詢所有軟件包</string>
<string name="text_permission_package_usage_stats">允許應用程式訪問其他應用程式的使用統計數據</string>
<string name="text_permission_write_settings">允許應用程式修改系統設定</string>
<string name="text_permission_write_secure_settings">允許應用程式讀寫系統敏感設定</string>
<string name="text_permission_manage_users">允許應用程式管理使用者</string>
<string name="text_permission_interact_across_users_full">允許應用程式跨使用者互動</string>
<string name="text_permission_access_coarse_location">允許應用程式通過網路訪問粗略的位置信息</string>
<string name="text_permission_access_fine_location">允許應用程式通過GPS獲取精確的位置信息</string>
<string name="text_permission_record_audio">允許應用程式錄音</string>
<string name="text_permission_run_command">特定於Termux應用程式允許執行命令</string>
<string name="text_permission_read_phone_state">允許應用程式讀取手機狀態和身份</string>
<string name="text_permission_read_sms">允許應用程式讀取簡訊</string>
<string name="text_permission_shizuku">允許應用程式通過Shizuku服務與系統進行更高權限的交互</string>
<string name="text_switch_window">切換視窗</string>
<string name="text_symbols_settings">符號設定</string>
<string name="text_tailor_made_developer">二次開發者</string>

View File

@@ -753,6 +753,88 @@
<string name="text_supported_abis_short_32bit">支持 ABI (32 位)</string>
<string name="text_supported_abis_short_64bit">支持 ABI (64 位)</string>
<string name="text_supported_libraries_short">支持库</string>
<string name="text_signature_configuration">签名配置</string>
<string name="text_key_store">密钥库</string>
<string name="text_default_key_store">默认密钥库</string>
<string name="text_manage_key_store">管理密钥库</string>
<string name="text_signature_scheme">签名方案</string>
<string name="text_new_key_store">生成签名密钥</string>
<string name="text_key_store_password">密钥库密码</string>
<string name="text_key_alias">别名</string>
<string name="text_alias_password">别名密码</string>
<string name="text_signature_algorithm">签名算法</string>
<string name="text_validity_years">有效期 (年)</string>
<string name="text_first_and_last_name">姓名</string>
<string name="text_organization">组织名称</string>
<string name="text_organizational_unit">组织单位</string>
<string name="text_country_code">国家代码 (XX)</string>
<string name="text_state_or_province">州或省份</string>
<string name="text_city_or_locality">城市或区域</string>
<string name="text_street">街道</string>
<string name="text_filename_cannot_be_empty">文件名不能为空</string>
<string name="text_filename_cannot_contain_invalid_character">文件名不能包含下列任何字符: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">文件名太长</string>
<string name="text_password_requires_at_least_n_characters">密码至少需要%d位字符</string>
<string name="text_alias_cannot_be_empty">别名不能为空</string>
<string name="text_validity_years_cannot_be_empty">有效年份不能为空</string>
<string name="text_validity_years_cannot_be_zero">有效年份不能为0</string>
<string name="text_country_code_must_be_two_capital_letters">国家代码必须为两个大写字母</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">“姓名、组织名称、组织单位、国家代码、州或省份、城市或区域、街道”至少填写一个</string>
<string name="text_successfully_created_key_store">成功生成签名密钥</string>
<string name="text_failed_to_create_key_store">生成签名密钥失败</string>
<string name="text_key_store_has_not_been_verified">密钥尚未验证</string>
<string name="text_key_store_has_been_verified">密钥已验证</string>
<string name="text_verify">验证</string>
<string name="text_delete_all">删除全部</string>
<string name="text_unverified">未验证</string>
<string name="text_verified">已验证</string>
<string name="text_verify_key_store">验证签名密钥</string>
<string name="text_verify_success">验证成功</string>
<string name="text_verify_failed">验证失败</string>
<string name="text_file_path">文件路径</string>
<string name="text_supported_permissions_short">需要的权限</string>
<string name="text_permission_access_wifi_state">允许应用访问Wi-Fi状态</string>
<string name="text_permission_write_external_storage">允许应用写入外部存储</string>
<string name="text_permission_read_external_storage">允许应用读取外部存储</string>
<string name="text_permission_read_media_images">允许应用读取共享存储中的图片文件</string>
<string name="text_permission_read_media_video">允许应用读取共享存储中的视频文件</string>
<string name="text_permission_read_media_audio">允许应用读取共享存储中的音频文件</string>
<string name="text_permission_manage_external_storage">允许应用管理外部存储中的所有文件</string>
<string name="text_permission_broadcast_close_system_dialogs">允许应用发送一个意图来关闭系统对话框</string>
<string name="text_permission_read_privileged_phone_state">允许应用访问所有电话状态信息</string>
<string name="text_permission_install_shortcut">允许应用安装快捷方式</string>
<string name="text_permission_uninstall_shortcut">允许应用卸载快捷方式</string>
<string name="text_permission_request_install_packages">允许应用请求安装其他应用</string>
<string name="text_permission_wake_lock">防止手机进入休眠状态</string>
<string name="text_permission_use_exact_alarm">允许应用安排精确的闹钟或事件提醒</string>
<string name="text_permission_schedule_exact_alarm">允许应用安排时间精确的操作</string>
<string name="text_permission_vibrate">控制手机振动</string>
<string name="text_permission_internet">允许应用访问网络</string>
<string name="text_permission_access_network_state">允许应用查看网络连接状态</string>
<string name="text_permission_system_alert_window">允许应用显示在其他应用的上层</string>
<string name="text_permission_reorder_tasks">允许应用对正在运行的应用重新排序</string>
<string name="text_permission_request_ignore_battery_optimizations">允许应用请求忽略电池优化</string>
<string name="text_permission_receive_boot_completed">允许应用在设备启动时接收广播</string>
<string name="text_permission_post_notifications">允许应用显示通知</string>
<string name="text_permission_foreground_service">允许应用运行前台服务</string>
<string name="text_permission_foreground_service_media_projection">允许应用在前台服务中使用屏幕录制和媒体投影功能</string>
<string name="text_permission_foreground_service_special_use">允许应用在前台服务中执行一些特殊操作</string>
<string name="text_permission_unlimited_toasts">允许应用显示无限数量的Toast通知</string>
<string name="text_permission_capture_video_output">允许应用捕获视频输出</string>
<string name="text_permission_dump">允许应用转储系统信息</string>
<string name="text_permission_query_all_packages">允许应用查询所有软件包</string>
<string name="text_permission_package_usage_stats">允许应用访问其他应用的使用统计数据</string>
<string name="text_permission_write_settings">允许应用修改系统设置</string>
<string name="text_permission_write_secure_settings">允许应用读写系统敏感设置</string>
<string name="text_permission_manage_users">允许应用管理用户</string>
<string name="text_permission_interact_across_users_full">允许应用跨用户交互</string>
<string name="text_permission_access_coarse_location">允许应用通过网络访问粗略的位置信息</string>
<string name="text_permission_access_fine_location">允许应用通过GPS获取精确的位置信息</string>
<string name="text_permission_record_audio">允许应用录音</string>
<string name="text_permission_run_command">特定于Termux应用允许运行命令</string>
<string name="text_permission_read_phone_state">允许应用读取手机状态和身份</string>
<string name="text_permission_read_sms">允许应用读取短信</string>
<string name="text_permission_shizuku">允许应用通过 Shizuku 服务与系统进行更高权限的交互</string>
<string name="text_switch_window">切换窗口</string>
<string name="text_symbols_settings">符号设置</string>
<string name="text_tailor_made_developer">二次开发者</string>

View File

@@ -966,6 +966,94 @@
<string name="text_supported_abis_short_32bit">ABIs (32-bit)</string>
<string name="text_supported_abis_short_64bit">ABIs (64-bit)</string>
<string name="text_supported_libraries_short">Libraries</string>
<string name="text_jks" translatable="false">JKS</string>
<string name="text_bks" translatable="false">BKS</string>
<string name="text_default_alias" translatable="false">key0</string>
<string name="text_default_validity_years" translatable="false">25</string>
<string name="text_default_country_code" translatable="false">CN</string>
<string name="text_str_colon_space_str_formatter" translatable="false">%s: %s</string>
<string name="text_signature_configuration">Signature Configuration</string>
<string name="text_key_store">Keystore</string>
<string name="text_default_key_store">Default Keystore</string>
<string name="text_manage_key_store">Manage Keystore</string>
<string name="text_signature_scheme">Signature Scheme</string>
<string name="text_new_key_store">New Key Store</string>
<string name="text_key_store_password">Key Store Password</string>
<string name="text_key_alias">Alias</string>
<string name="text_alias_password">Alias Password</string>
<string name="text_signature_algorithm">Signature Algorithm</string>
<string name="text_validity_years">Validity (Years)</string>
<string name="text_first_and_last_name">Full Name</string>
<string name="text_organization">Organization Name</string>
<string name="text_organizational_unit">Organizational Unit</string>
<string name="text_country_code">Country Code (XX)</string>
<string name="text_state_or_province">State or Province</string>
<string name="text_city_or_locality">City or Locality</string>
<string name="text_street">Street</string>
<string name="text_filename_cannot_be_empty">Filename cannot be empty</string>
<string name="text_filename_cannot_contain_invalid_character">Filename cannot contain the following characters: \\ / : * ? &quot; &lt; &gt; |</string>
<string name="text_filename_is_too_long">Filename is too long</string>
<string name="text_password_requires_at_least_n_characters">Password must be at least %d characters long</string>
<string name="text_alias_cannot_be_empty">Alias cannot be empty</string>
<string name="text_validity_years_cannot_be_empty">Validity years cannot be empty</string>
<string name="text_validity_years_cannot_be_zero">Validity years cannot be zero</string>
<string name="text_country_code_must_be_two_capital_letters">Country code must be two capital letters</string>
<string name="text_at_least_one_certificate_issuer_field_is_not_empty">At least one field from \"Full Name, Organization Name, Organizational Unit, Country Code, State or Province, City or Locality, Street\" must be filled</string>
<string name="text_successfully_created_key_store">Successfully created signature key</string>
<string name="text_failed_to_create_key_store">Failed to create signature key</string>
<string name="text_key_store_has_not_been_verified">Keystore has not been verified</string>
<string name="text_key_store_has_been_verified">Keystore has been verified</string>
<string name="text_verify">Verify</string>
<string name="text_delete_all">Delete All</string>
<string name="text_unverified">Unverified</string>
<string name="text_verified">Verified</string>
<string name="text_verify_key_store">Verify Keystore</string>
<string name="text_verify_success">Verification successful</string>
<string name="text_verify_failed">Verification failed</string>
<string name="text_file_path">File Path</string>
<string name="text_supported_permissions_short">Permissions</string>
<string name="text_permission_access_wifi_state">Allow the app to access Wi-Fi state</string>
<string name="text_permission_write_external_storage">Allow the app to write to external storage</string>
<string name="text_permission_read_external_storage">Allow the app to read from external storage</string>
<string name="text_permission_read_media_images">Allow the app to read image files from shared storage</string>
<string name="text_permission_read_media_video">Allow the app to read video files from shared storage</string>
<string name="text_permission_read_media_audio">Allow the app to read audio files from shared storage</string>
<string name="text_permission_manage_external_storage">Allow the app to manage all files in external storage</string>
<string name="text_permission_broadcast_close_system_dialogs">Allow the app to send an intent to close system dialogs</string>
<string name="text_permission_read_privileged_phone_state">Allow the app to access all phone state information</string>
<string name="text_permission_install_shortcut">Allow the app to install shortcuts</string>
<string name="text_permission_uninstall_shortcut">Allow the app to uninstall shortcuts</string>
<string name="text_permission_request_install_packages">Allow the app to request installation of other apps</string>
<string name="text_permission_wake_lock">Prevent the phone from going to sleep</string>
<string name="text_permission_use_exact_alarm">Allow the app to schedule exact alarms or event reminders</string>
<string name="text_permission_schedule_exact_alarm">Allow the app to schedule time-precise operations</string>
<string name="text_permission_vibrate">Allow the app to control phone vibration</string>
<string name="text_permission_internet">Allow the app to access the internet</string>
<string name="text_permission_access_network_state">Allow the app to view network connection status</string>
<string name="text_permission_system_alert_window">Allow the app to display over other apps</string>
<string name="text_permission_reorder_tasks">Allow the app to reorder running tasks</string>
<string name="text_permission_request_ignore_battery_optimizations">Allow the app to request ignoring battery optimizations</string>
<string name="text_permission_receive_boot_completed">Allow the app to receive broadcast when device boot completes</string>
<string name="text_permission_post_notifications">Allow the app to post notifications</string>
<string name="text_permission_foreground_service">Allow the app to run foreground services</string>
<string name="text_permission_foreground_service_media_projection">Allow the app to use screen recording and media projection in foreground services</string>
<string name="text_permission_foreground_service_special_use">Allow the app to perform special operations in foreground services</string>
<string name="text_permission_unlimited_toasts">Allow the app to show unlimited Toast notifications</string>
<string name="text_permission_capture_video_output">Allow the app to capture video output</string>
<string name="text_permission_dump">Allow the app to dump system information</string>
<string name="text_permission_query_all_packages">Allow the app to query all packages</string>
<string name="text_permission_package_usage_stats">Allow the app to access usage statistics of other apps</string>
<string name="text_permission_write_settings">Allow the app to modify system settings</string>
<string name="text_permission_write_secure_settings">Allow the app to read/write secure system settings</string>
<string name="text_permission_manage_users">Allow the app to manage users</string>
<string name="text_permission_interact_across_users_full">Allow the app to interact across users</string>
<string name="text_permission_access_coarse_location">Allow the app to access approximate location via network</string>
<string name="text_permission_access_fine_location">Allow the app to access precise location via GPS</string>
<string name="text_permission_record_audio">Allow the app to record audio</string>
<string name="text_permission_run_command">Specific to Termux app, allow running commands</string>
<string name="text_permission_read_phone_state">Allow the app to read phone state and identity</string>
<string name="text_permission_read_sms">Allow the app to read SMS</string>
<string name="text_permission_shizuku">Allow the app to interact with the system with elevated permissions via Shizuku service</string>
<string name="text_switch_window">Switch window</string>
<string name="text_symbols_settings">Symbols settings</string>
<string name="text_tailor_made_developer">Tailor-made developer</string>