Merge pull request #1230 from re7gog/re7gog

Fixes and system font
This commit is contained in:
Imran
2024-01-03 18:06:04 -05:00
committed by GitHub
28 changed files with 148 additions and 58 deletions

View File

@@ -96,19 +96,15 @@ repositories {
} }
dependencies { dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
def shizuku_version = '13.1.5' def shizuku_version = '13.1.5'
implementation "dev.rikka.shizuku:api:$shizuku_version" implementation "dev.rikka.shizuku:api:$shizuku_version"
implementation "dev.rikka.shizuku:provider:$shizuku_version" implementation "dev.rikka.shizuku:provider:$shizuku_version"
def hidden_api_version = '4.1.0' def hidden_api_version = '4.3.1'
// DO NOT UPDATE Hidden API without updating the Android tools
// and do not update Android tools without updating the whole Flutter
// (also in android/build.gradle)
implementation "dev.rikka.tools.refine:runtime:$hidden_api_version" implementation "dev.rikka.tools.refine:runtime:$hidden_api_version"
implementation "dev.rikka.hidden:compat:$hidden_api_version" implementation "dev.rikka.hidden:compat:$hidden_api_version"
compileOnly "dev.rikka.hidden:stub:$hidden_api_version" compileOnly "dev.rikka.hidden:stub:$hidden_api_version"
implementation "org.lsposed.hiddenapibypass:hiddenapibypass:4.3"
implementation "com.github.topjohnwu.libsu:core:5.2.2" implementation "com.github.topjohnwu.libsu:core:5.2.2"
} }

View File

@@ -0,0 +1,44 @@
package dev.imranr.obtainium
import android.util.Xml
import org.xmlpull.v1.XmlPullParser
import java.io.File
import java.io.FileInputStream
class DefaultSystemFont {
fun get(): String {
return try {
val file = File("/system/etc/fonts.xml")
val fileStream = FileInputStream(file)
parseFontsFileStream(fileStream)
} catch (e: Exception) {
e.message ?: "Unknown fonts.xml parsing exception"
}
}
private fun parseFontsFileStream(fileStream: FileInputStream): String {
fileStream.use { stream ->
val parser = Xml.newPullParser()
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false)
parser.setInput(stream, null)
parser.nextTag()
return parseFonts(parser)
}
}
private fun parseFonts(parser: XmlPullParser): String {
while (!((parser.next() == XmlPullParser.END_TAG) && (parser.name == "family"))) {
if ((parser.eventType == XmlPullParser.START_TAG) && (parser.name == "font")
&& (parser.getAttributeValue(null, "style") == "normal")
&& (parser.getAttributeValue(null, "weight") == "400")) {
break
}
}
parser.next()
val fontFile = parser.text.trim()
if (fontFile == "") {
throw NoSuchFieldException("The font filename couldn't be found in fonts.xml")
}
return "/system/fonts/$fontFile"
}
}

View File

