System font and newer dependencies

This commit is contained in:
Gregory
2023-12-31 19:33:33 +03:00
parent 1fc8ee6fee
commit 5ba33786ab
11 changed files with 127 additions and 38 deletions

View File

@ -37,12 +37,12 @@ android {
ndkVersion flutter.ndkVersion ndkVersion flutter.ndkVersion
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_17
} }
kotlinOptions { kotlinOptions {
jvmTarget = '1.8' jvmTarget = '17'
} }
sourceSets { sourceSets {
@ -96,16 +96,11 @@ 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"

View File

@ -0,0 +1,33 @@
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 (_: Exception) {
null
}
}
private fun parseFontsFileStream(fileStream: FileInputStream): String {
fileStream.use { stream ->
val parser = Xml.newPullParser()
parser.setInput(stream, null)
parser.nextTag()
return parseFonts(parser)
}
}
private fun parseFonts(parser: XmlPullParser): String {
while (parser.name != "font") { parser.next() }
parser.next()
return "/system/fonts/" + parser.text.trim()
}
}

View File

@ -28,7 +28,7 @@ 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) {
@ -52,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))
} }
} }
@ -151,11 +151,14 @@ class MainActivity: FlutterActivity() {
HiddenApiBypass.addHiddenApiExemptions("") 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

@ -6,9 +6,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

@ -285,7 +285,8 @@
"normal": "Normal", "normal": "Normal",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Root", "root": "Root",
"shizukuBinderNotFound": "Shizuku is not running", "shizukuBinderNotFound": "Сompatible Shizuku service wasn't found",
"tryUseSystemFont": "Try to use a system font",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Remove App?", "one": "Remove App?",
"other": "Remove Apps?" "other": "Remove Apps?"

View File

@ -285,7 +285,8 @@
"normal": "Нормальный", "normal": "Нормальный",
"shizuku": "Shizuku", "shizuku": "Shizuku",
"root": "Суперпользователь", "root": "Суперпользователь",
"shizukuBinderNotFound": "Shizuku не запущен", "shizukuBinderNotFound": "Совместимый сервис Shizuku не найден",
"tryUseSystemFont": "Попытаться использовать системный шрифт",
"removeAppQuestion": { "removeAppQuestion": {
"one": "Удалить приложение?", "one": "Удалить приложение?",
"other": "Удалить приложения?" "other": "Удалить приложения?"

View File

@ -5,6 +5,7 @@ import 'package:flutter/services.dart';
import 'package:obtainium/pages/home.dart'; import 'package:obtainium/pages/home.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/notifications_provider.dart'; import 'package:obtainium/providers/notifications_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';
@ -185,6 +186,16 @@ class _ObtainiumState extends State<Obtainium> {
} }
existingUpdateInterval = actualUpdateInterval; existingUpdateInterval = actualUpdateInterval;
} }
settingsProvider.addListener(() async {
if (settingsProvider.tryUseSystemFont &&
settingsProvider.appFont == "Metropolis") {
bool fontLoaded = await NativeFeatures.tryLoadSystemFont();
if (fontLoaded) { settingsProvider.appFont = "SystemFont"; }
} else if (!settingsProvider.tryUseSystemFont &&
settingsProvider.appFont != "Metropolis") {
settingsProvider.appFont = "Metropolis";
}
});
} }
return DynamicColorBuilder( return DynamicColorBuilder(
@ -221,13 +232,13 @@ class _ObtainiumState extends State<Obtainium> {
colorScheme: settingsProvider.theme == ThemeSettings.dark colorScheme: settingsProvider.theme == ThemeSettings.dark
? darkColorScheme ? darkColorScheme
: lightColorScheme, : lightColorScheme,
fontFamily: 'Metropolis'), fontFamily: settingsProvider.appFont),
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.appFont),
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

@ -351,8 +351,6 @@ class _SettingsPageState extends State<SettingsPage> {
], ],
), ),
height16, height16,
installMethodDropdown,
height16,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -365,6 +363,7 @@ class _SettingsPageState extends State<SettingsPage> {
}) })
], ],
), ),
installMethodDropdown,
height32, height32,
Text( Text(
tr('sourceSpecific'), tr('sourceSpecific'),
@ -409,6 +408,18 @@ class _SettingsPageState extends State<SettingsPage> {
height16, height16,
localeDropdown, localeDropdown,
height16, height16,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(child: Text(tr('tryUseSystemFont'))),
Switch(
value: settingsProvider.tryUseSystemFont,
onChanged: (value) {
settingsProvider.tryUseSystemFont = value;
})
],
),
height16,
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [

View File

@ -33,7 +33,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();
@ -523,12 +523,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,25 @@
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 _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 +33,23 @@ class Installers {
return completer.future; return completer.future;
} }
static Future handleCalls(MethodCall call) async { static Future<bool> tryLoadSystemFont() async {
if (call.method == 'resPermShizuku') { var font = await _channel.invokeMethod('getSystemFont');
_resPermShizuku = call.arguments['res']; if (font == null) { return false; }
} var fontLoader = FontLoader('SystemFont');
fontLoader.addFont(_readFileBytes(font));
await fontLoader.load();
return true;
} }
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,24 @@ class SettingsProvider with ChangeNotifier {
notifyListeners(); notifyListeners();
} }
String get appFont {
return prefs?.getString('appFont') ?? 'Metropolis';
}
set appFont(String appFont) {
prefs?.setString('appFont', appFont);
notifyListeners();
}
bool get tryUseSystemFont {
return prefs?.getBool('tryUseSystemFont') ?? false;
}
set tryUseSystemFont(bool tryUseSystemFont) {
prefs?.setBool('tryUseSystemFont', tryUseSystemFont);
notifyListeners();
}
InstallMethodSettings get installMethod { InstallMethodSettings get installMethod {
return InstallMethodSettings return InstallMethodSettings
.values[prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index]; .values[prefs?.getInt('installMethod') ?? InstallMethodSettings.normal.index];