1
0
mirror of https://github.com/areteruhiro/LIME-beta-hiro.git synced 2025-02-05 21:11:39 +09:00

Compare commits

...

8 Commits

5 changed files with 109 additions and 135 deletions

View File

@ -10,7 +10,7 @@ android {
minSdk 28
targetSdk 35
versionCode 116160
versionName "1.16.17.2既読者確認機能β"
versionName "1.17.1"
multiDexEnabled false
proguardFiles += 'proguard-rules.pro'
buildConfigField 'String', 'HOOK_TARGET_VERSION', '"141910383"'

View File

@ -133,7 +133,21 @@ public class Main implements IXposedHookLoadPackage, IXposedHookInitPackageResou
}
});
}
if (limeOptions.RemoveNotification.checked) {
resparam.res.hookLayout(Constants.PACKAGE_NAME, "layout", "home_list_row_friend_profile_update_carousel", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(XC_LayoutInflated.LayoutInflatedParam liparam) throws Throwable {
liparam.view.setVisibility(View.GONE);
}
});
resparam.res.hookLayout(Constants.PACKAGE_NAME, "layout", "home_list_row_friend_profile_update_carousel_item", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(XC_LayoutInflated.LayoutInflatedParam liparam) throws Throwable {
liparam.view.setVisibility(View.GONE);
}
});
}
if (limeOptions.removeNaviAlbum.checked) {
resparam.res.setReplacement(Constants.PACKAGE_NAME, "drawable", "navi_top_albums", xModuleResources.fwd(R.drawable.empty_drawable));
}

View File