@@ -22,12 +22,13 @@ import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result import io.flutter.plugin.common.MethodChannel.Result
import java.io.IOException import java.io.IOException
import java.util.concurrent.CountDownLatch import java.util.concurrent.CountDownLatch
import org.lsposed.hiddenapibypass.HiddenApiBypass
import rikka.shizuku.Shizuku import rikka.shizuku.Shizuku
import rikka.shizuku.Shizuku.OnRequestPermissionResultListener import rikka.shizuku.Shizuku.OnRequestPermissionResultListener
import rikka.shizuku.ShizukuBinderWrapper import rikka.shizuku.ShizukuBinderWrapper
class MainActivity: FlutterActivity() { class MainActivity: FlutterActivity() {
private var installersChannel: MethodChannel? = null private var nativeChannel: MethodChannel? = null
private val SHIZUKU_PERMISSION_REQUEST_CODE = (10..200).random() private val SHIZUKU_PERMISSION_REQUEST_CODE = (10..200).random()
private fun shizukuCheckPermission(result: Result) { private fun shizukuCheckPermission(result: Result) {
@@ -51,7 +52,7 @@ class MainActivity: FlutterActivity() {
requestCode: Int, grantResult: Int -> requestCode: Int, grantResult: Int ->
if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) { if (requestCode == SHIZUKU_PERMISSION_REQUEST_CODE) {
val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0 val res = if (grantResult == PackageManager.PERMISSION_GRANTED) 1 else 0
installersChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res)) nativeChannel!!.invokeMethod("resPermShizuku", mapOf("res" to res))
} }
} }
@@ -76,7 +77,8 @@ class MainActivity: FlutterActivity() {
val params = val params =
PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)
var installFlags: Int = PackageInstallerUtils.getInstallFlags(params) var installFlags: Int = PackageInstallerUtils.getInstallFlags(params)
installFlags = installFlags or 0x00000004 // PackageManager.INSTALL_ALLOW_TEST installFlags = installFlags or (0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/
or 0x00000004 /*PackageManager.INSTALL_ALLOW_TEST*/)
PackageInstallerUtils.setInstallFlags(params, installFlags) PackageInstallerUtils.setInstallFlags(params, installFlags)
val sessionId = packageInstaller.createSession(params) val sessionId = packageInstaller.createSession(params)
val iSession = IPackageInstallerSession.Stub.asInterface( val iSession = IPackageInstallerSession.Stub.asInterface(
@@ -136,7 +138,7 @@ class MainActivity: FlutterActivity() {
} }
private fun rootInstallApk(apkFilePath: String, result: Result) { private fun rootInstallApk(apkFilePath: String, result: Result) {
Shell.sh("pm install -R -t " + apkFilePath).submit { out -> Shell.sh("pm install -r -t " + apkFilePath).submit { out ->
val builder = StringBuilder() val builder = StringBuilder()
for (data in out.getOut()) { builder.append(data) } for (data in out.getOut()) { builder.append(data) }
result.success(builder.toString().endsWith("Success")) result.success(builder.toString().endsWith("Success"))
@@ -145,12 +147,18 @@ class MainActivity: FlutterActivity() {
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine) super.configureFlutterEngine(flutterEngine)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.addHiddenApiExemptions("")
}
Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener) Shizuku.addRequestPermissionResultListener(shizukuRequestPermissionResultListener)
installersChannel = MethodChannel( nativeChannel = MethodChannel(
flutterEngine.dartExecutor.binaryMessenger, "installers") flutterEngine.dartExecutor.binaryMessenger, "native")
installersChannel!!.setMethodCallHandler { nativeChannel!!.setMethodCallHandler {
call, result -> call, result ->
if (call.method == "checkPermissionShizuku") { if (call.method == "getSystemFont") {
val res = DefaultSystemFont().get()
result.success(res)
} else if (call.method == "checkPermissionShizuku") {
shizukuCheckPermission(result) shizukuCheckPermission(result)
} else if (call.method == "checkPermissionRoot") { } else if (call.method == "checkPermissionRoot") {
rootCheckPermission(result) rootCheckPermission(result)

View File

@@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '1.8.10'
ext { ext {
compileSdkVersion = 34 // or latest compileSdkVersion = 34 // or latest
targetSdkVersion = 34 // or latest targetSdkVersion = 34 // or latest
@@ -11,9 +11,9 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.0' classpath "com.android.tools.build:gradle:7.4.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'dev.rikka.tools.refine:gradle-plugin:4.1.0' // Do not update! classpath "dev.rikka.tools.refine:gradle-plugin:4.3.1"
} }
} }

View File

@@ -103,7 +103,6 @@
"importErrors": "Uvezi greške", "importErrors": "Uvezi greške",
"importedXOfYApps": "{} od {} aplikacija uvezeno.", "importedXOfYApps": "{} od {} aplikacija uvezeno.",
"followingURLsHadErrors": "Sljedeći URL-ovi su imali greške:", "followingURLsHadErrors": "Sljedeći URL-ovi su imali greške:",
"okay": "Dobro",
"selectURL": "Odaberite URL", "selectURL": "Odaberite URL",
"selectURLs": "Odaberite URL-ove", "selectURLs": "Odaberite URL-ove",
"pick": "Odaberi", "pick": "Odaberi",

View File

@@ -103,7 +103,6 @@
"importErrors": "Chyba importu", "importErrors": "Chyba importu",
"importedXOfYApps": "{}importováno z {} aplikací.", "importedXOfYApps": "{}importováno z {} aplikací.",
"followingURLsHadErrors": "U následujících adres došlo k chybám:", "followingURLsHadErrors": "U následujících adres došlo k chybám:",
"okay": "Okay",
"selectURL": "Vybrat adresu", "selectURL": "Vybrat adresu",
"selectURLs": "Select adresy", "selectURLs": "Select adresy",
"pick": "Vybrat", "pick": "Vybrat",

View File

@@ -103,7 +103,6 @@
"importErrors": "Importfehler", "importErrors": "Importfehler",
"importedXOfYApps": "{} von {} Apps importiert.", "importedXOfYApps": "{} von {} Apps importiert.",
"followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:", "followingURLsHadErrors": "Bei folgenden URLs traten Fehler auf:",
"okay": "Okay",
"selectURL": "URL auswählen", "selectURL": "URL auswählen",
"selectURLs": "URLs auswählen", "selectURLs": "URLs auswählen",
"pick": "Auswählen", "pick": "Auswählen",

View File

@@ -103,7 +103,6 @@
"importErrors": "Import Errors", "importErrors": "Import Errors",
"importedXOfYApps": "{} of {} Apps imported.", "importedXOfYApps": "{} of {} Apps imported.",
"followingURLsHadErrors": "The following URLs had errors:", "followingURLsHadErrors": "The following URLs had errors:",
"okay": "Okay",
"selectURL": "Select URL", "selectURL": "Select URL",
"selectURLs": "Select URLs", "selectURLs": "Select URLs",
"pick": "Pick", "pick": "Pick",
@@ -287,7 +286,9 @@
"normal": "Normal", "normal": "Normal",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Сompatible Shizuku service wasn't found",
"useSystemFont": "Use the system font",
"systemFontError": "Error loading the system font: {}",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"

View File

@@ -103,7 +103,6 @@
"importErrors": "Errores de Importación", "importErrors": "Errores de Importación",
"importedXOfYApps": "{} de {} Aplicaciones importadas.", "importedXOfYApps": "{} de {} Aplicaciones importadas.",
"followingURLsHadErrors": "Las siguientes URLs han tenido problemas:", "followingURLsHadErrors": "Las siguientes URLs han tenido problemas:",
"okay": "Aceptar",
"selectURL": "Seleccionar URL", "selectURL": "Seleccionar URL",
"selectURLs": "Seleccionar URLs", "selectURLs": "Seleccionar URLs",
"pick": "Escoger", "pick": "Escoger",

View File

@@ -103,7 +103,6 @@
"importErrors": "خطاهای وارد کردن", "importErrors": "خطاهای وارد کردن",
"importedXOfYApps": "{} از {} برنامه وارد شد.", "importedXOfYApps": "{} از {} برنامه وارد شد.",
"followingURLsHadErrors": "آدرس های اینترنتی زیر دارای خطا بودند:", "followingURLsHadErrors": "آدرس های اینترنتی زیر دارای خطا بودند:",
"okay": "باشه",
"selectURL": "آدرس اینترنتی انتخاب شده", "selectURL": "آدرس اینترنتی انتخاب شده",
"selectURLs": "آدرس های اینترنتی انتخاب شده", "selectURLs": "آدرس های اینترنتی انتخاب شده",
"pick": "انتخاب", "pick": "انتخاب",

View File

@@ -103,7 +103,6 @@
"importErrors": "Erreurs d'importation", "importErrors": "Erreurs d'importation",
"importedXOfYApps": "{} sur {} applications importées.", "importedXOfYApps": "{} sur {} applications importées.",
"followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :", "followingURLsHadErrors": "Les URL suivantes comportaient des erreurs :",
"okay": "Okay",
"selectURL": "Sélectionnez l'URL", "selectURL": "Sélectionnez l'URL",
"selectURLs": "Sélectionnez les URLs", "selectURLs": "Sélectionnez les URLs",
"pick": "Prendre", "pick": "Prendre",

View File

@@ -103,7 +103,6 @@
"importErrors": "Importálási hibák", "importErrors": "Importálási hibák",
"importedXOfYApps": "{}/{} app importálva.", "importedXOfYApps": "{}/{} app importálva.",
"followingURLsHadErrors": "A következő URL-ek hibákat tartalmaztak:", "followingURLsHadErrors": "A következő URL-ek hibákat tartalmaztak:",
"okay": "Oké",
"selectURL": "Válassza ki az URL-t", "selectURL": "Válassza ki az URL-t",
"selectURLs": "Kiválasztott URL-ek", "selectURLs": "Kiválasztott URL-ek",
"pick": "Válasszon", "pick": "Válasszon",

View File

@@ -103,7 +103,6 @@
"importErrors": "Errori di importazione", "importErrors": "Errori di importazione",
"importedXOfYApps": "{} app di {} importate.", "importedXOfYApps": "{} app di {} importate.",
"followingURLsHadErrors": "I seguenti URL contengono errori:", "followingURLsHadErrors": "I seguenti URL contengono errori:",
"okay": "Va bene",
"selectURL": "Seleziona l'URL", "selectURL": "Seleziona l'URL",
"selectURLs": "Seleziona gli URL", "selectURLs": "Seleziona gli URL",
"pick": "Seleziona", "pick": "Seleziona",

View File

@@ -103,7 +103,6 @@
"importErrors": "インポートエラー", "importErrors": "インポートエラー",
"importedXOfYApps": "{} / {} アプリをインポートしました", "importedXOfYApps": "{} / {} アプリをインポートしました",
"followingURLsHadErrors": "以下のURLでエラーが発生しました:", "followingURLsHadErrors": "以下のURLでエラーが発生しました:",
"okay": "OK",
"selectURL": "URLを選択", "selectURL": "URLを選択",
"selectURLs": "URLを選択", "selectURLs": "URLを選択",
"pick": "選択", "pick": "選択",

View File

@@ -103,7 +103,6 @@
"importErrors": "Import foutmeldingen", "importErrors": "Import foutmeldingen",
"importedXOfYApps": "{} van {} apps geïmporteerd.", "importedXOfYApps": "{} van {} apps geïmporteerd.",
"followingURLsHadErrors": "De volgende URL's bevatten fouten:", "followingURLsHadErrors": "De volgende URL's bevatten fouten:",
"okay": "Ok",
"selectURL": "Selecteer URL", "selectURL": "Selecteer URL",
"selectURLs": "Selecteer URL's", "selectURLs": "Selecteer URL's",
"pick": "Kies", "pick": "Kies",

View File

@@ -103,7 +103,6 @@
"importErrors": "Błędy importowania", "importErrors": "Błędy importowania",
"importedXOfYApps": "Zaimportowano {} z {} aplikacji.", "importedXOfYApps": "Zaimportowano {} z {} aplikacji.",
"followingURLsHadErrors": "Następujące adresy URL zawierały błędy:", "followingURLsHadErrors": "Następujące adresy URL zawierały błędy:",
"okay": "Okej",
"selectURL": "Wybierz adres URL", "selectURL": "Wybierz adres URL",
"selectURLs": "Wybierz adresy URL", "selectURLs": "Wybierz adresy URL",
"pick": "Wybierz", "pick": "Wybierz",

View File

@@ -103,7 +103,6 @@
"importErrors": "Erros de Importação", "importErrors": "Erros de Importação",
"importedXOfYApps": "{} de {} Apps importados.", "importedXOfYApps": "{} de {} Apps importados.",
"followingURLsHadErrors": "As seguintes URLs apresentaram erros:", "followingURLsHadErrors": "As seguintes URLs apresentaram erros:",
"okay": "Ok",
"selectURL": "Selecionar URL", "selectURL": "Selecionar URL",
"selectURLs": "Selecionar URLs", "selectURLs": "Selecionar URLs",
"pick": "Escolher", "pick": "Escolher",

View File

@@ -103,7 +103,6 @@
"importErrors": "Ошибка импорта", "importErrors": "Ошибка импорта",
"importedXOfYApps": "Импортировано приложений: {} из {}", "importedXOfYApps": "Импортировано приложений: {} из {}",
"followingURLsHadErrors": "При импорте следующие URL-адреса содержали ошибки:", "followingURLsHadErrors": "При импорте следующие URL-адреса содержали ошибки:",
"okay": "Ok",
"selectURL": "Выбрать URL-адрес", "selectURL": "Выбрать URL-адрес",
"selectURLs": "Выбрать URL-адреса", "selectURLs": "Выбрать URL-адреса",
"pick": "Выбрать", "pick": "Выбрать",
@@ -287,7 +286,9 @@
"normal": "Нормальный", "normal": "Нормальный",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Суперпользователь", "root": "Суперпользователь",
"shizukuBinderNotFound": "Shizuku не запущен", "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден",
"useSystemFont": "Использовать системный шрифт",
"systemFontError": "Ошибка загрузки системного шрифта: {}",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@@ -103,7 +103,6 @@
"importErrors": "Importfel", "importErrors": "Importfel",
"importedXOfYApps": "{} av {} Appar importerade.", "importedXOfYApps": "{} av {} Appar importerade.",
"followingURLsHadErrors": "Följande URL:er hade fel:", "followingURLsHadErrors": "Följande URL:er hade fel:",
"okay": "Okej",
"selectURL": "Välj URL", "selectURL": "Välj URL",
"selectURLs": "Välj URL:er", "selectURLs": "Välj URL:er",
"pick": "Välj", "pick": "Välj",

View File

@@ -103,7 +103,6 @@
"importErrors": "İçe Aktarma Hataları", "importErrors": "İçe Aktarma Hataları",
"importedXOfYApps": "{}'den {} Uygulama İçe Aktarıldı.", "importedXOfYApps": "{}'den {} Uygulama İçe Aktarıldı.",
"followingURLsHadErrors": "Aşağıdaki URL'lerde hatalar oluştu:", "followingURLsHadErrors": "Aşağıdaki URL'lerde hatalar oluştu:",
"okay": "Tamam",
"selectURL": "URL Seç", "selectURL": "URL Seç",
"selectURLs": "URL'leri Seç", "selectURLs": "URL'leri Seç",
"pick": "Seç", "pick": "Seç",

View File

@@ -103,7 +103,6 @@
"importErrors": "Lỗi nhập", "importErrors": "Lỗi nhập",
"importedXOfYApps": "{} trong số {} Ứng dụng đã được nhập.", "importedXOfYApps": "{} trong số {} Ứng dụng đã được nhập.",
"followingURLsHadErrors": "Các URL sau có lỗi:", "followingURLsHadErrors": "Các URL sau có lỗi:",
"okay": "Ôkê",
"selectURL": "Chọn URL", "selectURL": "Chọn URL",
"selectURLs": "Chọn URL", "selectURLs": "Chọn URL",
"pick": "Chọn", "pick": "Chọn",

View File

@@ -103,7 +103,6 @@
"importErrors": "导入错误", "importErrors": "导入错误",
"importedXOfYApps": "已导入 {} 中的 {} 个应用。", "importedXOfYApps": "已导入 {} 中的 {} 个应用。",
"followingURLsHadErrors": "下列 URL 存在错误:", "followingURLsHadErrors": "下列 URL 存在错误:",
"okay": "好的",
"selectURL": "选择 URL", "selectURL": "选择 URL",
"selectURLs": "选择 URL", "selectURLs": "选择 URL",
"pick": "选择", "pick": "选择",

View File

@@ -36,7 +36,7 @@ List<MapEntry<Locale, String>> supportedLocales = const [
MapEntry(Locale('fr'), 'Français'), MapEntry(Locale('fr'), 'Français'),
MapEntry(Locale('es'), 'Español'), MapEntry(Locale('es'), 'Español'),
MapEntry(Locale('pl'), 'Polski'), MapEntry(Locale('pl'), 'Polski'),
MapEntry(Locale('ru'), 'Русский язык'), MapEntry(Locale('ru'), 'Русский'),
MapEntry(Locale('bs'), 'Bosanski'), MapEntry(Locale('bs'), 'Bosanski'),
MapEntry(Locale('pt'), 'Brasileiro'), MapEntry(Locale('pt'), 'Brasileiro'),
MapEntry(Locale('cs'), 'Česky'), MapEntry(Locale('cs'), 'Česky'),
@@ -236,13 +236,17 @@ class _ObtainiumState extends State<Obtainium> {
colorScheme: settingsProvider.theme == ThemeSettings.dark colorScheme: settingsProvider.theme == ThemeSettings.dark
? darkColorScheme ? darkColorScheme
: lightColorScheme, : lightColorScheme,
fontFamily: 'Metropolis'), fontFamily: settingsProvider.useSystemFont
? 'SystemFont'
: 'Metropolis'),
darkTheme: ThemeData( darkTheme: ThemeData(
useMaterial3: true, useMaterial3: true,
colorScheme: settingsProvider.theme == ThemeSettings.light colorScheme: settingsProvider.theme == ThemeSettings.light
? lightColorScheme ? lightColorScheme
: darkColorScheme, : darkColorScheme,
fontFamily: 'Metropolis'), fontFamily: settingsProvider.useSystemFont
? 'SystemFont'
: 'Metropolis'),
home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{ home: Shortcuts(shortcuts: <LogicalKeySet, Intent>{
LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(), LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
}, child: const HomePage())); }, child: const HomePage()));

View File

@@ -590,7 +590,7 @@ class _ImportErrorDialogState extends State<ImportErrorDialog> {
onPressed: () { onPressed: () {
Navigator.of(context).pop(null); Navigator.of(context).pop(null);
}, },
child: Text(tr('okay'))) child: Text(tr('ok')))
], ],
); );
} }

