You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1055 lines
52 KiB
Java
1055 lines
52 KiB
Java
package name.mikanoshi.customiuizer.mods;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.app.Activity;
|
|
import android.app.AlarmManager;
|
|
import android.app.Application;
|
|
import android.app.Fragment;
|
|
import android.app.PendingIntent;
|
|
import android.content.ClipData;
|
|
import android.content.ClipboardManager;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.content.res.Resources;
|
|
import android.content.res.TypedArray;
|
|
import android.database.ContentObserver;
|
|
import android.media.AudioAttributes;
|
|
import android.media.AudioManager;
|
|
import android.media.Ringtone;
|
|
import android.media.RingtoneManager;
|
|
import android.net.Uri;
|
|
import android.os.BadParcelableException;
|
|
import android.os.Binder;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.UserHandle;
|
|
import android.preference.Preference;
|
|
import android.preference.PreferenceActivity;
|
|
import android.provider.Settings;
|
|
import android.text.Spannable;
|
|
import android.text.SpannableString;
|
|
import android.text.SpannableStringBuilder;
|
|
import android.text.TextUtils;
|
|
import android.text.style.RelativeSizeSpan;
|
|
import android.util.TypedValue;
|
|
import android.view.Gravity;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.WindowManager;
|
|
import android.widget.FrameLayout;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.TableLayout;
|
|
import android.widget.TableRow;
|
|
import android.widget.TextView;
|
|
import android.widget.Toast;
|
|
|
|
import java.lang.reflect.Field;
|
|
import java.lang.reflect.Member;
|
|
import java.lang.reflect.Method;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Locale;
|
|
import java.util.TimeZone;
|
|
|
|
import de.robv.android.xposed.XC_MethodHook;
|
|
import de.robv.android.xposed.XC_MethodReplacement;
|
|
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
|
|
import de.robv.android.xposed.XposedBridge;
|
|
import de.robv.android.xposed.XposedHelpers;
|
|
|
|
import miui.app.ActionBar;
|
|
import miui.app.AlertDialog;
|
|
|
|
import name.mikanoshi.customiuizer.MainModule;
|
|
import name.mikanoshi.customiuizer.R;
|
|
import name.mikanoshi.customiuizer.utils.Helpers;
|
|
import name.mikanoshi.customiuizer.utils.Helpers.MethodHook;
|
|
|
|
import static de.robv.android.xposed.XposedHelpers.findClass;
|
|
import static de.robv.android.xposed.XposedHelpers.findClassIfExists;
|
|
import static java.lang.System.currentTimeMillis;
|
|
|
|
public class Various {
|
|
|
|
public static PackageInfo mLastPackageInfo;
|
|
public static Object mSupportFragment = null;
|
|
public static void AppInfoHook(LoadPackageParam lpparam) {
|
|
Class<?> amaCls = XposedHelpers.findClassIfExists("com.miui.appmanager.AMAppInfomationActivity", lpparam.classLoader);
|
|
if (amaCls == null) {
|
|
Helpers.log("AppInfoHook", "Cannot find activity class!");
|
|
return;
|
|
}
|
|
|
|
boolean oldMethodFound = false;
|
|
for (Member method: amaCls.getDeclaredMethods())
|
|
if (method.getName().equals("onLoadFinished")) oldMethodFound = true;
|
|
|
|
if (findClassIfExists("androidx.fragment.app.Fragment", lpparam.classLoader) != null)
|
|
Helpers.findAndHookConstructor("androidx.fragment.app.Fragment", lpparam.classLoader, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
try {
|
|
Field piField = XposedHelpers.findFirstFieldByExactType(param.thisObject.getClass(), PackageInfo.class);
|
|
if (piField != null) mSupportFragment = param.thisObject;
|
|
} catch (Throwable ignore) {}
|
|
}
|
|
});
|
|
|
|
if (Helpers.is12() || !oldMethodFound)
|
|
Helpers.findAndHookMethod(amaCls, "onCreate", Bundle.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
Handler handler = new Handler(Looper.getMainLooper());
|
|
handler.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
final Activity act = (Activity)param.thisObject;
|
|
Object contentFrag = act.getFragmentManager().findFragmentById(android.R.id.content);
|
|
Object frag = contentFrag != null ? contentFrag : mSupportFragment;
|
|
if (frag == null) {
|
|
Helpers.log("AppInfoHook", "Unable to find fragment");
|
|
return;
|
|
}
|
|
|
|
final Resources modRes;
|
|
try {
|
|
modRes = Helpers.getModuleRes(act);
|
|
Field piField = XposedHelpers.findFirstFieldByExactType(frag.getClass(), PackageInfo.class);
|
|
mLastPackageInfo = (PackageInfo)piField.get(frag);
|
|
Method[] addPref = XposedHelpers.findMethodsByExactParameters(frag.getClass(), void.class, String.class, String.class, String.class);
|
|
if (mLastPackageInfo == null || addPref.length == 0) {
|
|
Helpers.log("AppInfoHook", "Unable to find field/class/method in SecurityCenter to hook");
|
|
return;
|
|
} else {
|
|
addPref[0].setAccessible(true);
|
|
}
|
|
addPref[0].invoke(frag, "apk_versioncode", modRes.getString(R.string.appdetails_apk_version_code), String.valueOf(mLastPackageInfo.versionCode));
|
|
addPref[0].invoke(frag, "apk_filename", modRes.getString(R.string.appdetails_apk_file), mLastPackageInfo.applicationInfo.sourceDir);
|
|
addPref[0].invoke(frag, "data_path", modRes.getString(R.string.appdetails_data_path), mLastPackageInfo.applicationInfo.dataDir);
|
|
addPref[0].invoke(frag, "app_uid", modRes.getString(R.string.appdetails_app_uid), String.valueOf(mLastPackageInfo.applicationInfo.uid));
|
|
addPref[0].invoke(frag, "target_sdk", modRes.getString(R.string.appdetails_sdk), String.valueOf(mLastPackageInfo.applicationInfo.targetSdkVersion));
|
|
handler.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
addPref[0].invoke(frag, "open_in_store", modRes.getString(R.string.appdetails_playstore), "");
|
|
addPref[0].invoke(frag, "launch_app", modRes.getString(R.string.appdetails_launch), "");
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
});
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
return;
|
|
}
|
|
|
|
XposedBridge.hookAllMethods(frag.getClass(), "onPreferenceTreeClick", new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
String key = (String)XposedHelpers.callMethod(param.args[0], "getKey");
|
|
String title = (String)XposedHelpers.callMethod(param.args[0], "getTitle");
|
|
switch (key) {
|
|
case "apk_filename":
|
|
((ClipboardManager)act.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(title, mLastPackageInfo.applicationInfo.sourceDir));
|
|
Toast.makeText(act, act.getResources().getIdentifier("app_manager_copy_pkg_to_clip", "string", act.getPackageName()), Toast.LENGTH_SHORT).show();
|
|
param.setResult(true);
|
|
break;
|
|
case "data_path":
|
|
((ClipboardManager)act.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(title, mLastPackageInfo.applicationInfo.dataDir));
|
|
Toast.makeText(act, act.getResources().getIdentifier("app_manager_copy_pkg_to_clip", "string", act.getPackageName()), Toast.LENGTH_SHORT).show();
|
|
param.setResult(true);
|
|
break;
|
|
case "open_in_store":
|
|
try {
|
|
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + mLastPackageInfo.packageName));
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
act.startActivity(launchIntent);
|
|
} catch (android.content.ActivityNotFoundException anfe) {
|
|
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + mLastPackageInfo.packageName));
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
act.startActivity(launchIntent);
|
|
}
|
|
param.setResult(true);
|
|
break;
|
|
case "launch_app":
|
|
Intent launchIntent = act.getPackageManager().getLaunchIntentForPackage(mLastPackageInfo.packageName);
|
|
if (launchIntent == null) {
|
|
Toast.makeText(act, modRes.getString(R.string.appdetails_nolaunch), Toast.LENGTH_SHORT).show();
|
|
} else {
|
|
int user = 0;
|
|
try {
|
|
int uid = act.getIntent().getIntExtra("am_app_uid", -1);
|
|
user = (int)XposedHelpers.callStaticMethod(UserHandle.class, "getUserId", uid);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
if (user != 0) try {
|
|
XposedHelpers.callMethod(act, "startActivityAsUser", launchIntent, XposedHelpers.newInstance(UserHandle.class, user));
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
} else {
|
|
act.startActivity(launchIntent);
|
|
}
|
|
}
|
|
param.setResult(true);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
else
|
|
Helpers.hookAllMethods(amaCls, "onLoadFinished", new MethodHook() {
|
|
@Override
|
|
@SuppressWarnings("deprecation")
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
final PreferenceActivity act = (PreferenceActivity)param.thisObject;
|
|
Field piField = XposedHelpers.findFirstFieldByExactType(act.getClass(), PackageInfo.class);
|
|
final PackageInfo mPackageInfo = (PackageInfo)piField.get(act);
|
|
final Resources modRes = Helpers.getModuleRes(act);
|
|
Method[] addPref = XposedHelpers.findMethodsByExactParameters(act.getClass(), void.class, String.class, String.class, String.class);
|
|
if (mPackageInfo == null || addPref.length == 0) {
|
|
Helpers.log("AppInfoHook", "Unable to find field/class/method in SecurityCenter to hook");
|
|
return;
|
|
} else {
|
|
addPref[0].setAccessible(true);
|
|
}
|
|
addPref[0].invoke(act, "apk_versioncode", modRes.getString(R.string.appdetails_apk_version_code), String.valueOf(mPackageInfo.versionCode));
|
|
addPref[0].invoke(act, "apk_filename", modRes.getString(R.string.appdetails_apk_file), mPackageInfo.applicationInfo.sourceDir);
|
|
addPref[0].invoke(act, "data_path", modRes.getString(R.string.appdetails_data_path), mPackageInfo.applicationInfo.dataDir);
|
|
addPref[0].invoke(act, "app_uid", modRes.getString(R.string.appdetails_app_uid), String.valueOf(mPackageInfo.applicationInfo.uid));
|
|
addPref[0].invoke(act, "target_sdk", modRes.getString(R.string.appdetails_sdk), String.valueOf(mPackageInfo.applicationInfo.targetSdkVersion));
|
|
addPref[0].invoke(act, "open_in_store", modRes.getString(R.string.appdetails_playstore), "");
|
|
addPref[0].invoke(act, "launch_app", modRes.getString(R.string.appdetails_launch), "");
|
|
|
|
act.findPreference("apk_filename").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
((ClipboardManager)act.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(preference.getTitle(), mPackageInfo.applicationInfo.sourceDir));
|
|
Toast.makeText(act, act.getResources().getIdentifier("app_manager_copy_pkg_to_clip", "string", act.getPackageName()), Toast.LENGTH_SHORT).show();
|
|
return true;
|
|
}
|
|
});
|
|
|
|
act.findPreference("data_path").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
((ClipboardManager)act.getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText(preference.getTitle(), mPackageInfo.applicationInfo.dataDir));
|
|
Toast.makeText(act, act.getResources().getIdentifier("app_manager_copy_pkg_to_clip", "string", act.getPackageName()), Toast.LENGTH_SHORT).show();
|
|
return true;
|
|
}
|
|
});
|
|
|
|
act.findPreference("open_in_store").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
try {
|
|
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + mPackageInfo.packageName));
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
act.startActivity(launchIntent);
|
|
} catch (android.content.ActivityNotFoundException anfe) {
|
|
Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + mPackageInfo.packageName));
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
act.startActivity(launchIntent);
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
|
|
act.findPreference("launch_app").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
|
@Override
|
|
public boolean onPreferenceClick(Preference preference) {
|
|
Intent launchIntent = act.getPackageManager().getLaunchIntentForPackage(mPackageInfo.packageName);
|
|
if (launchIntent == null) {
|
|
Toast.makeText(act, modRes.getString(R.string.appdetails_nolaunch), Toast.LENGTH_SHORT).show();
|
|
} else {
|
|
int user = 0;
|
|
try {
|
|
int uid = act.getIntent().getIntExtra("am_app_uid", -1);
|
|
user = (int)XposedHelpers.callStaticMethod(UserHandle.class, "getUserId", uid);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
|
|
launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
|
|
if (user != 0) try {
|
|
XposedHelpers.callMethod(act, "startActivityAsUser", launchIntent, XposedHelpers.newInstance(UserHandle.class, user));
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
} else {
|
|
act.startActivity(launchIntent);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
public static Bundle checkBundle(Context context, Bundle bundle) {
|
|
if (context == null) {
|
|
Helpers.log("AppsDefaultSortHook", "Context is null!");
|
|
return null;
|
|
}
|
|
if (bundle == null) bundle = new Bundle();
|
|
int order = Integer.parseInt(Helpers.getSharedStringPref(context, "pref_key_various_appsort", "0"));
|
|
bundle.putInt("current_sory_type", order); // Xiaomi noob typos :)
|
|
bundle.putInt("current_sort_type", order); // Future proof, they may fix it someday :D
|
|
return bundle;
|
|
}
|
|
|
|
public static void AppsDefaultSortHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.miui.appmanager.AppManagerMainActivity", lpparam.classLoader, "onCreate", Bundle.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
param.args[0] = checkBundle((Context)param.thisObject, (Bundle)param.args[0]);
|
|
|
|
// Bruteforce class on MIUI 12.5
|
|
if (Helpers.is125()) {
|
|
String fragCls = null;
|
|
Class<?> xfragCls = findClassIfExists("androidx.fragment.app.Fragment", lpparam.classLoader);
|
|
Field[] fields = param.thisObject.getClass().getDeclaredFields();
|
|
for (Field field: fields)
|
|
if (Fragment.class.isAssignableFrom(field.getType()) ||
|
|
(xfragCls != null && xfragCls.isAssignableFrom(field.getType()))) {
|
|
fragCls = field.getType().getCanonicalName();
|
|
break;
|
|
}
|
|
|
|
if (fragCls != null)
|
|
Helpers.hookAllMethods(fragCls, lpparam.classLoader, "onActivityCreated", new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
try {
|
|
param.args[0] = checkBundle((Context)XposedHelpers.callMethod(param.thisObject, "getContext"), (Bundle)param.args[0]);
|
|
} catch (Throwable t) {
|
|
Helpers.log("AppsDefaultSortHook", t.getMessage());
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// Helpers.findAndHookMethod("com.miui.appmanager.AppManagerMainActivity", lpparam.classLoader, "onSaveInstanceState", Bundle.class, new MethodHook() {
|
|
// @Override
|
|
// protected void after(final MethodHookParam param) throws Throwable {
|
|
// Bundle bundle = (Bundle)param.args[0];
|
|
// if (bundle == null) bundle = new Bundle();
|
|
// bundle.putInt("current_sory_type", 1); // Xiaomi noob typos :)
|
|
// bundle.putInt("current_sort_type", 1); // Future proof, they may fix it someday :D
|
|
// Helpers.log("onSaveInstanceState: " + String.valueOf(bundle));
|
|
// }
|
|
// });
|
|
}
|
|
|
|
private static void setAppState(final Activity act, String pkgName, MenuItem item, boolean enable) {
|
|
try {
|
|
PackageManager pm = act.getPackageManager();
|
|
pm.setApplicationEnabledSetting(pkgName, enable ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
|
|
int state = pm.getApplicationEnabledSetting(pkgName);
|
|
boolean isEnabledOrDefault = (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
|
|
if ((enable && isEnabledOrDefault) || (!enable && !isEnabledOrDefault)) {
|
|
item.setTitle(act.getResources().getIdentifier(enable ? "app_manager_disable_text" : "app_manager_enable_text", "string", "com.miui.securitycenter"));
|
|
Toast.makeText(act, act.getResources().getIdentifier(enable ? "app_manager_enabled" : "app_manager_disabled", "string", "com.miui.securitycenter"), Toast.LENGTH_SHORT).show();
|
|
} else {
|
|
Toast.makeText(act, Helpers.getModuleRes(act).getString(R.string.disable_app_fail), Toast.LENGTH_LONG).show();
|
|
}
|
|
new Handler().postDelayed(act::invalidateOptionsMenu, 500);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
|
|
public static void AppsDisableServiceHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.server.pm.PackageManagerServiceInjector", lpparam.classLoader, "isAllowedDisable", XC_MethodReplacement.returnConstant(true));
|
|
}
|
|
|
|
public static void AppsDisableHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.miui.appmanager.ApplicationsDetailsActivity", lpparam.classLoader, "onCreateOptionsMenu", Menu.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
Activity act = (Activity)param.thisObject;
|
|
Menu menu = (Menu)param.args[0];
|
|
MenuItem dis = menu.add(0, 666, 1, act.getResources().getIdentifier("app_manager_disable_text", "string", lpparam.packageName));
|
|
dis.setIcon(act.getResources().getIdentifier("action_button_stop", "drawable", lpparam.packageName));
|
|
dis.setEnabled(true);
|
|
dis.setShowAsAction(1);
|
|
//XposedHelpers.setAdditionalInstanceField(param.thisObject, "mDisableButton", dis);
|
|
|
|
PackageManager pm = act.getPackageManager();
|
|
Field piField = XposedHelpers.findFirstFieldByExactType(act.getClass(), PackageInfo.class);
|
|
PackageInfo mPackageInfo = (PackageInfo)piField.get(act);
|
|
ApplicationInfo appInfo = pm.getApplicationInfo(mPackageInfo.packageName, PackageManager.GET_META_DATA);
|
|
boolean isSystem = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
|
boolean isUpdatedSystem = (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
|
|
|
|
dis.setTitle(act.getResources().getIdentifier(appInfo.enabled ? "app_manager_disable_text" : "app_manager_enable_text", "string", lpparam.packageName));
|
|
|
|
if (!appInfo.enabled || (isSystem && !isUpdatedSystem)) {
|
|
MenuItem item = menu.findItem(2);
|
|
if (item != null) item.setVisible(false);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.miui.appmanager.ApplicationsDetailsActivity", lpparam.classLoader, "onOptionsItemSelected", MenuItem.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
MenuItem item = (MenuItem)param.args[0];
|
|
if (item == null || item.getItemId() != 666) return;
|
|
|
|
Activity act = (Activity)param.thisObject;
|
|
Resources modRes = Helpers.getModuleRes(act);
|
|
Field piField = XposedHelpers.findFirstFieldByExactType(act.getClass(), PackageInfo.class);
|
|
PackageInfo mPackageInfo = (PackageInfo)piField.get(act);
|
|
if ("com.android.settings".equals(mPackageInfo.packageName) || "com.google.android.packageinstaller".equals(mPackageInfo.packageName) || "com.android.packageinstaller".equals(mPackageInfo.packageName)) {
|
|
Toast.makeText(act, modRes.getString(R.string.disable_app_settings), Toast.LENGTH_SHORT).show();
|
|
return;
|
|
}
|
|
|
|
PackageManager pm = act.getPackageManager();
|
|
ApplicationInfo appInfo = pm.getApplicationInfo(mPackageInfo.packageName, PackageManager.GET_META_DATA);
|
|
boolean isSystem = (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
|
|
int state = pm.getApplicationEnabledSetting(mPackageInfo.packageName);
|
|
boolean isEnabledOrDefault = (state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
|
|
if (isEnabledOrDefault) {
|
|
if (isSystem) {
|
|
String title = modRes.getString(R.string.disable_app_title);
|
|
String text = modRes.getString(R.string.disable_app_text);
|
|
new AlertDialog.Builder(act).setTitle(title).setMessage(text).setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
|
public void onClick(DialogInterface dialog, int whichButton) {
|
|
setAppState(act, mPackageInfo.packageName, item, false);
|
|
}
|
|
}).setNegativeButton(android.R.string.cancel, null).show();
|
|
} else setAppState(act, mPackageInfo.packageName, item, false);
|
|
} else setAppState(act, mPackageInfo.packageName, item, true);
|
|
param.setResult(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void AppsRestrictHook(LoadPackageParam lpparam) {
|
|
Method[] mGetAppInfo = XposedHelpers.findMethodsByExactParameters(findClass("com.miui.appmanager.AppManageUtils", lpparam.classLoader), ApplicationInfo.class, Object.class, String.class, int.class, int.class);
|
|
if (mGetAppInfo.length == 0)
|
|
Helpers.log("AppsRestrictHook", "Cannot find getAppInfo method!");
|
|
else
|
|
Helpers.hookMethod(mGetAppInfo[0], new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
if ((int)param.args[2] == 128 && (int)param.args[3] == 0) {
|
|
ApplicationInfo appInfo = (ApplicationInfo)param.getResult();
|
|
appInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
|
|
param.setResult(appInfo);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.miui.networkassistant.ui.fragment.ShowAppDetailFragment", lpparam.classLoader, "initFirewallData", new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
Object mAppInfo = XposedHelpers.getObjectField(param.thisObject, "mAppInfo");
|
|
if (mAppInfo != null) XposedHelpers.setBooleanField(mAppInfo, "isSystemApp", false);
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllMethods("com.miui.networkassistant.service.FirewallService", lpparam.classLoader, "setSystemAppWifiRuleAllow", XC_MethodReplacement.DO_NOTHING);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public static void AppsRestrictPowerHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.miui.powerkeeper.provider.PowerKeeperConfigureManager", lpparam.classLoader, "pkgHasIcon", String.class, XC_MethodReplacement.returnConstant(true));
|
|
//Helpers.hookAllMethods("com.miui.powerkeeper.provider.PowerKeeperConfigureManager", lpparam.classLoader, "isControlApp", XC_MethodReplacement.returnConstant(true));
|
|
|
|
Helpers.findAndHookMethod("com.miui.powerkeeper.provider.PreSetGroup", lpparam.classLoader, "initGroup", new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
HashMap<String, Integer> mGroupHeadUidMap = (HashMap<String, Integer>)XposedHelpers.getStaticObjectField(findClass("com.miui.powerkeeper.provider.PreSetGroup", lpparam.classLoader), "mGroupHeadUidMap");
|
|
mGroupHeadUidMap.clear();
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.miui.powerkeeper.provider.PreSetApp", lpparam.classLoader, "isPreSetApp", String.class, XC_MethodReplacement.returnConstant(false));
|
|
Helpers.hookAllMethods("com.miui.powerkeeper.utils.Utils", lpparam.classLoader, "pkgHasIcon", XC_MethodReplacement.returnConstant(true));
|
|
}
|
|
|
|
public static void AlarmCompatHook() {
|
|
Helpers.findAndHookMethod(Settings.System.class, "getStringForUser", ContentResolver.class, String.class, int.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
ContentResolver resolver = (ContentResolver)param.args[0];
|
|
String pkgName = (String)XposedHelpers.callMethod(resolver, "getPackageName");
|
|
String key = (String)param.args[1];
|
|
if ("next_alarm_formatted".equals(key) && MainModule.mPrefs.getStringSet("various_alarmcompat_apps").contains(pkgName))
|
|
param.args[1] = "next_alarm_clock_formatted";
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void AlarmCompatServiceHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.server.AlarmManagerService", lpparam.classLoader, "onBootPhase", int.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
if ((int)param.args[0] != 500 /*PHASE_SYSTEM_SERVICES_READY*/) return;
|
|
|
|
Context mContext = (Context)XposedHelpers.callMethod(param.thisObject, "getContext");
|
|
if (mContext == null) {
|
|
Helpers.log("AlarmCompatServiceHook", "Context is NULL");
|
|
return;
|
|
}
|
|
ContentResolver resolver = mContext.getContentResolver();
|
|
ContentObserver alarmObserver = new ContentObserver(new Handler()) {
|
|
@Override
|
|
public void onChange(boolean selfChange) {
|
|
if (selfChange) return;
|
|
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mNextAlarmTime", Helpers.getNextMIUIAlarmTime(mContext));
|
|
}
|
|
};
|
|
alarmObserver.onChange(false);
|
|
resolver.registerContentObserver(Settings.System.getUriFor("next_alarm_clock_formatted"), false, alarmObserver);
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.android.server.AlarmManagerService", lpparam.classLoader, "getNextAlarmClockImpl", int.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
Context mContext = (Context)XposedHelpers.callMethod(param.thisObject, "getContext");
|
|
String pkgName = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
|
|
Object mNextAlarmTime = XposedHelpers.getAdditionalInstanceField(param.thisObject, "mNextAlarmTime");
|
|
if (mNextAlarmTime != null && MainModule.mPrefs.getStringSet("various_alarmcompat_apps").contains(pkgName))
|
|
param.setResult((long)mNextAlarmTime == 0 ? null : new AlarmManager.AlarmClockInfo((long)mNextAlarmTime, null));
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void ShowCallUIHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.incallui.InCallPresenter", lpparam.classLoader, "startUi", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
if (!(boolean)param.getResult() || !"INCOMING".equals(param.args[0].toString())) return;
|
|
try {
|
|
boolean isCarMode = (boolean)XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.android.incallui.util.Utils.CarMode", lpparam.classLoader), "isCarMode");
|
|
if (isCarMode) return;
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (MainModule.mPrefs.getStringAsInt("various_showcallui", 0) == 1)
|
|
if (Settings.Global.getInt(mContext.getContentResolver(), Helpers.modulePkg + ".foreground.fullscreen", 0) == 1) return;
|
|
|
|
XposedHelpers.callMethod(param.thisObject, "showInCall", false, false);
|
|
Object mStatusBarNotifier = XposedHelpers.getObjectField(param.thisObject, "mStatusBarNotifier");
|
|
if (mStatusBarNotifier != null) XposedHelpers.callMethod(mStatusBarNotifier, "cancelInCall");
|
|
param.setResult(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void InCallBrightnessHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.incallui.InCallActivity", lpparam.classLoader, "onCreate", Bundle.class, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Activity act = (Activity)param.thisObject;
|
|
|
|
int opt = Integer.parseInt(Helpers.getSharedStringPref(act, "pref_key_various_calluibright_type", "0"));
|
|
if (opt == 1 || opt == 2) {
|
|
Object presenter = XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.android.incallui.InCallPresenter", lpparam.classLoader), "getInstance");
|
|
if (presenter == null) {
|
|
Helpers.log("InCallBrightnessHook", "InCallPresenter is null");
|
|
return;
|
|
}
|
|
|
|
String state = String.valueOf(XposedHelpers.callMethod(presenter, "getInCallState"));
|
|
if (opt == 1 && !"INCOMING".equals(state)) return;
|
|
else if (opt == 2 && !"OUTGOING".equals(state) && !"PENDING_OUTGOING".equals(state)) return;
|
|
}
|
|
|
|
String key = "pref_key_various_calluibright_night";
|
|
boolean checkNight = Helpers.getSharedBoolPref(act, key, false);
|
|
if (checkNight) {
|
|
int start_hour = Helpers.getSharedIntPref(act, key + "_start_hour", 0);
|
|
int start_minute = Helpers.getSharedIntPref(act, key + "_start_minute", 0);
|
|
int end_hour = Helpers.getSharedIntPref(act, key + "_end_hour", 0);
|
|
int end_minute = Helpers.getSharedIntPref(act, key + "_end_minute", 0);
|
|
|
|
SimpleDateFormat formatter = new SimpleDateFormat("H:m", Locale.ENGLISH);
|
|
formatter.setTimeZone(TimeZone.getDefault());
|
|
Date start = formatter.parse(start_hour + ":" + start_minute);
|
|
Date end = formatter.parse(end_hour + ":" + end_minute);
|
|
Date now = formatter.parse(formatter.format(new Date()));
|
|
if (start == null || end == null || now == null) return;
|
|
|
|
boolean isNight = start.before(end) ? now.after(start) && now.before(end) : now.before(end) || now.after(start);
|
|
if (isNight) return;
|
|
}
|
|
|
|
WindowManager.LayoutParams params = act.getWindow().getAttributes();
|
|
int val = Helpers.getSharedIntPref(act, "pref_key_various_calluibright_val", 0);
|
|
if (val == 0) return;
|
|
params.screenBrightness = val / 100f;
|
|
act.getWindow().setAttributes(params);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void CallReminderHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.server.telecom.MiuiMissedCallNotifierImpl", lpparam.classLoader, "startRepeatReminder", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
param.setResult(null);
|
|
if ((int)XposedHelpers.callMethod(param.thisObject, "getRepeatTimes") > 0) {
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
AlarmManager alarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
|
|
int interval = Helpers.getSharedIntPref(mContext, "pref_key_various_callreminder_interval", 5);
|
|
PendingIntent repeatAlarmPendingIntent = (PendingIntent)XposedHelpers.callMethod(param.thisObject, "getRepeatAlarmPendingIntent");
|
|
alarmManager.cancel(repeatAlarmPendingIntent);
|
|
alarmManager.setExact(AlarmManager.RTC_WAKEUP, currentTimeMillis() + interval * 60 * 1000L, repeatAlarmPendingIntent);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.android.server.telecom.MiuiMissedCallNotifierImpl", lpparam.classLoader, "onRepeatReminder", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
param.setResult(null);
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
|
|
Object remindTime = XposedHelpers.callMethod(param.thisObject, "getMinAndIncreaseMissCallRemindTime", true);
|
|
int repeatTimes = remindTime == null ? -1 : (int)XposedHelpers.callMethod(param.thisObject, "getRepeatTimes") - XposedHelpers.getIntField(remindTime, "remindTimes");
|
|
if (repeatTimes >= 0) {
|
|
String uriStr = Helpers.getSharedStringPref(mContext, "pref_key_various_callreminder_sound", "");
|
|
if (!TextUtils.isEmpty(uriStr)) {
|
|
Uri uri = Uri.parse(uriStr);
|
|
Ringtone ringtone = RingtoneManager.getRingtone(mContext, uri);
|
|
if (ringtone != null) {
|
|
if (ringtone.isPlaying()) ringtone.stop();
|
|
ringtone.setAudioAttributes(new AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_NOTIFICATION).build());
|
|
ringtone.play();
|
|
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCurrentRingtone", ringtone);
|
|
}
|
|
}
|
|
|
|
Helpers.performCustomVibration(mContext,
|
|
Integer.parseInt(Helpers.getSharedStringPref(mContext, "pref_key_various_callreminder_vibration", "0")),
|
|
Helpers.getSharedStringPref(mContext, "pref_key_various_callreminder_vibration_own", "")
|
|
);
|
|
}
|
|
|
|
if (repeatTimes > 0) {
|
|
int interval = Helpers.getSharedIntPref(mContext, "pref_key_various_callreminder_interval", 5);
|
|
((AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE)).setExact(AlarmManager.RTC_WAKEUP, currentTimeMillis() + interval * 60 * 1000, (PendingIntent)XposedHelpers.callMethod(param.thisObject, "getRepeatAlarmPendingIntent"));
|
|
} else {
|
|
XposedHelpers.callMethod(param.thisObject, "cancelRepeatReminder");
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.android.server.telecom.MiuiMissedCallNotifierImpl", lpparam.classLoader, "cancelMissedCallNotification", String.class, boolean.class, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Ringtone ringtone = (Ringtone)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCurrentRingtone");
|
|
if (ringtone != null && ringtone.isPlaying()) ringtone.stop();
|
|
}
|
|
});
|
|
}
|
|
|
|
private static TextView createTitleTextView(Context context, ViewGroup.LayoutParams lp, int resId) {
|
|
TextView tv = new TextView(context);
|
|
tv.setMaxLines(1);
|
|
tv.setSingleLine(true);
|
|
tv.setGravity(Gravity.START);
|
|
tv.setLayoutParams(lp);
|
|
tv.setTextAppearance(resId != -1 ? resId : android.R.style.TextAppearance_DeviceDefault);
|
|
return tv;
|
|
}
|
|
|
|
private static TextView createValueTextView(Context context, ViewGroup.LayoutParams lp, int resId, int gravity) {
|
|
TextView tv = new TextView(context);
|
|
tv.setMaxLines(1);
|
|
tv.setSingleLine(true);
|
|
tv.setGravity(gravity);
|
|
tv.setEllipsize(TextUtils.TruncateAt.START);
|
|
tv.setLayoutParams(lp);
|
|
tv.setTextAppearance(resId != -1 ? resId : android.R.style.TextAppearance_DeviceDefault);
|
|
return tv;
|
|
}
|
|
|
|
public static void AppInfoDuringInstallHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.packageinstaller.PackageInstallerActivity", lpparam.classLoader, "startInstallConfirm", new MethodHook() {
|
|
@Override
|
|
@SuppressLint("SetTextI18n")
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Activity act = (Activity)param.thisObject;
|
|
PackageInfo mPkgInfo = (PackageInfo)XposedHelpers.getObjectField(param.thisObject, "mPkgInfo");
|
|
if (mPkgInfo == null) return;
|
|
|
|
float density = act.getResources().getDisplayMetrics().density;
|
|
|
|
TypedArray a = act.obtainStyledAttributes(new int[]{android.R.attr.textAppearance});
|
|
int resId = a.getResourceId(0, -1);
|
|
a.recycle();
|
|
|
|
PackageInfo mAppInfo = null;
|
|
try {
|
|
PackageManager mPm = (PackageManager)XposedHelpers.getObjectField(param.thisObject, "mPm");
|
|
mAppInfo = mPm.getPackageInfo(mPkgInfo.packageName, 0);
|
|
} catch (Throwable ignore) {}
|
|
|
|
Resources modRes = Helpers.getModuleRes(act);
|
|
|
|
LinearLayout container = new LinearLayout(act);
|
|
LinearLayout.LayoutParams lpCont = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
lpCont.setMargins(Math.round(16.0f * density), Math.round(8.0f * density), Math.round(16.0f * density), Math.round(4.0f * density));
|
|
container.setLayoutParams(lpCont);
|
|
container.setOrientation(LinearLayout.VERTICAL);
|
|
|
|
LinearLayout name = new LinearLayout(act);
|
|
name.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
|
|
name.setOrientation(LinearLayout.HORIZONTAL);
|
|
|
|
LinearLayout.LayoutParams lpInfoTitle = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
lpInfoTitle.setMargins(0, 0, Math.round(20.0f * density), 0);
|
|
TextView infoTitle = createTitleTextView(act, lpInfoTitle, resId);
|
|
infoTitle.setText(modRes.getString(R.string.various_installappinfo_package));
|
|
LinearLayout.LayoutParams lpInfo = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
lpInfo.weight = 1;
|
|
TextView info = createValueTextView(act, lpInfo, resId, Gravity.END);
|
|
info.setText(mPkgInfo.applicationInfo.packageName);
|
|
|
|
name.addView(infoTitle);
|
|
name.addView(info);
|
|
|
|
TableLayout table = new TableLayout(act);
|
|
LinearLayout.LayoutParams lpTable = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
table.setLayoutParams(lpTable);
|
|
table.setColumnStretchable(0, false);
|
|
table.setColumnStretchable(1, true);
|
|
table.setColumnStretchable(2, false);
|
|
table.setColumnShrinkable(0, false);
|
|
table.setColumnShrinkable(1, true);
|
|
table.setColumnShrinkable(2, false);
|
|
|
|
TableLayout.LayoutParams lpRow = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT);
|
|
lpRow.gravity = Gravity.BOTTOM;
|
|
TableRow row1 = new TableRow(act); row1.setLayoutParams(lpRow);
|
|
TableRow row2 = new TableRow(act); row2.setLayoutParams(lpRow);
|
|
TableRow row3 = new TableRow(act); row3.setLayoutParams(lpRow);
|
|
|
|
TableRow.LayoutParams lp0 = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
|
|
lp0.column = 0;
|
|
lp0.setMargins(0, 0, Math.round(20.0f * density), 0);
|
|
TableRow.LayoutParams lp1 = new TableRow.LayoutParams(0, TableRow.LayoutParams.MATCH_PARENT);
|
|
lp1.column = 1;
|
|
lp1.weight = 1;
|
|
FrameLayout.LayoutParams lp2 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
|
|
lp2.gravity = Gravity.BOTTOM | Gravity.END;
|
|
lp2.setMargins(0, 0, Math.round(20.0f * density), 0);
|
|
TableRow.LayoutParams lp3 = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
|
|
lp3.column = 2;
|
|
|
|
TextView infoTitle1 = createTitleTextView(act, lp0, resId);
|
|
infoTitle1.setText(modRes.getString(R.string.various_installappinfo_vername));
|
|
TextView infoTitle2 = createTitleTextView(act, lp0, resId);
|
|
infoTitle2.setText(modRes.getString(R.string.various_installappinfo_vercode));
|
|
TextView infoTitle3 = createTitleTextView(act, lp0, resId);
|
|
infoTitle3.setText(modRes.getString(R.string.various_installappinfo_sdk));
|
|
|
|
FrameLayout dummy1 = new FrameLayout(act); dummy1.setLayoutParams(lp1);
|
|
FrameLayout dummy2 = new FrameLayout(act); dummy2.setLayoutParams(lp1);
|
|
FrameLayout dummy3 = new FrameLayout(act); dummy3.setLayoutParams(lp1);
|
|
|
|
String current = modRes.getString(R.string.various_installappinfo_current);
|
|
|
|
TextView info1current = createValueTextView(act, lp2, resId, Gravity.START);
|
|
if (mAppInfo != null) {
|
|
SpannableString span = new SpannableString(current + " " + mAppInfo.versionName);
|
|
span.setSpan(new RelativeSizeSpan(0.7f), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
info1current.setText(span);
|
|
} else info1current.setText(" ");
|
|
|
|
TextView info2current = createValueTextView(act, lp2, resId, Gravity.START);
|
|
if (mAppInfo != null) {
|
|
SpannableString span = new SpannableString(current + " " + mAppInfo.versionCode);
|
|
span.setSpan(new RelativeSizeSpan(0.7f), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
info2current.setText(span);
|
|
} else info2current.setText(" ");
|
|
|
|
TextView info3current = createValueTextView(act, lp2, resId, Gravity.START);
|
|
if (mAppInfo != null) {
|
|
SpannableString span = new SpannableString(current + " " + mAppInfo.applicationInfo.minSdkVersion + "-" + mAppInfo.applicationInfo.targetSdkVersion);
|
|
span.setSpan(new RelativeSizeSpan(0.7f), 0, span.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
info3current.setText(span);
|
|
} else info3current.setText(" ");
|
|
|
|
TextView info1 = createValueTextView(act, lp3, resId, Gravity.END);
|
|
info1.setText(mPkgInfo.versionName);
|
|
TextView info2 = createValueTextView(act, lp3, resId, Gravity.END);
|
|
info2.setText(String.valueOf(mPkgInfo.versionCode));
|
|
TextView info3 = createValueTextView(act, lp3, resId, Gravity.END);
|
|
info3.setText(mPkgInfo.applicationInfo.minSdkVersion + "-" + mPkgInfo.applicationInfo.targetSdkVersion);
|
|
|
|
row1.addView(infoTitle1);
|
|
row2.addView(infoTitle2);
|
|
row3.addView(infoTitle3);
|
|
|
|
row1.addView(dummy1); dummy1.addView(info1current);
|
|
row2.addView(dummy2); dummy2.addView(info2current);
|
|
row3.addView(dummy3); dummy3.addView(info3current);
|
|
|
|
row1.addView(info1);
|
|
row2.addView(info2);
|
|
row3.addView(info3);
|
|
|
|
table.addView(row1);
|
|
table.addView(row2);
|
|
table.addView(row3);
|
|
|
|
container.addView(name);
|
|
container.addView(table);
|
|
|
|
boolean isDialog = false;
|
|
try { isDialog = "com.android.internal.app.AlertActivity".equals(act.getClass().getSuperclass().getCanonicalName()); } catch (Throwable ignore) {}
|
|
ViewGroup parent = (ViewGroup)act.findViewById(act.getResources().getIdentifier("install_confirm_question", "id", "com.android.packageinstaller")).getParent();
|
|
if (parent.getChildCount() == 1) parent = ((ViewGroup)parent.getParent());
|
|
if (!isDialog) {
|
|
parent.addView(container, parent.getChildCount() - 1);
|
|
} else {
|
|
ViewGroup fParent = parent;
|
|
parent.post(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (fParent.getMeasuredHeight() == 0)
|
|
fParent.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
|
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)container.getLayoutParams();
|
|
lp.topMargin += fParent.getMeasuredHeight();
|
|
lp.leftMargin = 0;
|
|
lp.rightMargin = 0;
|
|
container.setLayoutParams(lp);
|
|
fParent.addView(container, fParent.getChildCount() - 1);
|
|
} catch (Throwable ignore) {}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void AppInfoDuringMiuiInstallHook(LoadPackageParam lpparam) {
|
|
Method[] methods = XposedHelpers.findMethodsByExactParameters(findClass("com.android.packageinstaller.PackageInstallerActivity", lpparam.classLoader), void.class, String.class);
|
|
if (methods.length == 0) {
|
|
Helpers.log("AppInfoDuringMiuiInstallHook", "Cannot find appropriate method");
|
|
return;
|
|
}
|
|
for (Method method: methods)
|
|
Helpers.hookMethod(method, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Activity act = (Activity)param.thisObject;
|
|
TextView version = act.findViewById(act.getResources().getIdentifier("install_version", "id", lpparam.packageName));
|
|
Field fPkgInfo = XposedHelpers.findFirstFieldByExactType(param.thisObject.getClass(), PackageInfo.class);
|
|
PackageInfo mPkgInfo = (PackageInfo)fPkgInfo.get(param.thisObject);
|
|
if (version == null || mPkgInfo == null) return;
|
|
|
|
TextView source = act.findViewById(act.getResources().getIdentifier("install_source", "id", lpparam.packageName));
|
|
source.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
source.setText(mPkgInfo.packageName);
|
|
|
|
PackageInfo mAppInfo = null;
|
|
try {
|
|
mAppInfo = act.getPackageManager().getPackageInfo(mPkgInfo.packageName, 0);
|
|
} catch (Throwable ignore) {}
|
|
|
|
//String size = "";
|
|
//String[] texts = version.getText().toString().split("\\|");
|
|
//if (texts.length >= 2) size = texts[1].trim();
|
|
|
|
Resources modRes = Helpers.getModuleRes(act);
|
|
|
|
SpannableStringBuilder builder = new SpannableStringBuilder();
|
|
//if (!TextUtils.isEmpty(size)) builder.append(size).append("\n");
|
|
builder.append(modRes.getString(R.string.various_installappinfo_vername)).append(":\t\t");
|
|
if (mAppInfo != null) builder.append(mAppInfo.versionName).append(" ➟ ");
|
|
builder.append(mPkgInfo.versionName).append("\n");
|
|
builder.append(modRes.getString(R.string.various_installappinfo_vercode)).append(":\t\t");
|
|
if (mAppInfo != null) builder.append(String.valueOf(mAppInfo.versionCode)).append(" ➟ ");
|
|
builder.append(String.valueOf(mPkgInfo.versionCode)).append("\n");
|
|
builder.append(modRes.getString(R.string.various_installappinfo_sdk)).append(":\t\t");
|
|
if (mAppInfo != null) builder.append(String.valueOf(mAppInfo.applicationInfo.minSdkVersion)).append("-").append(String.valueOf(mAppInfo.applicationInfo.targetSdkVersion)).append(" ➟ ");
|
|
builder.append(String.valueOf(mPkgInfo.applicationInfo.minSdkVersion)).append("-").append(String.valueOf(mPkgInfo.applicationInfo.targetSdkVersion));
|
|
|
|
version.setGravity(Gravity.CENTER_HORIZONTAL);
|
|
version.setSingleLine(false);
|
|
version.setMaxLines(10);
|
|
version.setText(builder);
|
|
version.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13.09f);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void MiuiPackageInstallerServiceHook(LoadPackageParam lpparam) {
|
|
MethodHook hook = new MethodHook() {
|
|
@Override
|
|
@SuppressWarnings({"unchecked", "ConstantConditions"})
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
try {
|
|
if (param.args[0] == null) return;
|
|
Intent origIntent = (Intent)param.args[0];
|
|
Intent intent = (Intent)origIntent.clone();
|
|
String action = intent.getAction();
|
|
if (!Intent.ACTION_INSTALL_PACKAGE.equals(action)) return;
|
|
//XposedBridge.log(intent.getPackage() + ": " + intent.getType() + " | " + intent.getDataString());
|
|
boolean res = false;
|
|
try {
|
|
res = XposedHelpers.callMethod(param.thisObject, "getPackageInfo", "com.miui.packageinstaller", 0, 0) != null;
|
|
} catch (Throwable e) {}
|
|
if (!res) return;
|
|
|
|
List<ResolveInfo> resolved = new ArrayList<ResolveInfo>((List<ResolveInfo>)param.getResult());
|
|
ResolveInfo resolveInfo;
|
|
Iterator<ResolveInfo> itr = resolved.iterator();
|
|
while (itr.hasNext()) {
|
|
resolveInfo = itr.next();
|
|
if (resolveInfo.activityInfo != null && !"com.miui.packageinstaller".equals(resolveInfo.activityInfo.packageName)) itr.remove();
|
|
}
|
|
|
|
if (resolved.size() > 0) param.setResult(resolved);
|
|
} catch (Throwable t) {
|
|
if (!(t instanceof BadParcelableException)) XposedBridge.log(t);
|
|
}
|
|
}
|
|
};
|
|
|
|
if (!Helpers.findAndHookMethodSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "queryIntentActivitiesInternal", Intent.class, String.class, int.class, int.class, int.class, boolean.class, boolean.class, hook))
|
|
Helpers.findAndHookMethod("com.android.server.pm.PackageManagerService", lpparam.classLoader, "queryIntentActivitiesInternal", Intent.class, String.class, int.class, int.class, hook);
|
|
}
|
|
|
|
public static void MiuiPackageInstallerHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.packageinstaller.PackageInstallerActivity", lpparam.classLoader, "onCreate", Bundle.class, new MethodHook() {
|
|
@Override
|
|
@SuppressWarnings("unchecked")
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
Activity act = (Activity)param.thisObject;
|
|
List<ApplicationInfo> packs = act.getPackageManager().getInstalledApplications(PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DISABLED_COMPONENTS);
|
|
for (Field field: param.thisObject.getClass().getDeclaredFields())
|
|
if (field.getType() == List.class) {
|
|
field.setAccessible(true);
|
|
ArrayList<String> whiteList = (ArrayList<String>)field.get(param.thisObject);
|
|
if (whiteList == null || whiteList.size() <= 1) continue;
|
|
for (ApplicationInfo pack: packs)
|
|
if (!whiteList.contains(pack.packageName)) whiteList.add(pack.packageName);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static final HashSet<String> miuiApps = new HashSet<String>(Arrays.asList(
|
|
"com.android.camera",
|
|
"com.android.soundrecorder",
|
|
"com.android.cellbroadcastreceiver",
|
|
"com.android.providers.downloads.ui"
|
|
//"com.android.stk" ???
|
|
));
|
|
|
|
public static void CollapseMIUITitlesHook(LoadPackageParam lpparam, XC_MethodHook.MethodHookParam param, int opt) {
|
|
Application app = (Application)param.thisObject;
|
|
String pkgName = app.getPackageName();
|
|
|
|
boolean isMIUIapp = pkgName.startsWith("com.miui") || pkgName.startsWith("com.xiaomi") || miuiApps.contains(pkgName);
|
|
if (!isMIUIapp) isMIUIapp = app.checkSelfPermission("miui.permission.USE_INTERNAL_GENERAL_API") == PackageManager.PERMISSION_GRANTED;
|
|
if (!isMIUIapp) return;
|
|
|
|
Class<?> abvCls = XposedHelpers.findClassIfExists("com.miui.internal.widget.AbsActionBarView", lpparam.classLoader);
|
|
if (abvCls != null)
|
|
Helpers.hookAllConstructors(abvCls, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
XposedHelpers.setIntField(param.thisObject, "mExpandState", ActionBar.STATE_COLLAPSE);
|
|
XposedHelpers.setIntField(param.thisObject, "mInnerExpandState", ActionBar.STATE_COLLAPSE);
|
|
if (opt == 3) XposedHelpers.setBooleanField(param.thisObject, "mResizable", false);
|
|
}
|
|
});
|
|
|
|
abvCls = XposedHelpers.findClassIfExists("miuix.appcompat.internal.app.widget.ActionBarView", lpparam.classLoader);
|
|
if (abvCls != null)
|
|
Helpers.hookAllConstructors(abvCls, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
try {
|
|
XposedHelpers.callMethod(param.thisObject, "setExpandState", ActionBar.STATE_COLLAPSE);
|
|
if (opt == 3) XposedHelpers.callMethod(param.thisObject, "setResizable", false);
|
|
} catch (Throwable ignore) {
|
|
XposedBridge.log(ignore);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void GboardPaddingHook() {
|
|
Helpers.findAndHookMethod(findClass("android.os.SystemProperties", null), "get", String.class, new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
String key = (String)param.args[0];
|
|
if (key.equals("ro.com.google.ime.kb_pad_port_b")) {
|
|
int opt = MainModule.mPrefs.getInt("various_gboardpadding_port", 0);
|
|
if (opt > 0) param.setResult(String.valueOf(opt));
|
|
} else if (key.equals("ro.com.google.ime.kb_pad_land_b")) {
|
|
int opt = MainModule.mPrefs.getInt("various_gboardpadding_land", 0);
|
|
if (opt > 0) param.setResult(String.valueOf(opt));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void ScreenRecorderFramerateHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.miui.screenrecorder.config.ScreenRecorderConfig", lpparam.classLoader, "setFramesValue", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
param.args[0] = 90;
|
|
}
|
|
});
|
|
}
|
|
|
|
// public static void LargeCallerPhotoHook(LoadPackageParam lpparam) {
|
|
// Helpers.findAndHookMethod("com.android.incallui.CallCardFragment", lpparam.classLoader, "setCallCardImage", Drawable.class, boolean.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(final MethodHookParam param) throws Throwable {
|
|
// param.args[1] = true;
|
|
// }
|
|
// });
|
|
//
|
|
// Helpers.findAndHookMethod("com.android.incallui.CallCardFragment", lpparam.classLoader, "showBigAvatar", boolean.class, Drawable.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(final MethodHookParam param) throws Throwable {
|
|
// //Helpers.log("showBigAvatar: " + String.valueOf(param.args[0]) + " | " + String.valueOf(param.args[1]));
|
|
// if (param.args[1] == null)
|
|
// param.setResult(null);
|
|
// else
|
|
// param.args[0] = true;
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
} |