* refa: jni

* refa: jni
This commit is contained in:
My-Responsitories
2026-05-30 12:10:35 +00:00
committed by GitHub
parent 6a75061dbb
commit d4d9fc3405
17 changed files with 1002 additions and 305 deletions

View File

@@ -0,0 +1,191 @@
package com.example.piliplus;
import android.app.PendingIntent;
import android.app.PictureInPictureParams;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.provider.Settings;
import android.view.WindowManager;
import androidx.annotation.Keep;
import com.github.dart_lang.jni_flutter.JniFlutterPlugin;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@Keep
public final class AndroidHelper {
public static volatile boolean isFoldable = false;
private AndroidHelper() {
}
private static Context getContext() {
return JniFlutterPlugin.getApplicationContext();
}
public static void back() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
public static void biliSendCommAntifraud(
int action, long oid, int type, long rpId, long root, long parent, long ctime, @NotNull String commentText,
String pictures, @NotNull String sourceId, long uid, @NotNull String cookie
) {
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
"icu.freedomIntrovert.biliSendCommAntifraud",
"icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity"
));
intent.putExtra("action", action);
intent.putExtra("oid", oid);
intent.putExtra("type", type);
intent.putExtra("rpid", rpId);
intent.putExtra("root", root);
intent.putExtra("parent", parent);
intent.putExtra("ctime", ctime);
intent.putExtra("comment_text", commentText);
if (pictures != null) {
intent.putExtra("pictures", pictures);
}
intent.putExtra("source_id", sourceId);
intent.putExtra("uid", uid);
ArrayList<String> cookiesList = new ArrayList<>(1);
cookiesList.add(cookie);
intent.putStringArrayListExtra("cookies", cookiesList);
getContext().startActivity(intent);
}
public static void openLinkVerifySettings() {
Context context = getContext();
Uri uri = Uri.parse("package:" + context.getPackageName());
try {
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
intent = new Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri);
} else {
intent = new Intent(Intent.ACTION_MAIN, uri);
intent.setClassName(
"com.android.settings",
"com.android.settings.applications.InstalledAppOpenByDefaultActivity"
);
}
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Throwable ignored) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
public static boolean openMusic(@NotNull String title, String artist, String album) {
Intent intent = new Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(SearchManager.QUERY, title);
intent.putExtra(MediaStore.EXTRA_MEDIA_TITLE, title);
if (artist != null) {
intent.putExtra(MediaStore.EXTRA_MEDIA_ARTIST, artist);
}
if (album != null) {
intent.putExtra(MediaStore.EXTRA_MEDIA_ALBUM, album);
}
intent.addCategory(Intent.CATEGORY_DEFAULT);
Context context = getContext();
PackageManager pm = context.getPackageManager();
try {
if (pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
context.startActivity(intent);
return true;
}
} catch (Throwable ignored) {
}
try {
intent.setAction(MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH);
if (pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
context.startActivity(intent);
return true;
}
} catch (Throwable ignored) {
}
return false;
}
public static void setPipAutoEnterEnabled(boolean autoEnable, long engineId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PictureInPictureParams params = new PictureInPictureParams.Builder().setAutoEnterEnabled(autoEnable).build();
android.app.Activity activity = JniFlutterPlugin.getActivity(engineId);
if (activity != null) {
activity.setPictureInPictureParams(params);
}
}
}
public static int[] maxScreenSize() {
Context context = getContext();
WindowManager wm = context.getSystemService(WindowManager.class);
try {
float density = context.getResources().getDisplayMetrics().density;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Rect maxBounds = wm.getMaximumWindowMetrics().getBounds();
return new int[]{Math.round(maxBounds.width() / density), Math.round(maxBounds.height() / density)};
} else {
Point realSize = new Point();
wm.getDefaultDisplay().getRealSize(realSize);
return new int[]{Math.round(realSize.x / density), Math.round(realSize.y / density)};
}
} catch (Exception e) {
return null;
}
}
public static void createShortcut(@NotNull String id, @NotNull String uri, @NotNull String label, @NotNull String icon) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Context context = getContext();
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
if (shortcutManager != null && shortcutManager.isRequestPinShortcutSupported()) {
Bitmap bitmap = BitmapFactory.decodeFile(icon);
ShortcutInfo shortcut = new ShortcutInfo.Builder(context, id)
.setShortLabel(label)
.setIcon(Icon.createWithAdaptiveBitmap(bitmap))
.setIntent(new Intent(Intent.ACTION_VIEW, Uri.parse(uri)))
.build();
// TODO: WorkerThread
Intent pinIntent = shortcutManager.createShortcutResultIntent(shortcut);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context, 0, pinIntent, PendingIntent.FLAG_IMMUTABLE
);
shortcutManager.requestPinShortcut(shortcut, pendingIntent.getIntentSender());
}
}
}
@Keep
public static final class ToDart {
public static volatile Runnable onUserLeaveHint;
public static volatile Runnable onConfigurationChanged;
private ToDart() {
}
}
}

