Fully Implement Silent Installation

Automated Code Formatting
This commit is contained in:
LooKeR 2021-10-13 00:32:34 +05:30
parent 8c8b8509a7
commit a8336bbde0
8 changed files with 432 additions and 378 deletions

View File

@ -5,21 +5,17 @@ import android.app.Application
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.*
import android.content.pm.PackageInfo
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.database.Database
import com.looker.droidify.entity.InstalledItem
import com.looker.droidify.index.RepositoryUpdater
import com.looker.droidify.network.Downloader
import com.looker.droidify.network.PicassoDownloader
import com.looker.droidify.service.Connection
import com.looker.droidify.service.SyncService
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.Utils.toInstalledItem
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.android.singleSignature
import com.looker.droidify.utility.extension.android.versionCodeCompat
import com.squareup.picasso.OkHttp3Downloader
import com.squareup.picasso.Picasso
import java.net.InetSocketAddress
@ -27,10 +23,6 @@ import java.net.Proxy
@Suppress("unused")
class MainApplication : Application() {
private fun PackageInfo.toInstalledItem(): InstalledItem {
val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty()
return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString)
}
override fun onCreate() {
super.onCreate()

View File

@ -26,6 +26,8 @@ import com.looker.droidify.service.Connection
import com.looker.droidify.service.DownloadService
import com.looker.droidify.utility.RxUtils
import com.looker.droidify.utility.Utils
import com.looker.droidify.utility.Utils.startPackageInstaller
import com.looker.droidify.utility.Utils.startUpdate
import com.looker.droidify.utility.extension.android.*
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
@ -134,7 +136,6 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks {
}
addOnScrollListener(scrollListener)
addItemDecoration(adapter.gridItemDecoration)
// addItemDecoration(DividerItemDecoration(context, adapter::configureDivider))
savedInstanceState?.getParcelable<ProductAdapter.SavedState>(STATE_ADAPTER)
?.let(adapter::restoreState)
layoutManagerState = savedInstanceState?.getParcelable(STATE_LAYOUT_MANAGER)
@ -385,27 +386,7 @@ class ProductFragment() : ScreenFragment(), ProductAdapter.Callbacks {
ProductAdapter.Action.INSTALL,
ProductAdapter.Action.UPDATE -> {
val installedItem = installed?.installedItem
val productRepository = Product.findSuggested(products, installedItem) { it.first }
val compatibleReleases = productRepository?.first?.selectedReleases.orEmpty()
.filter { installedItem == null || installedItem.signature == it.signature }
val release = if (compatibleReleases.size >= 2) {
compatibleReleases
.filter { it.platforms.contains(Android.primaryPlatform) }
.minByOrNull { it.platforms.size }
?: compatibleReleases.minByOrNull { it.platforms.size }
?: compatibleReleases.firstOrNull()
} else {
compatibleReleases.firstOrNull()
}
val binder = downloadConnection.binder
if (productRepository != null && release != null && binder != null) {
binder.enqueue(
packageName,
productRepository.first.name,
productRepository.second,
release
)
} else Unit
startUpdate(packageName, installedItem, products, downloadConnection)
}
ProductAdapter.Action.LAUNCH -> {
val launcherActivities = installed?.launcherActivities.orEmpty()

View File

@ -1,7 +1,6 @@
package com.looker.droidify.screen
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.os.Parcel
import android.view.ViewGroup
@ -11,15 +10,12 @@ import android.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.database.CursorOwner
import com.looker.droidify.utility.KParcelable
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.Utils.startPackageInstaller
import com.looker.droidify.utility.extension.resources.getDrawableFromAttr
import com.looker.droidify.utility.extension.text.nullIfEmpty
import com.topjohnwu.superuser.Shell
import java.io.File
abstract class ScreenActivity : FragmentActivity() {
companion object {
@ -219,11 +215,7 @@ abstract class ScreenActivity : FragmentActivity() {
is SpecialIntent.Install -> {
val packageName = specialIntent.packageName
if (!packageName.isNullOrEmpty()) {
val fragment = currentFragment
if (fragment !is ProductFragment || fragment.packageName != packageName) {
pushFragment(ProductFragment(packageName))
}
specialIntent.cacheFileName?.let(::startPackageInstaller)
specialIntent.cacheFileName?.let { startPackageInstaller(it) }
}
Unit
}
@ -244,37 +236,6 @@ abstract class ScreenActivity : FragmentActivity() {
}
}
internal fun startPackageInstaller(cacheFileName: String) {
val file = Cache.getReleaseFile(this, cacheFileName)
if (Preferences[Preferences.Key.RootPermission]) {
val commandBuilder = StringBuilder()
commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ")
commandBuilder.append(
getPackageInstallCommand(file)
)
commandBuilder.append(" ; settings put global verifier_verify_adb_installs 1")
Shell.su(commandBuilder.toString()).exec()
} else {
val (uri, flags) = if (Android.sdk(24)) {
Pair(
Cache.getReleaseUri(this, cacheFileName),
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} else {
Pair(Uri.fromFile(file), 0)
}
// TODO Handle deprecation
@Suppress("DEPRECATION")
startActivity(
Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags)
)
}
}
private fun getPackageInstallCommand(cacheFile: File): String =
"cat \"${cacheFile.absolutePath}\" | pm install -t -r -S ${cacheFile.length()}"
internal fun navigateProduct(packageName: String) = pushFragment(ProductFragment(packageName))
internal fun navigateRepositories() = pushFragment(RepositoriesFragment())
internal fun navigatePreferences() = pushFragment(SettingsFragment())

View File

@ -182,7 +182,9 @@ class SettingsFragment : ScreenFragment() {
preferences[Preferences.Key.ProxyHost]?.setEnabled(enabled)
preferences[Preferences.Key.ProxyPort]?.setEnabled(enabled)
}
preferences[Preferences.Key.RootPermission]?.setEnabled(Shell.getShell().isRoot)
preferences[Preferences.Key.RootPermission]?.setEnabled(
Shell.getCachedShell()?.isRoot ?: Shell.getShell().isRoot
)
if (key == Preferences.Key.Theme) {
requireActivity().recreate()
}

View File

@ -14,6 +14,7 @@ import com.looker.droidify.Common
import com.looker.droidify.MainActivity
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.entity.Release
import com.looker.droidify.entity.Repository
import com.looker.droidify.network.Downloader
@ -300,9 +301,17 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
stateSubject.onNext(State.Success(task.packageName, task.name, task.release) {
consumed = true
})
if (!consumed) {
showNotificationInstall(task)
}
if (consumed || (Preferences[Preferences.Key.RootPermission])) {
PendingIntent.getBroadcast(
this,
0,
Intent(this, Receiver::class.java)
.setAction("$ACTION_INSTALL.${task.packageName}")
.putExtra(EXTRA_CACHE_FILE_NAME, task.release.cacheFileName),
PendingIntent.FLAG_UPDATE_CURRENT
)
.send()
} else showNotificationInstall(task)
}
private fun validatePackage(task: Task, file: File): ValidationError? {
@ -436,7 +445,7 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
.observeOn(AndroidSchedulers.mainThread())
.subscribe { result, throwable ->
currentTask = null
throwable?.printStackTrace()
throwable.printStackTrace()
if (result == null || !result.success) {
showNotificationError(
task,

View File

@ -1,15 +1,31 @@
package com.looker.droidify.utility
import android.animation.ValueAnimator
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageInfo
import android.content.pm.Signature
import android.graphics.drawable.Drawable
import android.net.Uri
import android.provider.Settings
import android.util.Log
import com.looker.droidify.R
import com.looker.droidify.content.Cache
import com.looker.droidify.content.Preferences
import com.looker.droidify.entity.InstalledItem
import com.looker.droidify.entity.Product
import com.looker.droidify.entity.Repository
import com.looker.droidify.service.Connection
import com.looker.droidify.service.DownloadService
import com.looker.droidify.utility.extension.android.Android
import com.looker.droidify.utility.extension.android.singleSignature
import com.looker.droidify.utility.extension.android.versionCodeCompat
import com.looker.droidify.utility.extension.resources.getColorFromAttr
import com.looker.droidify.utility.extension.resources.getDrawableCompat
import com.looker.droidify.utility.extension.text.hex
import com.topjohnwu.superuser.Shell
import java.io.File
import java.security.MessageDigest
import java.security.cert.Certificate
import java.security.cert.CertificateEncodingException
@ -21,6 +37,11 @@ object Utils {
.apply { setTintList(context.getColorFromAttr(tintAttrResId)) }
}
fun PackageInfo.toInstalledItem(): InstalledItem {
val signatureString = singleSignature?.let(Utils::calculateHash).orEmpty()
return InstalledItem(packageName, versionName.orEmpty(), versionCodeCompat, signatureString)
}
fun getDefaultApplicationIcons(context: Context): Pair<Drawable, Drawable> {
val progressIcon: Drawable =
createDefaultApplicationIcon(context, android.R.attr.textColorSecondary)
@ -78,4 +99,92 @@ object Utils {
) != 0f
}
}
internal fun Activity.startPackageInstaller(cacheFileName: String) {
val file = Cache.getReleaseFile(this, cacheFileName)
if (Preferences[Preferences.Key.RootPermission]) {
val commandBuilder = StringBuilder()
val verifyState = getVerifyState()
if (verifyState == "1") commandBuilder.append("settings put global verifier_verify_adb_installs 0 ; ")
commandBuilder.append(getPackageInstallCommand(file))
commandBuilder.append(" ; settings put global verifier_verify_adb_installs $verifyState")
val result = Shell.su(commandBuilder.toString()).exec()
if (result.isSuccess) Shell.su("${getUtilBoxPath()} rm ${quote(file.absolutePath)}")
} else {
val (uri, flags) = if (Android.sdk(24)) {
Pair(
Cache.getReleaseUri(this, cacheFileName),
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
} else {
Pair(Uri.fromFile(file), 0)
}
// TODO Handle deprecation
@Suppress("DEPRECATION")
startActivity(
Intent(Intent.ACTION_INSTALL_PACKAGE)
.setDataAndType(uri, "application/vnd.android.package-archive").setFlags(flags)
)
}
}
fun startUpdate(
packageName: String,
installedItem: InstalledItem?,
products: List<Pair<Product, Repository>>,
downloadConnection: Connection<DownloadService.Binder, DownloadService>
) {
val productRepository = Product.findSuggested(products, installedItem) { it.first }
val compatibleReleases = productRepository?.first?.selectedReleases.orEmpty()
.filter { installedItem == null || installedItem.signature == it.signature }
val release = if (compatibleReleases.size >= 2) {
compatibleReleases
.filter { it.platforms.contains(Android.primaryPlatform) }
.minByOrNull { it.platforms.size }
?: compatibleReleases.minByOrNull { it.platforms.size }
?: compatibleReleases.firstOrNull()
} else {
compatibleReleases.firstOrNull()
}
val binder = downloadConnection.binder
if (productRepository != null && release != null && binder != null) {
binder.enqueue(
packageName,
productRepository.first.name,
productRepository.second,
release
)
} else Unit
}
private fun getPackageInstallCommand(cacheFile: File): String =
"cat \"${cacheFile.absolutePath}\" | pm install -t -r -S ${cacheFile.length()}"
private fun getVerifyState(): String =
Shell.sh("settings get global verifier_verify_adb_installs").exec().out[0]
private fun quote(string: String) =
"\"${string.replace(Regex("""[\\$"`]""")) { c -> "\\${c.value}" }}\""
private fun getUtilBoxPath(): String {
listOf("toybox", "busybox").forEach {
var shellResult = Shell.su("which $it").exec()
if (shellResult.out.isNotEmpty()) {
val utilBoxPath = shellResult.out.joinToString("")
if (utilBoxPath.isNotEmpty()) {
val utilBoxQuoted = quote(utilBoxPath)
shellResult = Shell.su("$utilBoxQuoted --version").exec()
if (shellResult.out.isNotEmpty()) {
val utilBoxVersion = shellResult.out.joinToString("")
Log.i(
this.javaClass.canonicalName,
"Using Utilbox $it : $utilBoxQuoted $utilBoxVersion"
)
}
return utilBoxQuoted
}
}
}
return ""
}
}

View File

@ -1,172 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_failed">A ação falhou</string>
<string name="add_repository">Adicionar repositório</string>
<string name="address">Endereço</string>
<string name="all_applications">Todos os aplicativos</string>
<string name="all_applications_up_to_date">Todos os aplicativos estão atualizados</string>
<string name="already_exists">Já existe</string>
<string name="always">Sempre</string>
<string name="amoled">Amoled</string>
<string name="anti_features">Características indesejadas</string>
<string name="application">Aplicativo</string>
<string name="application_not_found">Aplicativo não encontrado</string>
<string name="author_email">Email do autor</string>
<string name="author_website">Página do autor</string>
<string name="available">Disponível</string>
<string name="bug_tracker">Rastreador de erros</string>
<string name="cancel">Cancelar</string>
<string name="cant_edit_sync_DESC">Não é possível editar o repositório pois ele está sincronizando no momento.</string>
<string name="changelog">Lista de mudanças</string>
<string name="changes">Mudanças</string>
<string name="checking_repository">Checando o repositório</string>
<string name="compiled_for_debugging">Compilado para depuração</string>
<string name="confirmation">Confirmação</string>
<string name="connecting">Conectando</string>
<string name="contains_non_free_media">Contém mídia não livre</string>
<string name="could_not_download_FORMAT">Não foi possível baixar %s</string>
<string name="could_not_sync_FORMAT">Não foi possível sincronizar %s</string>
<string name="could_not_validate_FORMAT">Não foi possível validar %s</string>
<string name="dark">Escuro</string>
<string name="date_added">Data de adição</string>
<string name="delete">Excluir</string>
<string name="delete_repository_DESC">Tem certeza que deseja excluir o repositório?</string>
<string name="description">Descrição</string>
<string name="details">Detalhes</string>
<string name="donate">Doar</string>
<string name="downloaded_FORMAT">Baixado %s</string>
<string name="downloading">Baixando</string>
<string name="downloading_FORMAT">Baixando %s</string>
<string name="edit_repository">Editar repositório</string>
<string name="file_format_error_DESC">Formato de arquivo inválido.</string>
<string name="fingerprint">Fingerprint</string>
<string name="has_advertising">Contém anúncio</string>
<string name="has_non_free_dependencies">Possui dependências não livres</string>
<string name="has_security_vulnerabilities">Possui vulnerabilidades de segurança</string>
<string name="http_error_DESC">Resposta de servidor inválida.</string>
<string name="http_proxy">Proxy HTTP</string>
<string name="ignore_all_updates">Ignorar todas as atualizações</string>
<string name="ignore_this_update">Ignorar essa atualização</string>
<string name="incompatible_api_DESC_FORMAT">Sua %1$s (Versão da API %2$d) não é suportado. %3$s</string>
<string name="incompatible_api_max_DESC_FORMAT">A versão máxima da API é %d.</string>
<string name="incompatible_api_min_DESC_FORMAT">A versão mínima da API é %d.</string>
<string name="incompatible_features_DESC">Funcionalidades que estão faltando.</string>
<string name="incompatible_older_DESC">Esta versão é mais antiga que a instalada no seu dispositivo.
<string name="action_failed">A ação falhou</string>
<string name="add_repository">Adicionar repositório</string>
<string name="address">Endereço</string>
<string name="all_applications">Todos os aplicativos</string>
<string name="all_applications_up_to_date">Todos os aplicativos estão atualizados</string>
<string name="already_exists">Já existe</string>
<string name="always">Sempre</string>
<string name="amoled">Amoled</string>
<string name="anti_features">Características indesejadas</string>
<string name="application">Aplicativo</string>
<string name="application_not_found">Aplicativo não encontrado</string>
<string name="author_email">Email do autor</string>
<string name="author_website">Página do autor</string>
<string name="available">Disponível</string>
<string name="bug_tracker">Rastreador de erros</string>
<string name="cancel">Cancelar</string>
<string name="cant_edit_sync_DESC">Não é possível editar o repositório pois ele está sincronizando no momento.</string>
<string name="changelog">Lista de mudanças</string>
<string name="changes">Mudanças</string>
<string name="checking_repository">Checando o repositório</string>
<string name="compiled_for_debugging">Compilado para depuração</string>
<string name="confirmation">Confirmação</string>
<string name="connecting">Conectando</string>
<string name="contains_non_free_media">Contém mídia não livre</string>
<string name="could_not_download_FORMAT">Não foi possível baixar %s</string>
<string name="could_not_sync_FORMAT">Não foi possível sincronizar %s</string>
<string name="could_not_validate_FORMAT">Não foi possível validar %s</string>
<string name="dark">Escuro</string>
<string name="date_added">Data de adição</string>
<string name="delete">Excluir</string>
<string name="delete_repository_DESC">Tem certeza que deseja excluir o repositório?</string>
<string name="description">Descrição</string>
<string name="details">Detalhes</string>
<string name="donate">Doar</string>
<string name="downloaded_FORMAT">Baixado %s</string>
<string name="downloading">Baixando</string>
<string name="downloading_FORMAT">Baixando %s</string>
<string name="edit_repository">Editar repositório</string>
<string name="file_format_error_DESC">Formato de arquivo inválido.</string>
<string name="fingerprint">Fingerprint</string>
<string name="has_advertising">Contém anúncio</string>
<string name="has_non_free_dependencies">Possui dependências não livres</string>
<string name="has_security_vulnerabilities">Possui vulnerabilidades de segurança</string>
<string name="http_error_DESC">Resposta de servidor inválida.</string>
<string name="http_proxy">Proxy HTTP</string>
<string name="ignore_all_updates">Ignorar todas as atualizações</string>
<string name="ignore_this_update">Ignorar essa atualização</string>
<string name="incompatible_api_DESC_FORMAT">Sua %1$s (Versão da API %2$d) não é suportado. %3$s</string>
<string name="incompatible_api_max_DESC_FORMAT">A versão máxima da API é %d.</string>
<string name="incompatible_api_min_DESC_FORMAT">A versão mínima da API é %d.</string>
<string name="incompatible_features_DESC">Funcionalidades que estão faltando.</string>
<string name="incompatible_older_DESC">Esta versão é mais antiga que a instalada no seu dispositivo.
Desinstale a primeiro.</string>
<string name="incompatible_platforms_DESC_FORMAT">Sua %1$s plataforma não é suportada.
<string name="incompatible_platforms_DESC_FORMAT">Sua %1$s plataforma não é suportada.
Plataformas suportadas: %2$s.</string>
<string name="incompatible_signature_DESC">Esta versão é assinada com um certificado diferente do que está
<string name="incompatible_signature_DESC">Esta versão é assinada com um certificado diferente do que está
instalado no seu dispositivo. Desinstale-a primeiro.</string>
<string name="incompatible_version">Versão incompatível</string>
<string name="incompatible_versions">Versões incompatíveis</string>
<string name="incompatible_versions_summary">Mostrar versões de aplicativos incompatíveis com o dispositivo</string>
<string name="incompatible_with_FORMAT">Incompatível com %s</string>
<string name="install">Instalar</string>
<string name="installed">Instalado</string>
<string name="integrity_check_error_DESC">Não foi possível verificar a integridade.</string>
<string name="invalid_address">Endereço inválido</string>
<string name="invalid_fingerprint_format">Formato de fingerprint inválido</string>
<string name="invalid_metadata_error_DESC">Metadado inválido.</string>
<string name="invalid_permissions_error_DESC">Permissão inválido.</string>
<string name="invalid_signature_error_DESC">Assinatura inválida.</string>
<string name="invalid_username_format">Formato de nome do usuário inválido</string>
<string name="last_update">Última atualização</string>
<string name="launch">Abrir</string>
<string name="license">Licença</string>
<string name="license_FORMAT">Licença %s</string>
<string name="light">Claro</string>
<string name="link_copied_to_clipboard">Link copiado para a área de transferência</string>
<string name="links">Links</string>
<string name="merging_FORMAT">Incorporando %s</string>
<string name="name">Nome</string>
<string name="network_error_DESC">Erro da rede.</string>
<string name="never">Nunca</string>
<string name="new_updates_available">Novas atualizações disponíveis</string>
<plurals name="new_updates_DESC_FORMAT">
<item quantity="one">%d nova atualização.</item>
<item quantity="other">%d novas atualizações.</item>
</plurals>
<string name="no_applications_available">Não há aplicativos disponíveis</string>
<string name="no_applications_installed">Nenhum aplicativo instalado</string>
<string name="no_description_available_DESC">Nenhuma descrição disponível.</string>
<string name="no_matching_applications_found">Nenhum aplicativo correspondente encontrado</string>
<string name="no_proxy">Sem proxy</string>
<string name="notify_about_updates">Notificar sobre atualizações</string>
<string name="notify_about_updates_summary">Mostrar uma notificação quando atualizações estiverem disponíveis</string>
<string name="number_of_applications">Número de aplicativos</string>
<string name="ok">OK</string>
<string name="only_compatible_with_FORMAT">Somente compatível com %s</string>
<string name="only_on_wifi">Somente no Wi-Fi</string>
<string name="open_DESC_FORMAT">Abrir %s?</string>
<string name="other">Outro</string>
<string name="parsing_index_error_DESC">Não foi possível analisar o arquivo de índice.</string>
<string name="password">Senha</string>
<string name="password_missing">Falta a senha</string>
<string name="permissions">Permissões</string>
<string name="plus_more_FORMAT">+%d mais</string>
<string name="settings">Configurações</string>
<string name="processing_FORMAT">Processando %1$s</string>
<string name="project_website">Página do projeto</string>
<string name="promotes_non_free_network_services">Promove serviços de rede não livres</string>
<string name="promotes_non_free_software">Promove software não livre</string>
<string name="provided_by_FORMAT">Disponibilizado por %s</string>
<string name="proxy">Proxy</string>
<string name="proxy_host">Servidor de Proxy</string>
<string name="proxy_port">Porta de Proxy</string>
<string name="proxy_type">Tipo de Proxy</string>
<string name="repositories">Repositórios</string>
<string name="repository">Repositório</string>
<string name="repository_not_used_DESC">Este repositório ainda não foi usado. Você precisa o ativar para visualizar
<string name="incompatible_version">Versão incompatível</string>
<string name="incompatible_versions">Versões incompatíveis</string>
<string name="incompatible_versions_summary">Mostrar versões de aplicativos incompatíveis com o dispositivo</string>
<string name="incompatible_with_FORMAT">Incompatível com %s</string>
<string name="install">Instalar</string>
<string name="installed">Instalado</string>
<string name="integrity_check_error_DESC">Não foi possível verificar a integridade.</string>
<string name="invalid_address">Endereço inválido</string>
<string name="invalid_fingerprint_format">Formato de fingerprint inválido</string>
<string name="invalid_metadata_error_DESC">Metadado inválido.</string>
<string name="invalid_permissions_error_DESC">Permissão inválido.</string>
<string name="invalid_signature_error_DESC">Assinatura inválida.</string>
<string name="invalid_username_format">Formato de nome do usuário inválido</string>
<string name="last_update">Última atualização</string>
<string name="launch">Abrir</string>
<string name="license">Licença</string>
<string name="license_FORMAT">Licença %s</string>
<string name="light">Claro</string>
<string name="link_copied_to_clipboard">Link copiado para a área de transferência</string>
<string name="links">Links</string>
<string name="merging_FORMAT">Incorporando %s</string>
<string name="name">Nome</string>
<string name="network_error_DESC">Erro da rede.</string>
<string name="never">Nunca</string>
<string name="new_updates_available">Novas atualizações disponíveis</string>
<plurals name="new_updates_DESC_FORMAT">
<item quantity="one">%d nova atualização.</item>
<item quantity="other">%d novas atualizações.</item>
</plurals>
<string name="no_applications_available">Não há aplicativos disponíveis</string>
<string name="no_applications_installed">Nenhum aplicativo instalado</string>
<string name="no_description_available_DESC">Nenhuma descrição disponível.</string>
<string name="no_matching_applications_found">Nenhum aplicativo correspondente encontrado</string>
<string name="no_proxy">Sem proxy</string>
<string name="notify_about_updates">Notificar sobre atualizações</string>
<string name="notify_about_updates_summary">Mostrar uma notificação quando atualizações estiverem disponíveis</string>
<string name="number_of_applications">Número de aplicativos</string>
<string name="ok">OK</string>
<string name="only_compatible_with_FORMAT">Somente compatível com %s</string>
<string name="only_on_wifi">Somente no Wi-Fi</string>
<string name="open_DESC_FORMAT">Abrir %s?</string>
<string name="other">Outro</string>
<string name="parsing_index_error_DESC">Não foi possível analisar o arquivo de índice.</string>
<string name="password">Senha</string>
<string name="password_missing">Falta a senha</string>
<string name="permissions">Permissões</string>
<string name="plus_more_FORMAT">+%d mais</string>
<string name="settings">Configurações</string>
<string name="processing_FORMAT">Processando %1$s</string>
<string name="project_website">Página do projeto</string>
<string name="promotes_non_free_network_services">Promove serviços de rede não livres</string>
<string name="promotes_non_free_software">Promove software não livre</string>
<string name="provided_by_FORMAT">Disponibilizado por %s</string>
<string name="proxy">Proxy</string>
<string name="proxy_host">Servidor de Proxy</string>
<string name="proxy_port">Porta de Proxy</string>
<string name="proxy_type">Tipo de Proxy</string>
<string name="repositories">Repositórios</string>
<string name="repository">Repositório</string>
<string name="repository_not_used_DESC">Este repositório ainda não foi usado. Você precisa o ativar para visualizar
os aplicativos que ele fornece.</string>
<string name="repository_unsigned_DESC">Sem assinatura. Não foi possível verificar a lista de aplicativos. Tenha cuidado ao baixar
<string name="repository_unsigned_DESC">Sem assinatura. Não foi possível verificar a lista de aplicativos. Tenha cuidado ao baixar
aplicativos de repositórios sem assinatura.</string>
<string name="requires_FORMAT">Requer %s</string>
<string name="save">Salvar</string>
<string name="saving_details">Salvando detalhes</string>
<string name="screenshots">Capturas de tela</string>
<string name="search">Pesquisar</string>
<string name="select_mirror">Selecione um mirror</string>
<string name="show_more">Mostrar mais</string>
<string name="show_older_versions">Mostrar versões antigas</string>
<string name="signature_FORMAT">Assinatura %s</string>
<string name="signed_using_unsafe_algorithm">Assinado usando um algoritmo inseguro</string>
<string name="skip">Pular</string>
<string name="socks_proxy">SOCKS proxy</string>
<string name="sorting_order">Ordenar por</string>
<string name="source_code">Código fonte</string>
<string name="source_code_no_longer_available">Código fonte não está mais disponível</string>
<string name="suggested">Sugerido</string>
<string name="sync_repositories">Sincronizar repositórios</string>
<string name="sync_repositories_automatically">Sincronizar repositórios automaticamente</string>
<string name="syncing">Sincronizando</string>
<string name="syncing_FORMAT">Sincronizando %s</string>
<string name="system">Sistema</string>
<string name="tap_to_install_DESC">Toque para instalar.</string>
<string name="theme">Tema</string>
<string name="tracks_or_reports_your_activity">Rastreia ou relata sua atividade</string>
<string name="uninstall">Desinstalar</string>
<string name="unknown">Desconhecido</string>
<string name="unknown_error_DESC">Error desconhecido.</string>
<string name="unknown_FORMAT">Desconhecido: %s</string>
<string name="unsigned">Sem assinatura</string>
<string name="unstable_updates">Atualizações instáveis</string>
<string name="unstable_updates_summary">Sugerir instalar versões instáveis</string>
<string name="unverified">Não verificado</string>
<string name="update">Atualização</string>
<string name="updates">Atualizações</string>
<string name="upstream_source_code_is_not_free">O código fonte original não é livre</string>
<string name="username">Nome de usuário</string>
<string name="username_missing">Falta o nome de usuário</string>
<string name="validation_index_error_DESC">O índice não pôde ser validado.</string>
<string name="version_FORMAT">Versão %s</string>
<string name="versions">Versões</string>
<string name="waiting_to_start_download">Esperando para começar a baixar</string>
<string name="website">Página web</string>
<string name="root_permission">Instalação silenciosa</string>
<string name="root_permission_description">Permitir permissão de root para habilitar a instalação silenciosa</string>
<string name="themes">Temas</string>
<string name="credits">Créditos</string>
<string name="install_types">themes Tipos de instalação</string>
<string name="requires_FORMAT">Requer %s</string>
<string name="save">Salvar</string>
<string name="saving_details">Salvando detalhes</string>
<string name="screenshots">Capturas de tela</string>
<string name="search">Pesquisar</string>
<string name="select_mirror">Selecione um mirror</string>
<string name="show_more">Mostrar mais</string>
<string name="show_older_versions">Mostrar versões antigas</string>
<string name="signature_FORMAT">Assinatura %s</string>
<string name="signed_using_unsafe_algorithm">Assinado usando um algoritmo inseguro</string>
<string name="skip">Pular</string>
<string name="socks_proxy">SOCKS proxy</string>
<string name="sorting_order">Ordenar por</string>
<string name="source_code">Código fonte</string>
<string name="source_code_no_longer_available">Código fonte não está mais disponível</string>
<string name="suggested">Sugerido</string>
<string name="sync_repositories">Sincronizar repositórios</string>
<string name="sync_repositories_automatically">Sincronizar repositórios automaticamente</string>
<string name="syncing">Sincronizando</string>
<string name="syncing_FORMAT">Sincronizando %s</string>
<string name="system">Sistema</string>
<string name="tap_to_install_DESC">Toque para instalar.</string>
<string name="theme">Tema</string>
<string name="tracks_or_reports_your_activity">Rastreia ou relata sua atividade</string>
<string name="uninstall">Desinstalar</string>
<string name="unknown">Desconhecido</string>
<string name="unknown_error_DESC">Error desconhecido.</string>
<string name="unknown_FORMAT">Desconhecido: %s</string>
<string name="unsigned">Sem assinatura</string>
<string name="unstable_updates">Atualizações instáveis</string>
<string name="unstable_updates_summary">Sugerir instalar versões instáveis</string>
<string name="unverified">Não verificado</string>
<string name="update">Atualização</string>
<string name="updates">Atualizações</string>
<string name="upstream_source_code_is_not_free">O código fonte original não é livre</string>
<string name="username">Nome de usuário</string>
<string name="username_missing">Falta o nome de usuário</string>
<string name="validation_index_error_DESC">O índice não pôde ser validado.</string>
<string name="version_FORMAT">Versão %s</string>
<string name="versions">Versões</string>
<string name="waiting_to_start_download">Esperando para começar a baixar</string>
<string name="website">Página web</string>
<string name="root_permission">Instalação silenciosa</string>
<string name="root_permission_description">Permitir permissão de root para habilitar a instalação silenciosa</string>
<string name="themes">Temas</string>
<string name="credits">Créditos</string>
<string name="install_types">themes Tipos de instalação</string>
</resources>

View File

@ -1,150 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="action_failed">操作失败</string>
<string name="add_repository">添加存储库</string>
<string name="address">地址</string>
<string name="all_applications">全部应用</string>
<string name="all_applications_up_to_date">所有应用都是最新的</string>
<string name="already_exists">已经存在</string>
<string name="always">总是</string>
<string name="amoled">Amoled</string>
<string name="anti_features">不需要的特征</string>
<string name="application">应用</string>
<string name="application_not_found">应用未找到</string>
<string name="author_email">作者邮箱</string>
<string name="author_website">作者网站</string>
<string name="available">可用</string>
<string name="bug_tracker">错误追踪器</string>
<string name="cancel">取消</string>
<string name="cant_edit_sync_DESC">无法编辑存储库,因为它现在正在同步。</string>
<string name="changelog">变更日志</string>
<string name="changes">变更</string>
<string name="checking_repository">检查存储库</string>
<string name="compiled_for_debugging">编译调试</string>
<string name="confirmation">确认</string>
<string name="connecting">连接中</string>
<string name="contains_non_free_media">包含非自由媒体</string>
<string name="could_not_download_FORMAT">无法下载 %s</string>
<string name="could_not_sync_FORMAT">无法同步 %s</string>
<string name="could_not_validate_FORMAT">无法验证 %s</string>
<string name="dark">暗色</string>
<string name="date_added">添加日期</string>
<string name="delete">删除</string>
<string name="delete_repository_DESC">您确定要删除此存储库吗?</string>
<string name="description">描述</string>
<string name="details">详情</string>
<string name="donate">捐助</string>
<string name="downloaded_FORMAT">已下载 %s</string>
<string name="downloading">下载中</string>
<string name="downloading_FORMAT">正在下载 %s</string>
<string name="edit_repository">编辑存储库</string>
<string name="file_format_error_DESC">文件格式无效。</string>
<string name="fingerprint">指纹</string>
<string name="has_advertising">包含广告</string>
<string name="has_non_free_dependencies">包含非自由依赖</string>
<string name="has_security_vulnerabilities">包含安全漏洞</string>
<string name="http_error_DESC">服务器响应无效。</string>
<string name="http_proxy">HTTP 代理</string>
<string name="ignore_all_updates">忽略所有更新</string>
<string name="ignore_this_update">忽略此更新</string>
<string name="incompatible_api_DESC_FORMAT">您的 %1$sAPI 版本 %2$d不受支持。 %3$s</string>
<string name="incompatible_api_max_DESC_FORMAT">最大 API 版本为 %d。</string>
<string name="incompatible_api_min_DESC_FORMAT">最小 API 版本为 %d。</string>
<string name="incompatible_features_DESC">缺少的功能。</string>
<string name="incompatible_older_DESC">此版本比您设备上安装的版本旧。
<string name="action_failed">操作失败</string>
<string name="add_repository">添加存储库</string>
<string name="address">地址</string>
<string name="all_applications">全部应用</string>
<string name="all_applications_up_to_date">所有应用都是最新的</string>
<string name="already_exists">已经存在</string>
<string name="always">总是</string>
<string name="amoled">Amoled</string>
<string name="anti_features">不需要的特征</string>
<string name="application">应用</string>
<string name="application_not_found">应用未找到</string>
<string name="author_email">作者邮箱</string>
<string name="author_website">作者网站</string>
<string name="available">可用</string>
<string name="bug_tracker">错误追踪器</string>
<string name="cancel">取消</string>
<string name="cant_edit_sync_DESC">无法编辑存储库,因为它现在正在同步。</string>
<string name="changelog">变更日志</string>
<string name="changes">变更</string>
<string name="checking_repository">检查存储库</string>
<string name="compiled_for_debugging">编译调试</string>
<string name="confirmation">确认</string>
<string name="connecting">连接中</string>
<string name="contains_non_free_media">包含非自由媒体</string>
<string name="could_not_download_FORMAT">无法下载 %s</string>
<string name="could_not_sync_FORMAT">无法同步 %s</string>
<string name="could_not_validate_FORMAT">无法验证 %s</string>
<string name="dark">暗色</string>
<string name="date_added">添加日期</string>
<string name="delete">删除</string>
<string name="delete_repository_DESC">您确定要删除此存储库吗?</string>
<string name="description">描述</string>
<string name="details">详情</string>
<string name="donate">捐助</string>
<string name="downloaded_FORMAT">已下载 %s</string>
<string name="downloading">下载中</string>
<string name="downloading_FORMAT">正在下载 %s</string>
<string name="edit_repository">编辑存储库</string>
<string name="file_format_error_DESC">文件格式无效。</string>
<string name="fingerprint">指纹</string>
<string name="has_advertising">包含广告</string>
<string name="has_non_free_dependencies">包含非自由依赖</string>
<string name="has_security_vulnerabilities">包含安全漏洞</string>
<string name="http_error_DESC">服务器响应无效。</string>
<string name="http_proxy">HTTP 代理</string>
<string name="ignore_all_updates">忽略所有更新</string>
<string name="ignore_this_update">忽略此更新</string>
<string name="incompatible_api_DESC_FORMAT">您的 %1$sAPI 版本 %2$d不受支持。 %3$s</string>
<string name="incompatible_api_max_DESC_FORMAT">最大 API 版本为 %d。</string>
<string name="incompatible_api_min_DESC_FORMAT">最小 API 版本为 %d。</string>
<string name="incompatible_features_DESC">缺少的功能。</string>
<string name="incompatible_older_DESC">此版本比您设备上安装的版本旧。
请先卸载那个。</string>
<string name="incompatible_platforms_DESC_FORMAT">您的 %1$s 平台不受支持。
<string name="incompatible_platforms_DESC_FORMAT">您的 %1$s 平台不受支持。
支持的平台:%2$s。</string>
<string name="incompatible_signature_DESC">此版本使用不同的证书签名
<string name="incompatible_signature_DESC">此版本使用不同的证书签名
之前安装在您设备上的。请先卸载那个。</string>
<string name="incompatible_version">版本不兼容</string>
<string name="incompatible_versions">版本不兼容</string>
<string name="incompatible_versions_summary">显示与设备不兼容的应用版本</string>
<string name="incompatible_with_FORMAT">与 %s 不兼容</string>
<string name="install">安装</string>
<string name="installed">已安装</string>
<string name="integrity_check_error_DESC">无法检查完整性。</string>
<string name="invalid_address">地址无效</string>
<string name="invalid_fingerprint_format">指纹格式无效</string>
<string name="invalid_metadata_error_DESC">元数据无效。</string>
<string name="invalid_permissions_error_DESC">权限无效。</string>
<string name="invalid_signature_error_DESC">签名无效。</string>
<string name="invalid_username_format">用户名格式无效</string>
<string name="last_update">最近更新</string>
<string name="launch">启动</string>
<string name="license">许可证</string>
<string name="license_FORMAT">许可证 %s</string>
<string name="light">亮色</string>
<string name="link_copied_to_clipboard">链接已复制到剪贴板</string>
<string name="links">链接</string>
<string name="merging_FORMAT">合并 %s</string>
<string name="name">名称</string>
<string name="network_error_DESC">网络错误.</string>
<string name="never">从不</string>
<string name="new_updates_available">新的更新可用</string>
<plurals name="new_updates_DESC_FORMAT">
<item quantity="one">%d 个更新.</item>
<item quantity="other">%d 个更新.</item>
</plurals>
<string name="no_applications_available">没有可用的应用</string>
<string name="no_applications_installed">没有已安装的应用</string>
<string name="no_description_available_DESC">没有可用的描述。</string>
<string name="no_matching_applications_found">未找到匹配的应用</string>
<string name="no_proxy">无代理</string>
<string name="notify_about_updates">更新通知</string>
<string name="notify_about_updates_summary">有可用更新时显示通知</string>
<string name="number_of_applications">应用数量</string>
<string name="ok">好的</string>
<string name="only_compatible_with_FORMAT">仅与 %s 兼容</string>
<string name="only_on_wifi">仅连到 Wi-Fi 时</string>
<string name="open_DESC_FORMAT">打开 %s</string>
<string name="other">其他</string>
<string name="parsing_index_error_DESC">无法解析索引文件。</string>
<string name="password">密码</string>
<string name="password_missing">缺少密码</string>
<string name="permissions">权限</string>
<string name="plus_more_FORMAT">+%d 个</string>
<string name="settings">设置</string>
<string name="processing_FORMAT">正在处理 %1$s</string>
<string name="project_website">项目网站</string>
<string name="promotes_non_free_network_services">推广非自由网络服务</string>
<string name="promotes_non_free_software">推广非自由软件</string>
<string name="provided_by_FORMAT">由 %s 提供</string>
<string name="proxy">代理</string>
<string name="proxy_host">代理主机</string>
<string name="proxy_port">代理端口</string>
<string name="proxy_type">代理类型</string>
<string name="repositories">存储库</string>
<string name="repository">存储库</string>
<string name="repository_not_used_DESC">此存储库尚未使用。您需要启用它才能查看
<string name="incompatible_version">版本不兼容</string>
<string name="incompatible_versions">版本不兼容</string>
<string name="incompatible_versions_summary">显示与设备不兼容的应用版本</string>
<string name="incompatible_with_FORMAT">与 %s 不兼容</string>
<string name="install">安装</string>
<string name="installed">已安装</string>
<string name="integrity_check_error_DESC">无法检查完整性。</string>
<string name="invalid_address">地址无效</string>
<string name="invalid_fingerprint_format">指纹格式无效</string>
<string name="invalid_metadata_error_DESC">元数据无效。</string>
<string name="invalid_permissions_error_DESC">权限无效。</string>
<string name="invalid_signature_error_DESC">签名无效。</string>
<string name="invalid_username_format">用户名格式无效</string>
<string name="last_update">最近更新</string>
<string name="launch">启动</string>
<string name="license">许可证</string>
<string name="license_FORMAT">许可证 %s</string>
<string name="light">亮色</string>
<string name="link_copied_to_clipboard">链接已复制到剪贴板</string>
<string name="links">链接</string>
<string name="merging_FORMAT">合并 %s</string>
<string name="name">名称</string>
<string name="network_error_DESC">网络错误.</string>
<string name="never">从不</string>
<string name="new_updates_available">新的更新可用</string>
<plurals name="new_updates_DESC_FORMAT">
<item quantity="one">%d 个更新.</item>
<item quantity="other">%d 个更新.</item>
</plurals>
<string name="no_applications_available">没有可用的应用</string>
<string name="no_applications_installed">没有已安装的应用</string>
<string name="no_description_available_DESC">没有可用的描述。</string>
<string name="no_matching_applications_found">未找到匹配的应用</string>
<string name="no_proxy">无代理</string>
<string name="notify_about_updates">更新通知</string>
<string name="notify_about_updates_summary">有可用更新时显示通知</string>
<string name="number_of_applications">应用数量</string>
<string name="ok">好的</string>
<string name="only_compatible_with_FORMAT">仅与 %s 兼容</string>
<string name="only_on_wifi">仅连到 Wi-Fi 时</string>
<string name="open_DESC_FORMAT">打开 %s</string>
<string name="other">其他</string>
<string name="parsing_index_error_DESC">无法解析索引文件。</string>
<string name="password">密码</string>
<string name="password_missing">缺少密码</string>
<string name="permissions">权限</string>
<string name="plus_more_FORMAT">+%d 个</string>
<string name="settings">设置</string>
<string name="processing_FORMAT">正在处理 %1$s</string>
<string name="project_website">项目网站</string>
<string name="promotes_non_free_network_services">推广非自由网络服务</string>
<string name="promotes_non_free_software">推广非自由软件</string>
<string name="provided_by_FORMAT">由 %s 提供</string>
<string name="proxy">代理</string>
<string name="proxy_host">代理主机</string>
<string name="proxy_port">代理端口</string>
<string name="proxy_type">代理类型</string>
<string name="repositories">存储库</string>
<string name="repository">存储库</string>
<string name="repository_not_used_DESC">此存储库尚未使用。您需要启用它才能查看
它提供的应用程序。</string>
<string name="repository_unsigned_DESC">未签名。无法验证此应用列表。小心下载
<string name="repository_unsigned_DESC">未签名。无法验证此应用列表。小心下载
来自未签名存储库的应用。</string>
<string name="requires_FORMAT">需要 %s</string>
<string name="save">保存</string>
<string name="saving_details">保存详情</string>
<string name="screenshots">截图</string>
<string name="search">搜索</string>
<string name="select_mirror">选择一个镜像</string>
<string name="show_more">显示更多</string>
<string name="show_older_versions">显示旧版本</string>
<string name="signature_FORMAT">签名 %s</string>
<string name="signed_using_unsafe_algorithm">使用不安全算法签名</string>
<string name="skip">跳过</string>
<string name="socks_proxy">SOCKS 代理</string>
<string name="sorting_order">排序顺序</string>
<string name="source_code">源代码</string>
<string name="source_code_no_longer_available">源代码不再可用</string>
<string name="suggested">建议</string>
<string name="sync_repositories">同步存储库</string>
<string name="sync_repositories_automatically">自动同步存储库</string>
<string name="syncing">同步中</string>
<string name="syncing_FORMAT">同步中 %s</string>
<string name="system">系统</string>
<string name="tap_to_install_DESC">点击安装。</string>
<string name="theme">主题</string>
<string name="tracks_or_reports_your_activity">跟踪或报告您的活动</string>
<string name="requires_FORMAT">需要 %s</string>
<string name="save">保存</string>
<string name="saving_details">保存详情</string>
<string name="screenshots">截图</string>
<string name="search">搜索</string>
<string name="select_mirror">选择一个镜像</string>
<string name="show_more">显示更多</string>
<string name="show_older_versions">显示旧版本</string>
<string name="signature_FORMAT">签名 %s</string>
<string name="signed_using_unsafe_algorithm">使用不安全算法签名</string>
<string name="skip">跳过</string>
<string name="socks_proxy">SOCKS 代理</string>
<string name="sorting_order">排序顺序</string>
<string name="source_code">源代码</string>
<string name="source_code_no_longer_available">源代码不再可用</string>
<string name="suggested">建议</string>
<string name="sync_repositories">同步存储库</string>
<string name="sync_repositories_automatically">自动同步存储库</string>
<string name="syncing">同步中</string>
<string name="syncing_FORMAT">同步中 %s</string>
<string name="system">系统</string>
<string name="tap_to_install_DESC">点击安装。</string>
<string name="theme">主题</string>
<string name="tracks_or_reports_your_activity">跟踪或报告您的活动</string>
<string name="uninstall">卸载</string>
<string name="unknown">未知</string>
<string name="unknown_error_DESC">未知错误。</string>