View File

@@ -7,6 +7,7 @@ import 'package:obtainium/custom_errors.dart';
import 'package:obtainium/main.dart'; import 'package:obtainium/main.dart';
import 'package:obtainium/providers/apps_provider.dart'; import 'package:obtainium/providers/apps_provider.dart';
import 'package:obtainium/providers/logs_provider.dart'; import 'package:obtainium/providers/logs_provider.dart';
import 'package:obtainium/providers/native_provider.dart';
import 'package:obtainium/providers/settings_provider.dart'; import 'package:obtainium/providers/settings_provider.dart';
import 'package:obtainium/providers/source_provider.dart'; import 'package:obtainium/providers/source_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -350,8 +351,6 @@ class _SettingsPageState extends State<SettingsPage> {
], ],
), ),
height16, height16,
installMethodDropdown,
height16,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@@ -364,6 +363,7 @@ class _SettingsPageState extends State<SettingsPage> {
}) })
], ],
), ),
installMethodDropdown,
height32, height32,
Text( Text(
tr('sourceSpecific'), tr('sourceSpecific'),
@@ -408,6 +408,30 @@ class _SettingsPageState extends State<SettingsPage> {
height16, height16,
localeDropdown, localeDropdown,
height16, height16,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(tr('useSystemFont'))),
Switch(
value: settingsProvider.useSystemFont,
onChanged: (useSystemFont) {
if (useSystemFont) {
NativeFeatures.loadSystemFont().then((fontLoadRes) {
if (fontLoadRes == 'ok') {
settingsProvider.useSystemFont = true;
} else {
showError(ObtainiumError(
tr('systemFontError', args: [fontLoadRes])
), context);
}
});
} else {
settingsProvider.useSystemFont = false;
}
})
],
),
height16,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [

View File

@@ -32,7 +32,7 @@ import 'package:http/http.dart';
import 'package:android_intent_plus/android_intent.dart'; import 'package:android_intent_plus/android_intent.dart';
import 'package:flutter_archive/flutter_archive.dart'; import 'package:flutter_archive/flutter_archive.dart';
import 'package:shared_storage/shared_storage.dart' as saf; import 'package:shared_storage/shared_storage.dart' as saf;
import 'installers_provider.dart'; import 'native_provider.dart';
final pm = AndroidPackageManager(); final pm = AndroidPackageManager();
@@ -522,12 +522,12 @@ class AppsProvider with ChangeNotifier {
code = await AndroidPackageInstaller.installApk( code = await AndroidPackageInstaller.installApk(
apkFilePath: file.file.path); apkFilePath: file.file.path);
case InstallMethodSettings.shizuku: case InstallMethodSettings.shizuku:
code = (await Installers.installWithShizuku( code = (await NativeFeatures.installWithShizuku(
apkFileUri: file.file.uri.toString())) apkFileUri: file.file.uri.toString()))
? 0 ? 0
: 1; : 1;
case InstallMethodSettings.root: case InstallMethodSettings.root:
code = (await Installers.installWithRoot(apkFilePath: file.file.path)) code = (await NativeFeatures.installWithRoot(apkFilePath: file.file.path))
? 0 ? 0
: 1; : 1;
} }
@@ -694,14 +694,14 @@ class AppsProvider with ChangeNotifier {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
} }
case InstallMethodSettings.shizuku: case InstallMethodSettings.shizuku:
int code = await Installers.checkPermissionShizuku(); int code = await NativeFeatures.checkPermissionShizuku();
if (code == -1) { if (code == -1) {
throw ObtainiumError(tr('shizukuBinderNotFound')); throw ObtainiumError(tr('shizukuBinderNotFound'));
} else if (code == 0) { } else if (code == 0) {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
} }
case InstallMethodSettings.root: case InstallMethodSettings.root:
if (!(await Installers.checkPermissionRoot())) { if (!(await NativeFeatures.checkPermissionRoot())) {
throw ObtainiumError(tr('cancelled')); throw ObtainiumError(tr('cancelled'));
} }
} }