View File

@@ -1,32 +1,19 @@
package com.example.piliplus
import android.app.PendingIntent
import android.app.PictureInPictureParams
import android.app.SearchManager
import android.content.ComponentName
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.res.Configuration
import android.graphics.BitmapFactory
import android.graphics.Point
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.provider.Settings
import android.view.WindowManager.LayoutParams
import androidx.core.net.toUri
import com.ryanheise.audioservice.AudioServiceActivity
import io.flutter.SystemChrome
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.SystemChrome
import kotlin.math.roundToInt
class MainActivity : AudioServiceActivity() {
// TODO: remove
private lateinit var methodChannel: MethodChannel
private var isFoldable = false
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
@@ -34,169 +21,15 @@ class MainActivity : AudioServiceActivity() {
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "PiliPlus")
methodChannel.setMethodCallHandler { call, result ->
when (call.method) {
"back" -> back()
"biliSendCommAntifraud" -> {
try {
val action = call.argument<Int>("action") ?: 0
val oid = call.argument<Number>("oid") ?: 0L
val type = call.argument<Int>("type") ?: 0
val rpid = call.argument<Number>("rpid") ?: 0L
val root = call.argument<Number>("root") ?: 0L
val parent = call.argument<Number>("parent") ?: 0L
val ctime = call.argument<Number>("ctime") ?: 0L
val commentText = call.argument<String>("comment_text") ?: ""
val pictures = call.argument<String?>("pictures")
val sourceId = call.argument<String>("source_id") ?: ""
val uid = call.argument<Number>("uid") ?: 0L
val cookies = call.argument<List<String>>("cookies") ?: emptyList()
val intent = Intent().apply {
component = ComponentName(
"icu.freedomIntrovert.biliSendCommAntifraud",
"icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity"
)
putExtra("action", action)
putExtra("oid", oid.toLong())
putExtra("type", type)
putExtra("rpid", rpid.toLong())
putExtra("root", root.toLong())
putExtra("parent", parent.toLong())
putExtra("ctime", ctime.toLong())
putExtra("comment_text", commentText)
if (pictures != null)
putExtra("pictures", pictures)
putExtra("source_id", sourceId)
putExtra("uid", uid.toLong())
putStringArrayListExtra("cookies", ArrayList(cookies))
}
startActivity(intent)
} catch (_: Exception) {
}
}
"linkVerifySettings" -> {
val uri = ("package:" + context.packageName).toUri()
try {
val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Intent(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, uri)
} else {
Intent("android.intent.action.MAIN", uri).setClassName(
"com.android.settings",
"com.android.settings.applications.InstalledAppOpenByDefaultActivity"
)
}
context.startActivity(intent)
} catch (_: Throwable) {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, uri)
context.startActivity(intent)
}
}
"music" -> {
val title = call.argument<String>("title")
val intent = Intent(MediaStore.INTENT_ACTION_MEDIA_SEARCH).apply {
putExtra(SearchManager.QUERY, title)
putExtra(MediaStore.EXTRA_MEDIA_TITLE, title)
call.argument<String?>("artist")
?.let { putExtra(MediaStore.EXTRA_MEDIA_ARTIST, it) }
call.argument<String?>("album")
?.let { putExtra(MediaStore.EXTRA_MEDIA_ALBUM, it) }
addCategory(Intent.CATEGORY_DEFAULT)
}
try {
if (packageManager.resolveActivity(
intent,
PackageManager.MATCH_DEFAULT_ONLY
) != null
) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {
}
try {
intent.action = MediaStore.INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
if (packageManager.resolveActivity(
intent,
PackageManager.MATCH_DEFAULT_ONLY
) != null
) {
startActivity(intent)
result.success(true)
return@setMethodCallHandler
}
} catch (_: Throwable) {
}
result.success(false)
}
"setPipAutoEnterEnabled" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val params = PictureInPictureParams.Builder()
.setAutoEnterEnabled(call.argument<Boolean>("autoEnable") ?: false)
.build()
setPictureInPictureParams(params)
}
}
"createShortcut" -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
val shortcutManager =
context.getSystemService(ShortcutManager::class.java)
if (shortcutManager.isRequestPinShortcutSupported) {
val id = call.argument<String>("id")!!
val uri = call.argument<String>("uri")!!
val label = call.argument<String>("label")!!
val icon = call.argument<String>("icon")!!
val bitmap = BitmapFactory.decodeFile(icon)
val shortcut =
ShortcutInfo.Builder(context, id)
.setShortLabel(label)
.setIcon(Icon.createWithAdaptiveBitmap(bitmap))
.setIntent(Intent(Intent.ACTION_VIEW, uri.toUri()))
.build()
val pinIntent =
shortcutManager.createShortcutResultIntent(shortcut)
val pendingIntent = PendingIntent.getBroadcast(
context, 0, pinIntent, PendingIntent.FLAG_IMMUTABLE
)
shortcutManager.requestPinShortcut(
shortcut,
pendingIntent.intentSender
)
}
} catch (_: Exception) {
}
}
}
"maxScreenSize" -> {
maxScreenSize()?.let {
result.success(it)
}
}
"isFoldable" -> {
result.success(isFoldable)
}
"SystemChrome.setEnabledSystemUIMode" -> {
SystemChrome.onMethodCall(
this,
"SystemChrome.setEnabledSystemUIMode",
call.argument("arguments")
this, "SystemChrome.setEnabledSystemUIMode", call.argument("arguments")
)
}
"SystemChrome.setEnabledSystemUIOverlays" -> {
SystemChrome.onMethodCall(
this,
"SystemChrome.setEnabledSystemUIOverlays",
call.argument("arguments")
this, "SystemChrome.setEnabledSystemUIOverlays", call.argument("arguments")
)
}
@@ -207,57 +40,20 @@ class MainActivity : AudioServiceActivity() {
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (isFoldable) {
maxScreenSize()?.let {
MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
"ScreenChannel"
).invokeMethod("onConfigChanged", it)
}
if (AndroidHelper.isFoldable) {
AndroidHelper.ToDart.onConfigurationChanged?.run()
}
}
private fun maxScreenSize(): Map<String, Int>? {
try {
val density = resources.displayMetrics.density
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val maxBounds = windowManager.maximumWindowMetrics.bounds
return mapOf(
"maxWidth" to (maxBounds.width() / density).roundToInt(),
"maxHeight" to (maxBounds.height() / density).roundToInt(),
)
} else {
val realSizePoint = Point()
windowManager.defaultDisplay.getRealSize(realSizePoint)
return mapOf(
"maxWidth" to (realSizePoint.x / density).roundToInt(),
"maxHeight" to (realSizePoint.y / density).roundToInt(),
)
}
} catch (_: Exception) {
return null
}
}
private fun back() {
val intent = Intent(Intent.ACTION_MAIN).apply {
addCategory(Intent.CATEGORY_HOME)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
startActivity(intent)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
window.attributes.layoutInDisplayCutoutMode = LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
isFoldable =
packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HINGE_ANGLE)
AndroidHelper.isFoldable = packageManager.hasSystemFeature(PackageManager.FEATURE_SENSOR_HINGE_ANGLE)
} catch (_: Exception) {
}
}
@@ -270,17 +66,15 @@ class MainActivity : AudioServiceActivity() {
override fun onUserLeaveHint() {
super.onUserLeaveHint()
methodChannel.invokeMethod("onUserLeaveHint", null)
AndroidHelper.ToDart.onUserLeaveHint?.run()
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration?
isInPictureInPictureMode: Boolean, newConfig: Configuration?
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
MethodChannel(
flutterEngine!!.dartExecutor.binaryMessenger,
"floating"
).invokeMethod("onPipChanged", isInPictureInPictureMode)
MethodChannel(flutterEngine!!.dartExecutor.binaryMessenger, "floating").invokeMethod(
"onPipChanged", isInPictureInPictureMode
)
}
}

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME