> clazzList = new ArrayList<>();
42 | static {
43 | Collections.addAll(clazzList, array);
44 | }
45 | }
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/task/TaskCommon.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.task;
2 |
3 | import java.util.List;
4 |
5 | import fansirsqi.xposed.sesame.model.BaseModel;
6 | import fansirsqi.xposed.sesame.util.Log;
7 | import fansirsqi.xposed.sesame.util.TimeUtil;
8 |
9 | /**
10 | * 通用任务工具类
11 | *
12 | * 提供任务相关的通用功能,包括时间判断和状态更新。
13 | */
14 | public class TaskCommon {
15 | public static volatile Boolean IS_ENERGY_TIME = false;
16 | public static volatile Boolean IS_AFTER_8AM = false;
17 | public static volatile Boolean IS_MODULE_SLEEP_TIME = false;
18 |
19 | public static void update() {
20 |
21 | Log.runtime("TaskCommon Update:");
22 | long currentTimeMillis = System.currentTimeMillis();
23 | List isEnergyTime = BaseModel.getEnergyTime().getValue();
24 | Log.runtime("获取能量时间配置:" + isEnergyTime);
25 | if (isConfigDisabled(isEnergyTime)) {
26 | Log.runtime("只收能量时间配置已关闭");
27 | IS_ENERGY_TIME = false;
28 | } else {
29 | IS_ENERGY_TIME = TimeUtil.checkInTimeRange(currentTimeMillis, isEnergyTime);
30 | }
31 |
32 | List isModuleSleepTime = BaseModel.getModelSleepTime().getValue();
33 | Log.runtime("获取模块休眠配置:" + isModuleSleepTime);
34 | if (isConfigDisabled(isModuleSleepTime)) {
35 | Log.runtime("休眠配置已关闭");
36 | IS_MODULE_SLEEP_TIME = false;
37 | } else {
38 | IS_MODULE_SLEEP_TIME = TimeUtil.checkInTimeRange(currentTimeMillis, isModuleSleepTime);
39 | }
40 |
41 | IS_AFTER_8AM = TimeUtil.isAfterOrCompareTimeStr(currentTimeMillis, "0800");
42 | }
43 |
44 | /**
45 | * 判断当前配置是否表示“关闭”
46 | *
47 | * @param config 输入的字符串列表
48 | * @return true 表示关闭
49 | */
50 | public static boolean isConfigDisabled(List config) {
51 | if (config == null || config.isEmpty()) return true;
52 |
53 | String first = config.get(0).trim();
54 |
55 | return "-1".equals(first);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/util/FansirsqiUtil.kt:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.util
2 |
3 | import kotlinx.coroutines.Dispatchers
4 | import kotlinx.coroutines.withContext
5 | import org.json.JSONObject
6 | import java.io.BufferedReader
7 | import java.io.InputStreamReader
8 | import java.net.HttpURLConnection
9 | import java.net.URL
10 |
11 | object FansirsqiUtil {
12 | // 定义一言API的URL
13 | private const val HITOKOTO_API_URL = "https://v1.hitokoto.cn/"
14 |
15 | /**
16 | * 获取一言(挂起函数),推荐在协程中使用
17 | * @return 成功返回句子,失败返回默认句子
18 | */
19 | suspend fun getOneWord(): String = withContext(Dispatchers.IO) {
20 | return@withContext try {
21 | val connection = URL(HITOKOTO_API_URL).openConnection() as HttpURLConnection
22 | connection.requestMethod = "GET"
23 | connection.connectTimeout = 5000
24 | connection.readTimeout = 5000
25 |
26 | val response = BufferedReader(InputStreamReader(connection.inputStream)).use { reader ->
27 | reader.readText()
28 | }
29 |
30 | val jsonObject = JSONObject(response)
31 | val hitokoto = jsonObject.optString(
32 | "hitokoto",
33 | " 去年相送,余杭门外,飞雪似杨花。\n今年春尽,杨花似雪,犹不见还家。"
34 | )
35 | val from = jsonObject.optString("from", "少年游·润州作代人寄远 苏轼")
36 |
37 | "$hitokoto\n\n -----Re: $from"
38 | } catch (e: Exception) {
39 | Log.printStackTrace(e)
40 | " 去年相送,余杭门外,飞雪似杨花。\n今年春尽,杨花似雪,犹不见还家。\n\n -----Re: 少年游·润州作代人寄远 苏轼"
41 | }
42 | }
43 |
44 | /**
45 | * 生成随机字符串
46 | * @param length 字符串长度
47 | */
48 | fun getRandomString(length: Int): String {
49 | val charPool: List = ('a'..'z') + ('A'..'Z') + ('0'..'9')
50 | return (1..length)
51 | .map { kotlin.random.Random.nextInt(0, charPool.size) }
52 | .map(charPool::get)
53 | .joinToString("")
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
19 |
26 |
27 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/extensions/JSONExtensions.kt:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.extensions
2 |
3 | import org.json.JSONArray
4 | import org.json.JSONException
5 |
6 | // 所有JSON相关的扩展函数放在这里
7 |
8 |
9 | /**
10 | * JSON 相关扩展函数集合
11 | */
12 | object JSONExtensions {
13 |
14 | /**
15 | * 安全地将 List 转换为 JSONArray
16 | * @receiver 字符串列表(允许为null,返回空JSONArray)
17 | */
18 | fun List?.toSafeJSONArray(): JSONArray {
19 | return this?.let { JSONArray(it) } ?: JSONArray()
20 | }
21 |
22 | /**
23 | * 将 MutableList 转换为 JSONArray
24 | * @receiver 可变的字符串集合
25 | * @throws JSONException 如果元素包含无效的JSON值
26 | */
27 | fun MutableList.toJSONArray(): JSONArray = JSONArray(this)
28 |
29 | /**
30 | * 将 JSONArray 转换为 MutableList
31 | * @receiver JSON数组对象
32 | * @throws JSONException 如果数组包含非字符串元素
33 | */
34 | fun JSONArray.toMutableStringList(): MutableList {
35 | return MutableList(length()) { getString(it) }
36 | }
37 |
38 | /**
39 | * 安全地将 JSONArray 转换为 List
40 | * @receiver JSON数组对象(允许为null,返回空列表)
41 | * @param default 转换失败时的默认值
42 | */
43 | fun JSONArray?.toSafeStringList(default: String = ""): List {
44 | if (this == null) return emptyList()
45 | return try {
46 | List(length()) { getString(it) ?: default }
47 | } catch (e: JSONException) {
48 | emptyList()
49 | }
50 | }
51 |
52 | /**
53 | * 将 JSONArray 转换为指定类型的列表
54 | * @param transform 类型转换函数
55 | */
56 | inline fun JSONArray.toList(transform: (Any?) -> T): List {
57 | return List(length()) { transform(get(it)) }
58 | }
59 |
60 | /**
61 | * 检查 JSONArray 是否为空
62 | */
63 | fun JSONArray?.isNullOrEmpty(): Boolean {
64 | return this == null || length() == 0
65 | }
66 |
67 | /**
68 | * 如果 JSONArray 为null则返回空数组
69 | */
70 | fun JSONArray?.orEmpty(): JSONArray {
71 | return this ?: JSONArray()
72 | }
73 | }
74 |
75 |
76 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/hook/rpc/bridge/RpcBridge.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.hook.rpc.bridge;
2 | import fansirsqi.xposed.sesame.entity.RpcEntity;
3 | public interface RpcBridge {
4 | RpcVersion getVersion();
5 | void load() throws Exception;
6 | void unload();
7 | String requestString(RpcEntity rpcEntity, int tryCount, int retryInterval);
8 | default String requestString(RpcEntity rpcEntity) {
9 | return requestString(rpcEntity, 3, -1);
10 | }
11 | default String requestString(String method, String data) {
12 | return requestString(method, data, 3, -1);
13 | }
14 | default String requestString(String method, String data, String relation) {
15 | return requestString(method, data, relation, 3, -1);
16 | }
17 | default String requestString(String method, String data, String appName, String methodName, String facadeName) {
18 | return requestString(new RpcEntity(method, data, appName, methodName, facadeName), 3, -1);
19 | }
20 | default String requestString(String method, String data, int tryCount, int retryInterval) {
21 | return requestString(new RpcEntity(method, data), tryCount, retryInterval);
22 | }
23 | default String requestString(String method, String data, String relation, int tryCount, int retryInterval) {
24 | return requestString(new RpcEntity(method, data, relation), tryCount, retryInterval);
25 | }
26 | RpcEntity requestObject(RpcEntity rpcEntity, int tryCount, int retryInterval);
27 |
28 | default RpcEntity requestObject(String method, String data, String relation) {
29 | return requestObject(method, data, relation, 3, -1);
30 | }
31 | default RpcEntity requestObject(String method, String data, int tryCount, int retryInterval) {
32 | return requestObject(new RpcEntity(method, data), tryCount, retryInterval);
33 | }
34 | default RpcEntity requestObject(String method, String data, String relation, int tryCount, int retryInterval) {
35 | return requestObject(new RpcEntity(method, data, relation), tryCount, retryInterval);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/util/GlobalThreadPools.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.util;
2 |
3 | import java.util.concurrent.ExecutorService;
4 | import java.util.concurrent.Executors;
5 | import java.util.concurrent.LinkedBlockingQueue;
6 | import java.util.concurrent.ScheduledExecutorService;
7 | import java.util.concurrent.SynchronousQueue;
8 | import java.util.concurrent.ThreadPoolExecutor;
9 | import java.util.concurrent.TimeUnit;
10 |
11 | /**
12 | * 全局线程池管理类
13 | */
14 | public class GlobalThreadPools {
15 | private static final String TAG = "GlobalThreadPools";
16 |
17 | /**
18 | * 使当前线程暂停指定的毫秒数。
19 | *
20 | * @param millis 毫秒数。
21 | */
22 | public static void sleep(long millis) {
23 | try {
24 | Thread.sleep(millis);
25 | } catch (InterruptedException e) {
26 | Log.error(TAG, "Thread sleep interrupted " + e.getMessage());
27 | Thread.currentThread().interrupt();
28 | } catch (Exception e1) {
29 | Log.printStackTrace(e1);
30 | // Thread.currentThread().interrupt();
31 | Log.error(TAG, "Thread sleep interrupted " + e1.getMessage());
32 | } catch (Throwable t) {
33 | Log.printStackTrace(t);
34 | // Thread.currentThread().interrupt();
35 | Log.error(TAG, "Thread sleep interrupted " + t.getMessage());
36 | }
37 | }
38 |
39 | public static void shutdownAndAwaitTermination(ExecutorService pool, long timeout, String poolName) {
40 | if (pool != null && !pool.isShutdown()) {
41 | pool.shutdown();
42 | try {
43 | if (!pool.awaitTermination(1, TimeUnit.SECONDS)) {
44 | pool.shutdownNow();
45 | if (!pool.awaitTermination(timeout, TimeUnit.SECONDS)) {
46 | Log.runtime(TAG, "thread " + poolName + " can't close");
47 | }
48 | }
49 | } catch (InterruptedException ie) {
50 | pool.shutdownNow();
51 | Thread.currentThread().interrupt();
52 | }
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/task/ancientTree/AncientTreeRpcCall.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.task.ancientTree;
2 | import fansirsqi.xposed.sesame.hook.RequestManager;
3 | public class AncientTreeRpcCall {
4 | private static final String VERSION = "20230522";
5 | public static String homePage(String selectCityCode) {
6 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.homePage",
7 | "[{\"cityCode\":\"330100\",\"selectCityCode\":\"" + selectCityCode
8 | + "\",\"source\":\"antforesthome\"}]");
9 | }
10 | public static String queryTreeItemsForExchange(String cityCode) {
11 | return RequestManager.requestString("alipay.antforest.forest.h5.queryTreeItemsForExchange",
12 | "[{\"cityCode\":\"" + cityCode
13 | + "\",\"itemTypes\":\"\",\"source\":\"chInfo_ch_appcenter__chsub_9patch\",\"version\":\""
14 | + VERSION + "\"}]");
15 | }
16 | public static String districtDetail(String districtCode) {
17 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.districtDetail",
18 | "[{\"districtCode\":\"" + districtCode + "\",\"source\":\"antforesthome\"}]");
19 | }
20 | public static String projectDetail(String ancientTreeProjectId, String cityCode) {
21 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.projectDetail",
22 | "[{\"ancientTreeProjectId\":\"" + ancientTreeProjectId
23 | + "\",\"channel\":\"ONLINE\",\"cityCode\":\"" + cityCode
24 | + "\",\"source\":\"ancientreethome\"}]");
25 | }
26 | public static String protect(String activityId, String ancientTreeProjectId, String cityCode) {
27 | return RequestManager.requestString("alipay.greenmatrix.rpc.h5.ancienttree.protect",
28 | "[{\"ancientTreeActivityId\":\"" + activityId + "\",\"ancientTreeProjectId\":\""
29 | + ancientTreeProjectId + "\",\"cityCode\":\"" + cityCode
30 | + "\",\"source\":\"ancientreethome\"}]");
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/ui/ObjSyncReference.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.ui;
2 | import lombok.Data;
3 | /**
4 | * 线程安全的引用包装器。
5 | * 提供了一个泛型对象的线程安全访问和修改。
6 | * @param 泛型类型参数。
7 | */
8 | @Data
9 | public class ObjSyncReference {
10 | /**
11 | * 被包装的对象。
12 | */
13 | private T obj;
14 | /**
15 | * 无参构造函数。
16 | */
17 | public ObjSyncReference() {
18 | }
19 | /**
20 | * 带对象的构造函数。
21 | * @param obj 被包装的对象。
22 | */
23 | public ObjSyncReference(T obj) {
24 | this.obj = obj;
25 | }
26 | /**
27 | * 检查对象是否存在。
28 | * @return 如果对象不为空,返回true。
29 | */
30 | public Boolean has() {
31 | synchronized (this) {
32 | return this.obj != null;
33 | }
34 | }
35 | /**
36 | * 获取被包装的对象。
37 | * @return 被包装的对象。
38 | */
39 | public T get() {
40 | synchronized (this) {
41 | return obj;
42 | }
43 | }
44 | /**
45 | * 设置被包装的对象。
46 | * 如果当前对象与传入对象相同,或当前对象为null且传入对象不为null,则设置对象并返回true。
47 | * @param obj 新的对象。
48 | * @return 如果设置成功,返回true。
49 | */
50 | public Boolean set(T obj) {
51 | synchronized (this) {
52 | if (this.obj == obj) {
53 | return true;
54 | }
55 | if (this.obj != null) {
56 | return false;
57 | }
58 | this.obj = obj;
59 | return true;
60 | }
61 | }
62 | /**
63 | * 强制设置被包装的对象。
64 | * 无论当前对象是什么,都会设置为传入的对象。
65 | * @param obj 新的对象。
66 | */
67 | public void setForce(T obj) {
68 | synchronized (this) {
69 | this.obj = obj;
70 | }
71 | }
72 | /**
73 | * 删除被包装的对象。
74 | */
75 | public void del() {
76 | synchronized (this) {
77 | this.obj = null;
78 | }
79 | }
80 | /**
81 | * 如果被包装的对象与传入对象相同,则删除。
82 | * @param obj 要比较的对象。
83 | */
84 | public void delIfEquals(T obj) {
85 | synchronized (this) {
86 | if (this.obj == obj) {
87 | this.obj = null;
88 | }
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable/all_log.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
20 |
21 |
--------------------------------------------------------------------------------
/serve-debug/schemas.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 | import json # Import json for parsing
3 | from pydantic import BaseModel, field_validator, ValidationError # Import field_validator
4 | from typing import Optional, Any # 导入 Optional 和 Any 用于可选字段和任意类型
5 |
6 | from models import HookData # 保留,可能未来需要
7 | from config import logger
8 |
9 | # 定义 Pydantic 模型用于请求体和响应体
10 | class HookDataBase(BaseModel):
11 | # 更新字段类型以匹配实际传入的数据
12 | TimeStamp: Optional[int] = None # 时间戳通常是整数
13 | Method: str
14 | Params: Optional[Any] = None # Params 可以是任意 JSON 对象/字典
15 | Data: Optional[Any] = None # Data 可以是任意 JSON 对象/字典
16 |
17 | class HookDataCreate(HookDataBase):
18 | pass # 创建时不需要 id, created_at, updated_at
19 |
20 | class HookDataSchema(HookDataBase):
21 | id: int
22 | created_at: datetime
23 | updated_at: datetime
24 |
25 | # Override types from HookDataBase for response serialization
26 | TimeStamp: Optional[int] = None
27 | Params: Optional[Any] = None
28 | Data: Optional[Any] = None
29 |
30 | @field_validator('TimeStamp', mode='before')
31 | @classmethod
32 | def parse_timestamp(cls, value):
33 | if isinstance(value, str):
34 | try:
35 | return int(value)
36 | except (ValueError, TypeError):
37 | logger.warning(f"Could not parse timestamp string: {value}")
38 | return None # Or handle error as needed
39 | return value # Keep original if already int or None
40 |
41 | @field_validator('Params', 'Data', mode='before')
42 | @classmethod
43 | def parse_json_string(cls, value):
44 | if isinstance(value, str):
45 | try:
46 | return json.loads(value)
47 | except json.JSONDecodeError:
48 | logger.warning(f"Could not parse JSON string: {value}")
49 | # Decide how to handle invalid JSON: return original string, None, or raise error
50 | return value # Return original string if parsing fails
51 | return value # Keep original if already dict or None
52 |
53 | class Config:
54 | from_attributes = True # 允许从 ORM 对象创建 Pydantic 模型 (Pydantic V2)
55 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/forest.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/task/AnswerAI/AnswerAIInterface.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.task.AnswerAI;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * AI答题服务接口
7 | * 定义了AI答题服务的基本操作,包括获取答案、设置模型等功能
8 | */
9 | public interface AnswerAIInterface {
10 |
11 | /**
12 | * 设置模型名称
13 | *
14 | * @param modelName 模型名称
15 | */
16 | default void setModelName(String modelName) {
17 | // 默认空实现
18 | }
19 |
20 | /**
21 | * 获取模型名称
22 | *
23 | * @return 当前使用的模型名称
24 | */
25 | default String getModelName() {
26 | // 默认空实现
27 | return "";
28 | }
29 |
30 | /**
31 | * 获取AI回答结果
32 | *
33 | * @param text 问题内容
34 | * @return AI回答结果,如果获取失败返回空字符串
35 | */
36 | String getAnswerStr(String text);
37 |
38 | /**
39 | * 获取AI回答结果,指定模型
40 | *
41 | * @param text 问题内容
42 | * @param model 模型名称
43 | * @return AI回答结果,如果获取失败返回空字符串
44 | */
45 | String getAnswerStr(String text, String model);
46 |
47 | /**
48 | * 获取AI答案
49 | *
50 | * @param title 问题标题
51 | * @param answerList 候选答案列表
52 | * @return 选中的答案索引,如果没有找到合适的答案返回-1
53 | */
54 | Integer getAnswer(String title, List answerList);
55 |
56 | /**
57 | * 释放资源
58 | * 实现类应在此方法中清理所有使用的资源
59 | */
60 | default void release() {
61 | // 默认空实现
62 | }
63 |
64 | /**
65 | * 获取单例实例
66 | *
67 | * @return 默认的AI答题服务实现
68 | */
69 | static AnswerAIInterface getInstance() {
70 | return SingletonHolder.INSTANCE;
71 | }
72 |
73 | /**
74 | * 单例持有者,延迟加载
75 | */
76 | class SingletonHolder {
77 | private static final AnswerAIInterface INSTANCE = new AnswerAIInterface() {
78 | @Override
79 | public String getAnswerStr(String text) {
80 | return "";
81 | }
82 |
83 | @Override
84 | public String getAnswerStr(String text, String model) {
85 | return "";
86 | }
87 |
88 | @Override
89 | public Integer getAnswer(String title, List answerList) {
90 | return -1;
91 | }
92 | };
93 | }
94 | }
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/ChoiceModelField.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.model.modelFieldExt;
2 |
3 | import android.content.Context;
4 | import android.view.Gravity;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.Button;
8 | import android.widget.LinearLayout;
9 |
10 | import androidx.core.content.ContextCompat;
11 |
12 | import fansirsqi.xposed.sesame.R;
13 | import fansirsqi.xposed.sesame.model.ModelField;
14 | import fansirsqi.xposed.sesame.ui.ChoiceDialog;
15 | public class ChoiceModelField extends ModelField {
16 | private String[] choiceArray;
17 |
18 | public ChoiceModelField(String code, String name, Integer value) {
19 | super(code, name, value);
20 | }
21 | public ChoiceModelField(String code, String name, Integer value, String[] choiceArray) {
22 | super(code, name, value);
23 | this.choiceArray = choiceArray;
24 | }
25 |
26 | public ChoiceModelField(String code, String name, Integer value,String desc) {
27 | super(code, name, value, desc);
28 | }
29 | public ChoiceModelField(String code, String name, Integer value, String[] choiceArray,String desc) {
30 | super(code, name, value, desc);
31 | this.choiceArray = choiceArray;
32 | }
33 |
34 | @Override
35 | public String getType() {
36 | return "CHOICE";
37 | }
38 | public String[] getExpandKey() {
39 | return choiceArray;
40 | }
41 | @Override
42 | public View getView(Context context) {
43 | Button btn = new Button(context);
44 | btn.setText(getName());
45 | btn.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
46 | btn.setTextColor(ContextCompat.getColor(context, R.color.selection_color));
47 | btn.setBackground(ContextCompat.getDrawable(context, R.drawable.dialog_list_button));
48 | btn.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
49 | btn.setMinHeight(150);
50 | btn.setMaxHeight(180);
51 | btn.setPaddingRelative(40, 0, 40, 0);
52 | btn.setAllCaps(false);
53 | btn.setOnClickListener(v -> ChoiceDialog.show(v.getContext(), ((Button) v).getText(), this));
54 | return btn;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/farm.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
13 |
16 |
19 |
22 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/ui/OptionsAdapter.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.ui;
2 | /*
3 | * @Description: 好友统计,列表长按菜单
4 | * @UpdateDate: 2024/10/23
5 | * @UpdateTime: 16:39
6 | */
7 | import android.annotation.SuppressLint;
8 | import android.content.Context;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.BaseAdapter;
13 | import android.widget.TextView;
14 | import java.util.ArrayList;
15 | /**
16 | * 选项适配器。
17 | * 用于在列表视图中显示选项。
18 | */
19 | public class OptionsAdapter extends BaseAdapter {
20 | @SuppressLint("StaticFieldLeak")
21 | private static OptionsAdapter adapter;
22 | /**
23 | * 获取单例适配器实例。
24 | * @param c 上下文对象。
25 | * @return 适配器实例。
26 | */
27 | public static OptionsAdapter get(Context c) {
28 | if (adapter == null) {
29 | adapter = new OptionsAdapter(c);
30 | }
31 | return adapter;
32 | }
33 | private final Context context;
34 | private final ArrayList list;
35 | /**
36 | * 私有构造函数,防止外部直接实例化。
37 | * @param c 上下文对象。
38 | */
39 | private OptionsAdapter(Context c) {
40 | context = c;
41 | list = new ArrayList<>();
42 | // 初始化列表项
43 | list.add("查看森林");
44 | list.add("查看庄园");
45 | list.add("查看资料");
46 | list.add("删除");
47 | }
48 | @Override
49 | public int getCount() {
50 | // 返回列表项的数量
51 | return list == null ? 0 : list.size();
52 | }
53 | @Override
54 | public Object getItem(int position) {
55 | // 返回指定位置的列表项
56 | return list.get(position);
57 | }
58 | @Override
59 | public long getItemId(int position) {
60 | // 返回列表项的唯一ID,这里简单地使用位置作为ID
61 | return position;
62 | }
63 | @SuppressLint("InflateParams")
64 | @Override
65 | public View getView(int position, View convertView, ViewGroup parent) {
66 | // 复用convertView以提高性能
67 | if (convertView == null) {
68 | // inflate布局
69 | convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, null);
70 | }
71 | // 获取TextView并设置文本
72 | TextView txt = (TextView) convertView;
73 | txt.setText(getItem(position).toString());
74 | return convertView;
75 | }
76 | }
--------------------------------------------------------------------------------
/AppIdMap.txt:
--------------------------------------------------------------------------------
1 | 10000003:充值中心
2 | 10000009:爱心捐赠
3 | 20000001:null
4 | 20000003:账单
5 | 20000014:我的银行卡
6 | 20000019:余额
7 | 20000032:余额宝
8 | 20000033:余额提现
9 | 20000038:关联账户认证/身份认证
10 | 20000042:null
11 | 20000047:null
12 | 20000067:?
13 | 20000076:账单
14 | 20000111:?
15 | 20000120:饿了么外卖
16 | 20000123:个人收钱
17 | 20000134:股票
18 | 20000142:娱乐宝
19 | 20000160:支付宝会员
20 | 20000165:理财
21 | 20000180:借呗
22 | 20000193:生活缴费
23 | 20000199:花呗
24 | 20000218:黄金
25 | 20000241:车险服务
26 | 20000691:我的客服
27 | 20000725:设置
28 | 20000754:我的快递
29 | 20000793:基金
30 | 20000909:args error
31 | 20000936:蚂蚁保险
32 | 20001045:args error
33 | 60000002:蚂蚁森林
34 | 60000010:?
35 | 60000071:天天有料
36 | 60000081:商家服务
37 | 60000123:args error
38 | 60000127:args error
39 | 60000148:财富号
40 | 60000161:支付宝会员周周乐
41 | 63300018:?
42 | 66666673:风险测试/风险类型
43 | 66666674:蚂蚁庄园
44 | 66666698:标签系统/标签和随笔
45 | 66666708:余利宝
46 | 66666721:财富有料
47 | 66666735:基金组合
48 | 66666741:上证指数讨论区
49 | 66666755:好医保
50 | 66666783:爱攒油加油站
51 | 66666819:还贷管家
52 | 66666823:?
53 | 66666825:财富标签页/我的理财标签
54 | 66666828:知识课堂
55 | 66666866:收益曲线
56 | 66666883:网商贷
57 | 66666886:蚂蚁森林合种
58 | 66666897:工资理财
59 | 68686987:网贷
60 | 68687015:办理赔
61 | 68687031:智能理财助理
62 | 68687049:蚂蚁心愿
63 | 68687058:null
64 | 68687109:null
65 | 68687129:行走积分赛
66 | 68687131:养老金
67 | 68687158:支付宝积分猜涨跌
68 | 68687197:null
69 | 68687233:股票工具
70 | 68687242:尊享理财
71 | 68687249:大盘晴雨表
72 | 68687279:null
73 | 68687357:null
74 | 77700124:余额宝
75 | 77700126:互相宝
76 | 77700130:花呗账单
77 | 77700144:扫码点单
78 | 77700152:信用卡还款
79 | 77700173:标注高德地图(在高德地图上标注我的商铺)
80 | 77700174:财富王者
81 | 77700199:财富SHOW
82 | 77700223:笔笔攒
83 | 77700234:模拟炒股
84 | 77700252:市场投资情绪
85 | 77700253:资金管理
86 | 77700257:收钱有奖
87 | 77700279:校园生活
88 | 77700292:收入统计
89 | 77700296:?
90 | 98000012:?
91 | 2013062600000474:new
92 | 2016122804685366:new
93 | 2017081908285290:new
94 | 2018030502317554:new
95 | 2018040402504128:new
96 | 2018051160096372:new
97 | 2018052460226391:new
98 | 2018071160524903:new
99 | 2018091361395351:new
100 | 2018110662035452:new
101 | 2018110762040932:new
102 | 2018112962211021:new
103 | 2018122762703259:new
104 | 2019010462802084:new
105 | 2019012963182381:new
106 | 2019021363229455:new
107 | 2019030863479637:new
108 | 2019031563521845:new
109 | 2019032763709372:new
110 | 2019032863733398:new
111 | 2019040963856084:new
112 | 2019042364288308:new
113 | 2019060465478294:new
114 | 2019060565481471:new
115 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/data/ViewAppInfo.kt:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.data
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.content.pm.ApplicationInfo
7 | import android.os.Bundle
8 | import fansirsqi.xposed.sesame.BuildConfig
9 | import fansirsqi.xposed.sesame.R
10 | import fansirsqi.xposed.sesame.util.Log
11 | import androidx.core.net.toUri
12 |
13 | @SuppressLint("StaticFieldLeak")
14 | object ViewAppInfo {
15 | val TAG: String = ViewAppInfo::class.java.simpleName
16 | var context: Context? = null
17 | var appTitle: String = ""
18 | var appVersion: String = ""
19 | var appBuildTarget: String = ""
20 | var appBuildNumber: String = ""
21 | val emojiList =
22 | listOf(
23 | "🍅", "🍓", "🥓", "🍂", "🍚", "🌰", "🟢", "🌴",
24 | "🥗", "🧀", "🥩", "🍍", "🌶️", "🍲", "🍆", "🥕",
25 | "✨", "🍑", "🍘", "🍀", "🥞", "🍈", "🥝", "🧅",
26 | "🌵", "🌾", "🥜", "🍇", "🌭", "🥑", "🥐", "🥖",
27 | "🍊", "🌽", "🍉", "🍖", "🍄", "🥚", "🥙", "🥦",
28 | "🍌", "🍱", "🍏", "🍎", "🌲", "🌿", "🍁", "🍒",
29 | "🥔", "🌯", "🌱", "🍐", "🍞", "🍳", "🍙", "🍋",
30 | "🍗", "🌮", "🍃", "🥘", "🥒", "🧄", "🍠", "🥥", "📦"
31 | )
32 |
33 | // var runType: RunType? = RunType.DISABLE
34 | @Volatile
35 | internal var runType: RunType? = RunType.DISABLE
36 | @Synchronized set
37 |
38 | @JvmStatic
39 | fun setRunType(type: RunType) {
40 | runType = type
41 | }
42 |
43 | @JvmStatic
44 | fun getRunType() = runType
45 |
46 | /**
47 | * 初始化 ViewAppInfo,设置应用的相关信息,如版本号、构建日期等
48 | *
49 | * @param context 上下文对象,用于获取应用的资源信息
50 | */
51 | fun init(context: Context) {
52 | if (ViewAppInfo.context == null) {
53 | ViewAppInfo.context = context
54 | appBuildNumber = BuildConfig.VERSION_CODE.toString()
55 | appTitle = context.getString(R.string.app_name) //+ BuildConfig.VERSION_NAME
56 | appBuildTarget = BuildConfig.BUILD_DATE + " " + BuildConfig.BUILD_TIME + " ⏰"
57 | try {
58 | appVersion = "${BuildConfig.VERSION_NAME} " + emojiList.random()
59 | } catch (e: Exception) {
60 | Log.printStackTrace(e)
61 | }
62 | }
63 | }
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/entity/ReserveEntity.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.entity;
2 | import java.util.ArrayList;
3 | import java.util.Collections;
4 | import java.util.Iterator;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.Set;
8 | import fansirsqi.xposed.sesame.util.maps.IdMapManager;
9 | import fansirsqi.xposed.sesame.util.maps.ReserveaMap;
10 | /**
11 | * 表示支付宝保留项的实体类,包含 ID 和名称。
12 | */
13 | public class ReserveEntity extends MapperEntity {
14 | // 使用 volatile 关键字确保多线程环境下的可见性
15 | private static volatile List list;
16 | /**
17 | * 构造方法,根据给定的 ID 和名称初始化对象。
18 | * @param i 保留项的 ID
19 | * @param n 保留项的名称
20 | */
21 | public ReserveEntity(String i, String n) {
22 | id = i;
23 | name = n;
24 | }
25 | /**
26 | * 获取包含所有保留项的列表,首次调用时从 ReserveIdMapUtil 初始化。
27 | * 使用双重检查锁定机制实现懒加载以提高性能。
28 | * @return 包含所有 ReserveEntity 对象的不可变列表
29 | */
30 | public static List getList() {
31 | if (list == null) {
32 | synchronized (ReserveEntity.class) {
33 | if (list == null) {
34 | List tempList = new ArrayList<>();
35 | Set> idSet = IdMapManager.getInstance(ReserveaMap.class).getMap().entrySet();
36 | for (Map.Entry entry : idSet) {
37 | tempList.add(new ReserveEntity(entry.getKey(), entry.getValue()));
38 | }
39 | list = Collections.unmodifiableList(tempList);
40 | }
41 | }
42 | }
43 | return list;
44 | }
45 | /**
46 | * 根据给定的 ID 删除相应的 ReserveEntity 对象。
47 | * 首次调用 getList 方法以确保列表已初始化。
48 | * @param id 要删除的保留项 ID
49 | */
50 | public static void remove(String id) {
51 | getList();
52 | synchronized (ReserveEntity.class) {
53 | List tempList = new ArrayList<>(list); // 创建可变列表的副本
54 | Iterator iterator = tempList.iterator();
55 | while (iterator.hasNext()) {
56 | ReserveEntity reserve = iterator.next();
57 | if (reserve.id.equals(id)) {
58 | iterator.remove();
59 | }
60 | }
61 | list = Collections.unmodifiableList(tempList); // 确保返回不可变列表
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/entity/CollectEnergyEntity.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.entity;
2 | import lombok.Getter;
3 | import lombok.Setter;
4 | import org.json.JSONObject;
5 | /**
6 | * 表示一个能量收集实体,包含用户信息及操作相关的状态。
7 | */
8 | @Getter
9 | public class CollectEnergyEntity {
10 | // 用户 ID
11 | private final String userId;
12 | // 用户主页 JSON 对象
13 | @Setter
14 | private JSONObject userHome;
15 | // RPC 请求实体
16 | @Setter
17 | private RpcEntity rpcEntity;
18 | // 收集次数
19 | private Integer collectCount = 0;
20 | // 尝试次数
21 | private Integer tryCount = 0;
22 | // 是否需要翻倍
23 | @Setter
24 | private Boolean needDouble = false;
25 | // 是否需要重试
26 | @Setter
27 | private Boolean needRetry = false;
28 | /**
29 | * 构造方法,仅指定用户 ID。
30 | * @param userId 用户 ID
31 | */
32 | public CollectEnergyEntity(String userId) {
33 | this.userId = userId;
34 | }
35 | /**
36 | * 构造方法,指定用户 ID 和用户主页信息。
37 | * @param userId 用户 ID
38 | * @param userHome 用户主页 JSON 对象
39 | */
40 | public CollectEnergyEntity(String userId, JSONObject userHome) {
41 | this.userId = userId;
42 | this.userHome = userHome;
43 | }
44 | /**
45 | * 构造方法,指定用户 ID、用户主页信息及 RPC 请求实体。
46 | * @param userId 用户 ID
47 | * @param userHome 用户主页 JSON 对象
48 | * @param rpcEntity RPC 请求实体
49 | */
50 | public CollectEnergyEntity(String userId, JSONObject userHome, RpcEntity rpcEntity) {
51 | this.userId = userId;
52 | this.userHome = userHome;
53 | this.rpcEntity = rpcEntity;
54 | }
55 | /**
56 | * 增加尝试次数。
57 | * @return 更新后的尝试次数
58 | */
59 | public Integer addTryCount() {
60 | this.tryCount += 1;
61 | return tryCount;
62 | }
63 | /**
64 | * 重置尝试次数为 0。
65 | */
66 | public void resetTryCount() {
67 | this.tryCount = 0;
68 | }
69 | /**
70 | * 设置需要翻倍,并增加收集次数。
71 | */
72 | public void setNeedDouble() {
73 | this.collectCount += 1;
74 | this.needDouble = true;
75 | }
76 | /**
77 | * 取消需要翻倍状态。
78 | */
79 | public void unsetNeedDouble() {
80 | this.needDouble = false;
81 | }
82 | /**
83 | * 设置需要重试状态。
84 | */
85 | public void setNeedRetry() {
86 | this.needRetry = true;
87 | }
88 | /**
89 | * 取消需要重试状态。
90 | */
91 | public void unsetNeedRetry() {
92 | this.needRetry = false;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/fansirsqi/xposed/sesame/model/modelFieldExt/EmptyModelField.java:
--------------------------------------------------------------------------------
1 | package fansirsqi.xposed.sesame.model.modelFieldExt;
2 | import android.app.AlertDialog;
3 | import android.content.Context;
4 | import android.view.Gravity;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.Button;
8 | import android.widget.LinearLayout;
9 | import android.widget.Toast;
10 | import androidx.core.content.ContextCompat;
11 | import com.fasterxml.jackson.annotation.JsonIgnore;
12 | import fansirsqi.xposed.sesame.R;
13 | import fansirsqi.xposed.sesame.model.ModelField;
14 | public class EmptyModelField extends ModelField