View File

@@ -1,12 +1,26 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class Installers { class NativeFeatures {
static const MethodChannel _channel = MethodChannel('installers'); static const MethodChannel _channel = MethodChannel('native');
static bool _systemFontLoaded = false;
static bool _callbacksApplied = false; static bool _callbacksApplied = false;
static int _resPermShizuku = -2; // not set static int _resPermShizuku = -2; // not set
static Future waitWhile(bool Function() test, static Future<ByteData> _readFileBytes(String path) async {
var file = File(path);
var bytes = await file.readAsBytes();
return ByteData.view(bytes.buffer);
}
static Future _handleCalls(MethodCall call) async {
if (call.method == 'resPermShizuku') {
_resPermShizuku = call.arguments['res'];
}
}
static Future _waitWhile(bool Function() test,
[Duration pollInterval = const Duration(milliseconds: 250)]) { [Duration pollInterval = const Duration(milliseconds: 250)]) {
var completer = Completer(); var completer = Completer();
check() { check() {
@@ -20,20 +34,25 @@ class Installers {
return completer.future; return completer.future;
} }
static Future handleCalls(MethodCall call) async { static Future<String> loadSystemFont() async {
if (call.method == 'resPermShizuku') { if (_systemFontLoaded) { return "ok"; }
_resPermShizuku = call.arguments['res']; var getFontRes = await _channel.invokeMethod('getSystemFont');
} if (getFontRes[0] != '/') { return getFontRes; } // Error
var fontLoader = FontLoader('SystemFont');
fontLoader.addFont(_readFileBytes(getFontRes));
await fontLoader.load();
_systemFontLoaded = true;
return "ok";
} }
static Future<int> checkPermissionShizuku() async { static Future<int> checkPermissionShizuku() async {
if (!_callbacksApplied) { if (!_callbacksApplied) {
_channel.setMethodCallHandler(handleCalls); _channel.setMethodCallHandler(_handleCalls);
_callbacksApplied = true; _callbacksApplied = true;
} }
int res = await _channel.invokeMethod('checkPermissionShizuku'); int res = await _channel.invokeMethod('checkPermissionShizuku');
if (res == -2) { if (res == -2) {
await waitWhile(() => _resPermShizuku == -2); await _waitWhile(() => _resPermShizuku == -2);
res = _resPermShizuku; res = _resPermShizuku;
_resPermShizuku = -2; _resPermShizuku = -2;
} }

View File

@@ -51,6 +51,15 @@ class SettingsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
bool get useSystemFont {
return prefs?.getBool('useSystemFont') ?? false;
}
set useSystemFont(bool useSystemFont) {
prefs?.setBool('useSystemFont', useSystemFont);
notifyListeners();
}
InstallMethodSettings get installMethod { InstallMethodSettings get installMethod {
return InstallMethodSettings.values[ return InstallMethodSettings.values[
prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index]; prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index];