@ -38,6 +38,7 @@ public class PhotoAddNotification implements IHook {
private static final int MAX_RETRIES = 20;
private static final long RETRY_DELAY = 1000;
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.PhotoAddNotification.checked) return;
@ -96,12 +97,14 @@ public class PhotoAddNotification implements IHook {
String tag = (String) param.args[0];
int ids = (int) param.args[1];
if (Objects.equals(notification.category, "call")) {
// logAllNotificationDetails(tag, ids, notification, notification.tickerText != null ? notification.tickerText.toString() : null);
return;
}
if (limeOptions.GroupNotification.checked) {
handleNotificationHook(context, db1, db2, param, notification, true);
}
else {
} else {
if (param.args[0] == null) {
param.setResult(null);
return;
@ -112,6 +115,7 @@ public class PhotoAddNotification implements IHook {
});
}
private static boolean isHandlingNotification = false;
private static final Set<String> processedNotifications = new HashSet<>();
@ -124,7 +128,6 @@ public class PhotoAddNotification implements IHook {
isHandlingNotification = true;
try {
Notification originalNotification = hasTag ? (Notification) param.args[2] : (Notification) param.args[1];
String title = getNotificationTitle(originalNotification);
@ -235,7 +238,6 @@ public class PhotoAddNotification implements IHook {
param.setResult(null);
int randomNotificationId = (int) System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
@ -253,6 +255,7 @@ public class PhotoAddNotification implements IHook {
isHandlingNotification = false;
}
}
private Bitmap loadBitmapFromFile(File file) {
if (!file.exists()) {
return null;
@ -288,6 +291,7 @@ public class PhotoAddNotification implements IHook {
return null;
}
}
private Notification createNotificationWithImageFromBitmap(Context context, Notification original, Bitmap bitmap, String originalText) {
Notification.BigPictureStyle bigPictureStyle = new Notification.BigPictureStyle()
.bigPicture(bitmap) // メインの画像
@ -379,6 +383,7 @@ public class PhotoAddNotification implements IHook {
cursor.close();
return result;
}
private String getNotificationTitle(Notification notification) {
if (notification.extras != null) {
return notification.extras.getString(Notification.EXTRA_TITLE);
@ -392,47 +397,46 @@ public class PhotoAddNotification implements IHook {
}
return null;
}
}
/*
private void logAllNotificationDetails(String method, int ids, Notification notification, String tag) {
XposedBridge.log(method + " called. ID: " + ids + (tag != null ? ", Tag: " + tag : ""));
XposedBridge.log("Notification Icon: " + notification.icon);
XposedBridge.log("Notification When: " + notification.when);
XposedBridge.log("Notification Flags: " + notification.flags);
XposedBridge.log("Notification Priority: " + notification.priority);
XposedBridge.log("Notification Category: " + notification.category);
XposedBridge.log(method + " called. ID: " + ids + (tag != null ? ", Tag: " + tag : ""));
XposedBridge.log("Notification Icon: " + notification.icon);
XposedBridge.log("Notification When: " + notification.when);
XposedBridge.log("Notification Flags: " + notification.flags);
XposedBridge.log("Notification Priority: " + notification.priority);
XposedBridge.log("Notification Category: " + notification.category);
if (notification.extras != null) {
Bundle extras = notification.extras;
XposedBridge.log("Notification Extras:");
XposedBridge.log("Notification Extras:");
for (String key : extras.keySet()) {
Object value = extras.get(key);
XposedBridge.log(" " + key + ": " + (value != null ? value.toString() : "null"));
XposedBridge.log(" " + key + ": " + (value != null ? value.toString() : "null"));
}
} else {
XposedBridge.log("Notification has no extras.");
XposedBridge.log("Notification has no extras.");
}
if (notification.actions != null) {
XposedBridge.log("Notification Actions:");
XposedBridge.log("Notification Actions:");
for (int i = 0; i < notification.actions.length; i++) {
Notification.Action action = notification.actions[i];
XposedBridge.log(" Action " + i + ": " +
XposedBridge.log(" Action " + i + ": " +
"Title=" + action.title +
", Intent=" + action.actionIntent);
}
} else {
//XposedBridge.log("No actions found.");
//XposedBridge.log("No actions found.");
}
// その他の情報
XposedBridge.log("Notification Visibility: " + notification.visibility);
XposedBridge.log("Notification Color: " + notification.color);
XposedBridge.log("Notification Group: " + notification.getGroup());
XposedBridge.log("Notification SortKey: " + notification.getSortKey());
XposedBridge.log("Notification Sound: " + notification.sound);
XposedBridge.log("Notification Vibrate: " + (notification.vibrate != null ? "Yes" : "No"));
XposedBridge.log("Notification Visibility: " + notification.visibility);
XposedBridge.log("Notification Color: " + notification.color);
XposedBridge.log("Notification Group: " + notification.getGroup());
XposedBridge.log("Notification SortKey: " + notification.getSortKey());
XposedBridge.log("Notification Sound: " + notification.sound);
XposedBridge.log("Notification Vibrate: " + (notification.vibrate != null ? "Yes" : "No"));
}
*/
}

View File

@ -67,7 +67,6 @@ public class ReadChecker implements IHook {
private String currentGroupId = null;
private static final int MAX_RETRY_COUNT = 3; // 最大リトライ回数
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.ReadChecker.checked) return;
@ -111,7 +110,7 @@ public class ReadChecker implements IHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
String chatId = (String) param.getResult();
//XposedBridge.log(chatId);
XposedBridge.log(chatId);
if (isGroupExists(chatId)) {
shouldHookOnCreate = true;
currentGroupId = chatId;
@ -133,7 +132,7 @@ public class ReadChecker implements IHook {
Context systemContext = (Context) XposedHelpers.callMethod(param.thisObject, "getApplicationContext");
moduleContext = systemContext.createPackageContext("io.github.hiro.lime", Context.CONTEXT_IGNORE_SECURITY);
} catch (Exception e) {
//XposedBridge.log("Failed to get module context: " + e.getMessage());
XposedBridge.log("Failed to get module context: " + e.getMessage());
}
}
}
@ -142,7 +141,7 @@ public class ReadChecker implements IHook {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (moduleContext == null) {
//XposedBridge.log("Module context is null. Skipping hook.");
XposedBridge.log("Module context is null. Skipping hook.");
return;
}
@ -164,7 +163,7 @@ public class ReadChecker implements IHook {
private boolean isGroupExists(String groupId) {
if (limeDatabase == null) {
//XposedBridge.log("Database is not initialized.");
XposedBridge.log("Database is not initialized.");
return false;
}
String query = "SELECT 1 FROM read_message WHERE group_id = ?";
@ -177,7 +176,7 @@ public class ReadChecker implements IHook {
private boolean isNoGroup(String groupId) {
if (limeDatabase == null) {
//XposedBridge.log("Database is not initialized.");
XposedBridge.log("Database is not initialized.");
return true;
}
String query = "SELECT group_name FROM read_message WHERE group_id = ?";
@ -318,6 +317,7 @@ public class ReadChecker implements IHook {
ViewGroup layout = activity.findViewById(android.R.id.content);
layout.addView(imageButton);
}
private boolean copyImageFile(Context moduleContext, String imageName, File destinationFile) {
try (InputStream in = moduleContext.getResources().openRawResource(
moduleContext.getResources().getIdentifier(imageName.replace(".png", ""), "drawable", "io.github.hiro.lime"));
@ -333,6 +333,8 @@ public class ReadChecker implements IHook {
return false;
}
}
private int dpToPx(@NonNull Context context, float dp) {
float density = context.getResources().getDisplayMetrics().density;
return Math.round(dp * density);
@ -496,7 +498,7 @@ public class ReadChecker implements IHook {
if (userNameStr != null) {
// //("取得したuser_name: " + userNameStr);
//XposedBridge.log("取得したSent_User: " + SentUser);
XposedBridge.log("取得したSent_User: " + SentUser);
// user_name の値をトリミングして "null" かどうかを確認
String trimmedUserName = userNameStr.trim();
@ -511,15 +513,15 @@ public class ReadChecker implements IHook {
// SentUser mid として使用しcontacts テーブルからユーザー名を再取得
if (SentUser != null) {
String newUserName = queryDatabase(db4, "SELECT profile_name FROM contacts WHERE mid=?", SentUser);
//XposedBridge.log("再取得したnewUserName: " + newUserName);
XposedBridge.log("再取得したnewUserName: " + newUserName);
if (newUserName != null && !newUserName.equals("null")) {
// 新しいユーザー名を反映
userNameStr = "-" + newUserName + " [" + trimmedUserName.substring(bracketIndex + 1);
//XposedBridge.log("更新後のuser_name: " + userNameStr);
XposedBridge.log("更新後のuser_name: " + userNameStr);
}
} else {
//XposedBridge.log("SentUserがnullです。");
XposedBridge.log("SentUserがnullです。");
}
}
}
@ -634,6 +636,12 @@ public class ReadChecker implements IHook {
private void fetchDataAndSave(SQLiteDatabase db3, SQLiteDatabase db4, String paramValue, Context context, Context moduleContext) {
//("fetchDataAndSave");
if (paramValue == null) {
XposedBridge.log("paramValueがnullです。");
return;
}
String serverId = null;
String SentUser = null;
@ -698,8 +706,7 @@ public class ReadChecker implements IHook {
String finalContent = (content != null && !content.isEmpty() && !content.equals("null"))
? content
: (!mediaDescription.isEmpty() ? mediaDescription : "No content:" + serverId);
//("セーブメゾットに渡したよ" + serverId + ", Sent_User: " + SentUser);
XposedBridge.log("セーブメゾットに渡したよ。");
saveData(SendUser, groupId, serverId, SentUser, groupName, finalContent, user_name, timeFormatted, context);
} catch (Resources.NotFoundException e) {
@ -785,9 +792,9 @@ public class ReadChecker implements IHook {
if (oldDbFile.exists()) {
boolean deleted = oldDbFile.delete();
if (deleted) {
//XposedBridge.log("Old database file lime_data.db deleted.");
XposedBridge.log("Old database file lime_data.db deleted.");
} else {
//XposedBridge.log("Failed to delete old database file lime_data.db.");
XposedBridge.log("Failed to delete old database file lime_data.db.");
}
}
File dbFile = new File(context.getFilesDir(), "lime_checked_data.db");
@ -820,8 +827,7 @@ public class ReadChecker implements IHook {
content = (content == null) ? "null" : content;
user_name = (user_name == null) ? "null" : user_name;
timeFormatted = (timeFormatted == null) ? "null" : timeFormatted;
//("セーブメゾットまで処理されたよ: serverId=" + serverId + ", Sent_User=" + SentUser);
XposedBridge.log("セーブメゾットまで処理されたよ。");
Cursor cursor = null;
try {
@ -932,7 +938,7 @@ public class ReadChecker implements IHook {
limeDatabase.endTransaction();
}
} else {
//XposedBridge.log("Record already exists, skipping insertion: server_id=" + serverId + ", Sent_User=" + SentUser);
XposedBridge.log("Record already exists, skipping insertion: server_id=" + serverId + ", Sent_User=" + SentUser);
}
if (cursor != null) {

View File

@ -1,14 +1,28 @@
package io.github.hiro.lime.hooks;
import static io.github.hiro.lime.Main.limeOptions;
import android.app.Application;
import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Environment;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
@ -17,108 +31,44 @@ import de.robv.android.xposed.callbacks.XC_LoadPackage;
import io.github.hiro.lime.LimeOptions;
public class RemoveProfileNotification implements IHook {
private static boolean isHandlingHook = false;
@Override
public void hook(LimeOptions limeOptions, XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
if (!limeOptions.RemoveNotification.checked) return;
XposedBridge.hookAllMethods(Application.class, "onCreate", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Application appContext = (Application) param.thisObject;
if (appContext == null) {
return;
}
Context moduleContext;
try {
moduleContext = appContext.createPackageContext(
"io.github.hiro.lime", Context.CONTEXT_IGNORE_SECURITY);
} catch (PackageManager.NameNotFoundException ignored) {
return;
}
File dbFile1 = appContext.getDatabasePath("naver_line");
File dbFile2 = appContext.getDatabasePath("contact");
if (dbFile1.exists() && dbFile2.exists()) {
SQLiteDatabase.OpenParams.Builder builder1 = new SQLiteDatabase.OpenParams.Builder();
builder1.addOpenFlags(SQLiteDatabase.OPEN_READWRITE);
SQLiteDatabase.OpenParams dbParams1 = builder1.build();
SQLiteDatabase.OpenParams.Builder builder2 = new SQLiteDatabase.OpenParams.Builder();
builder2.addOpenFlags(SQLiteDatabase.OPEN_READWRITE);
SQLiteDatabase.OpenParams dbParams2 = builder2.build();
SQLiteDatabase db1 = SQLiteDatabase.openDatabase(dbFile1, dbParams1);
SQLiteDatabase db2 = SQLiteDatabase.openDatabase(dbFile2, dbParams2);
RemoveProfileNotifications(loadPackageParam, appContext, db1, db2, moduleContext);
}
}
});
}
private void RemoveProfileNotifications(XC_LoadPackage.LoadPackageParam loadPackageParam, Context context, SQLiteDatabase db1, SQLiteDatabase db2, Context moduleContext) throws ClassNotFoundException {
XposedBridge.hookAllMethods(
loadPackageParam.classLoader.loadClass(Constants.RESPONSE_HOOK.className),
Constants.RESPONSE_HOOK.methodName,
XposedHelpers.findAndHookMethod(
"android.content.res.Resources",
loadPackageParam.classLoader,
"getString",
int.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (!"sync".equals(param.args[0].toString())) return;
if (isHandlingHook) {
return;
}
int resourceId = (int) param.args[0];
Resources resources = (Resources) param.thisObject;
try {
String paramValue = param.args[1].toString();
String[] operations = paramValue.split("Operation\\(");
for (String operation : operations) {
if (operation.trim().isEmpty()) continue;
isHandlingHook = true;
String type = null;
String param1 = null;
String[] parts = operation.split(",");
for (String part : parts) {
part = part.trim();
if (part.startsWith("type:")) {
type = part.substring("type:".length()).trim();
} else if (part.startsWith("param1:")) {
param1 = part.substring("param1:".length()).trim();
}
}
if ("NOTIFIED_UPDATE_PROFILE".equals(type)) {
XposedBridge.log("取得したparam1: " + param1);
Cursor cursor = db2.rawQuery("SELECT mid, contact_type, profile_updated_time_millis, profile_name FROM contacts WHERE mid=?", new String[]{param1});
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
String mid = cursor.getString(cursor.getColumnIndex("mid"));
int rowsDeleted = db2.delete("contacts", "mid=?", new String[]{mid});
}
} finally {
cursor.close();
}
}
Object operationObject = param.args[1].getClass().getDeclaredField("a").get(param.args[1]);
if (operationObject != null) {
Field operationResponseField = operationObject.getClass().getSuperclass().getDeclaredField("value_");
operationResponseField.setAccessible(true);
Object operationResponse = operationResponseField.get(operationObject);
if (operationResponse != null) {
ArrayList<?> operationList = (ArrayList<?>) operationResponse.getClass().getDeclaredField("a").get(operationResponse);
for (Object op : operationList) {
Field typeField = op.getClass().getDeclaredField("c");
typeField.setAccessible(true);
Object typeFieldValue = typeField.get(op);
if ("NOTIFIED_UPDATE_PROFILE".equals(typeFieldValue.toString())) {
typeField.set(op, typeFieldValue.getClass().getMethod("valueOf", String.class).invoke(typeFieldValue, "DUMMY"));
}
}
}
}
}
// リソースIDに基づいて文字列を取得
String resourceString = resources.getString(resourceId);
// リソースIDとその文字列をXposedのログに出力
// XposedBridge.log("Resource ID: " + resourceId + ", String: " + resourceString);
// 2131622292のリソースIDに対して空の文字列を返す
if (resourceId == 2132088628) {
param.setResult(""); // 空の文字列を返す
}
} catch (Exception e) {
XposedBridge.log("RemoveProfileNotification: 予期しないエラー - " + e.getMessage());
} finally {
isHandlingHook = false;
}
}
});
}
);
}
}
}