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.
CustoMIUIzer/app/src/main/java/name/mikanoshi/customiuizer/mods/System.java

7965 lines
391 KiB
Java

package name.mikanoshi.customiuizer.mods;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.Dialog;
import android.app.KeyguardManager;
import android.app.MiuiNotification;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetProviderInfo;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.usb.UsbManager;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.MediaMetadata;
import android.media.MediaPlayer;
import android.media.SoundPool;
import android.media.session.MediaController;
import android.media.session.PlaybackState;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.TrafficStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.BadParcelableException;
import android.os.BatteryManager;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.text.Layout;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.TypefaceSpan;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Magnifier;
import android.widget.RelativeLayout;
import android.widget.RemoteViews;
import android.widget.ScrollView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.NetworkInterface;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
import static java.lang.System.currentTimeMillis;
import static java.lang.System.nanoTime;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import de.robv.android.xposed.callbacks.XCallback;
import de.robv.android.xposed.XC_MethodHook.MethodHookParam;
import de.robv.android.xposed.XC_MethodReplacement;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import static de.robv.android.xposed.XposedHelpers.findClass;
import static de.robv.android.xposed.XposedHelpers.findClassIfExists;
import static de.robv.android.xposed.XposedHelpers.findMethodExactIfExists;
import miui.os.SystemProperties;
import name.mikanoshi.customiuizer.MainModule;
import name.mikanoshi.customiuizer.R;
import name.mikanoshi.customiuizer.utils.AudioVisualizer;
import name.mikanoshi.customiuizer.utils.BatteryIndicator;
import name.mikanoshi.customiuizer.utils.Helpers;
import name.mikanoshi.customiuizer.utils.Helpers.MethodHook;
import name.mikanoshi.customiuizer.utils.Helpers.MimeType;
import name.mikanoshi.customiuizer.utils.SoundData;
import static name.mikanoshi.customiuizer.mods.GlobalActions.ACTION_PREFIX;
import org.json.JSONObject;
public class System {
public static void ScreenAnimHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.display.DisplayPowerController", lpparam.classLoader, "initialize", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
try {
XposedHelpers.setObjectField(param.thisObject, "mColorFadeEnabled", true);
XposedHelpers.setObjectField(param.thisObject, "mColorFadeFadesConfig", true);
} catch (Throwable ignore) {}
}
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
//ObjectAnimator mColorFadeOnAnimator = (ObjectAnimator)XposedHelpers.getObjectField(param.thisObject, "mColorFadeOnAnimator");
//mColorFadeOnAnimator.setDuration(250);
ObjectAnimator mColorFadeOffAnimator = (ObjectAnimator)XposedHelpers.getObjectField(param.thisObject, "mColorFadeOffAnimator");
//mColorFadeOffAnimator.setDuration(Helpers.getSharedIntPref(mContext, "pref_key_system_screenanim_duration", 0));
if (mColorFadeOffAnimator != null) {
int val = MainModule.mPrefs.getInt("system_screenanim_duration", 0);
if (val == 0) val = 250;
mColorFadeOffAnimator.setDuration(val);
}
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_screenanim_duration", 0) {
@Override
public void onChange(String name, int defValue) {
if (mColorFadeOffAnimator == null) return;
int val = Helpers.getSharedIntPref(mContext, name, defValue);
if (val == 0) val = 250;
mColorFadeOffAnimator.setDuration(val);
}
};
}
});
}
public static void NoLightUpOnChargeHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.power.PowerManagerService", lpparam.classLoader, "wakeUpNoUpdateLocked", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
String reason = param.args[1] instanceof String ? (String)param.args[1] : (String)param.args[2];
if (reason == null) return;
if (Integer.parseInt(MainModule.mPrefs.getString("system_nolightuponcharges", "1")) == 3 &&
(reason.equals("android.server.power:POWER") || reason.startsWith("android.server.power:PLUGGED"))) {
param.setResult(false);
return;
}
if (Integer.parseInt(MainModule.mPrefs.getString("system_nolightuponcharges", "1")) == 2 && (
reason.equals("android.server.power:POWER") ||
reason.startsWith("android.server.power:PLUGGED") ||
reason.equals("com.android.systemui:RAPID_CHARGE") ||
reason.equals("com.android.systemui:WIRELESS_CHARGE") ||
reason.equals("com.android.systemui:WIRELESS_RAPID_CHARGE")
)) param.setResult(false);
//Helpers.log("wakeUpNoUpdateLocked: " + param.args[0] + " | " + param.args[1] + " | " + param.args[2] + " | " + param.args[3] + " | " + param.args[4]);
}
});
}
public static void NoLightUpOnHeadsetHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.power.PowerManagerService", lpparam.classLoader, "wakeUpNoUpdateLocked", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
String reason = param.args[1] instanceof String ? (String)param.args[1] : (String)param.args[2];
if ("com.android.systemui:HEADSET".equals(reason)) param.setResult(false);
}
});
}
public static void ScramblePINHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.keyguard.KeyguardPINView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View[][] mViews = (View[][])XposedHelpers.getObjectField(param.thisObject, "mViews");
ArrayList<View> mRandomViews = new ArrayList<View>();
for (int row = 1; row <= 4; row++)
for (int col = 0; col <= 2; col++)
if (mViews[row][col] != null)
mRandomViews.add(mViews[row][col]);
Collections.shuffle(mRandomViews);
View pinview = (View)param.thisObject;
ViewGroup row1 = pinview.findViewById(pinview.getResources().getIdentifier("row1", "id", "com.android.systemui"));
ViewGroup row2 = pinview.findViewById(pinview.getResources().getIdentifier("row2", "id", "com.android.systemui"));
ViewGroup row3 = pinview.findViewById(pinview.getResources().getIdentifier("row3", "id", "com.android.systemui"));
ViewGroup row4 = pinview.findViewById(pinview.getResources().getIdentifier("row4", "id", "com.android.systemui"));
row1.removeAllViews();
row2.removeAllViews();
row3.removeAllViews();
row4.removeAllViews();
mViews[1] = new View[]{ mRandomViews.get(0), mRandomViews.get(1), mRandomViews.get(2)};
row1.addView(mRandomViews.get(0));
row1.addView(mRandomViews.get(1));
row1.addView(mRandomViews.get(2));
mViews[2] = new View[]{ mRandomViews.get(3), mRandomViews.get(4), mRandomViews.get(5)};
row2.addView(mRandomViews.get(3));
row2.addView(mRandomViews.get(4));
row2.addView(mRandomViews.get(5));
mViews[3] = new View[]{ mRandomViews.get(6), mRandomViews.get(7), mRandomViews.get(8)};
row3.addView(mRandomViews.get(6));
row3.addView(mRandomViews.get(7));
row3.addView(mRandomViews.get(8));
mViews[4] = new View[]{ null, mRandomViews.get(9), null};
row4.addView(mRandomViews.get(9));
XposedHelpers.setObjectField(param.thisObject, "mViews", mViews);
}
});
}
public static void NoPasswordHook() {
String isAllowed = Helpers.isQPlus() ? "isBiometricAllowedForUser" : "isFingerprintAllowedForUser";
//Helpers.findAndHookMethod("com.android.internal.widget.LockPatternUtils$StrongAuthTracker", null, "handleStrongAuthRequiredChanged", int.class, int.class, XC_MethodReplacement.DO_NOTHING);
Helpers.findAndHookMethod("com.android.internal.widget.LockPatternUtils$StrongAuthTracker", null, isAllowed, int.class, XC_MethodReplacement.returnConstant(true));
Helpers.findAndHookMethod("com.android.internal.widget.LockPatternUtils", null, isAllowed, int.class, XC_MethodReplacement.returnConstant(true));
}
// public static void NoPasswordKeyguardHook(LoadPackageParam lpparam) {
// Helpers.findAndHookMethod("com.android.keyguard.KeyguardUpdateMonitor$StrongAuthTracker", lpparam.classLoader, "isUnlockingWithFingerprintAllowed", XC_MethodReplacement.returnConstant(true));
// Helpers.findAndHookMethod("com.android.keyguard.KeyguardUpdateMonitor$StrongAuthTracker", lpparam.classLoader, "isUnlockingWithFingerprintAllowed", int.class, XC_MethodReplacement.returnConstant(true));
// Helpers.findAndHookMethod("com.android.keyguard.KeyguardUpdateMonitor", lpparam.classLoader, "isUnlockWithFingerprintPossible", int.class, XC_MethodReplacement.returnConstant(true));
// }
public static void EnhancedSecurityHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "interceptPowerKeyDown", KeyEvent.class, boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mPWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
KeyguardManager kgMgr = (KeyguardManager)mPWMContext.getSystemService(Context.KEYGUARD_SERVICE);
if (kgMgr.isKeyguardLocked() && kgMgr.isKeyguardSecure()) {
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
if (mHandler != null) {
Runnable mEndCallLongPress = (Runnable)XposedHelpers.getObjectField(param.thisObject, "mEndCallLongPress");
if (mEndCallLongPress != null) mHandler.removeCallbacks(mEndCallLongPress);
}
}
}
});
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "powerLongPress", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mPWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
KeyguardManager kgMgr = (KeyguardManager)mPWMContext.getSystemService(Context.KEYGUARD_SERVICE);
if (kgMgr.isKeyguardLocked() && kgMgr.isKeyguardSecure()) param.setResult(null);
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "showGlobalActions", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mPWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
KeyguardManager kgMgr = (KeyguardManager)mPWMContext.getSystemService(Context.KEYGUARD_SERVICE);
if (kgMgr.isKeyguardLocked() && kgMgr.isKeyguardSecure()) param.setResult(null);
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "showGlobalActionsInternal", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mPWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
KeyguardManager kgMgr = (KeyguardManager)mPWMContext.getSystemService(Context.KEYGUARD_SERVICE);
if (kgMgr.isKeyguardLocked() && kgMgr.isKeyguardSecure()) param.setResult(null);
}
});
}
@SuppressWarnings("RedundantIfStatement")
private static boolean isAuthOnce() {
int req = MainModule.mPrefs.getStringAsInt("system_noscreenlock_req", 1);
if (req <= 1) return true;
if (req == 2 && !isUnlockedWithFingerprint && !isUnlockedWithStrong) return false;
if (req == 3 && !isUnlockedWithStrong) return false;
return true;
}
private static boolean isTrusted(Context mContext, ClassLoader classLoader) {
return isTrustedWiFi(mContext) || isTrustedBt(classLoader);
}
private static boolean isTrustedWiFi(Context mContext) {
WifiManager wifiManager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
if (wifiManager == null) return false;
if (!wifiManager.isWifiEnabled()) return false;
Set<String> trustedNetworks = MainModule.mPrefs.getStringSet("system_noscreenlock_wifi");
return Helpers.containsStringPair(trustedNetworks, wifiManager.getConnectionInfo().getBSSID());
}
private static boolean isTrustedBt(ClassLoader classLoader) {
try {
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()) return false;
Set<String> trustedDevices = MainModule.mPrefs.getStringSet("system_noscreenlock_bt");
Object mController = XposedHelpers.callStaticMethod(findClass("com.android.systemui.Dependency", classLoader), "get", findClass("com.android.systemui.statusbar.policy.BluetoothController", classLoader));
Collection<?> cachedDevices = (Collection<?>)XposedHelpers.callMethod(mController, "getCachedDevicesCopy");
if (cachedDevices != null)
for (Object device: cachedDevices) {
BluetoothDevice mDevice = (BluetoothDevice)XposedHelpers.getObjectField(device, "mDevice");
if (mDevice == null) continue;
if (mDevice.getBondState() == BluetoothDevice.BOND_BONDED &&
(boolean)XposedHelpers.callMethod(device, "isConnected") &&
Helpers.containsStringPair(trustedDevices, mDevice.getAddress())) return true;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
return false;
}
private static boolean isUnlocked(Context mContext, ClassLoader classLoader) {
Class<?> kmvClas = findClass("com.android.systemui.keyguard.KeyguardViewMediator", classLoader);
XposedHelpers.setAdditionalStaticField(kmvClas, "isScreenLockDisabled", false);
if (!isAuthOnce()) return false;
int opt = MainModule.mPrefs.getStringAsInt("system_noscreenlock", 1);
if (forcedOption == 1) opt = 2;
boolean isTrusted = false;
if (opt == 3) isTrusted = isTrusted(mContext, classLoader);
if (opt == 2 || opt == 3 && isTrusted) {
XposedHelpers.setAdditionalStaticField(kmvClas, "isScreenLockDisabled", true);
return true;
} else return false;
}
private static void checkBTConnections(Context mContext) {
if (mContext == null)
Helpers.log("checkBTConnections", "mContext is NULL!");
else
mContext.sendBroadcast(new Intent(ACTION_PREFIX + "UnlockBTConnection"));
}
// private static void setLockScreenDisabled(ClassLoader classLoader, Object thisObject, boolean state) {
// try {
// Class kumCls = findClass("com.android.keyguard.KeyguardUpdateMonitor", classLoader);
// int user = (int)XposedHelpers.callStaticMethod(kumCls, "getCurrentUser");
// Object mLockPatternUtils = XposedHelpers.getObjectField(thisObject, "mLockPatternUtils");
// XposedHelpers.callMethod(mLockPatternUtils, "setLockScreenDisabled", state, user);
// Helpers.log("setLockScreenDisabled = " + state + ", " + user);
// } catch (Throwable t) {
// XposedBridge.log(t);
// }
// }
private static boolean isUnlockedInnerCall = false;
private static boolean isUnlockedWithFingerprint = false;
private static boolean isUnlockedWithStrong = false;
private static int forcedOption = -1;
public static void NoScreenLockHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.keyguard.KeyguardUpdateMonitor", lpparam.classLoader, "reportSuccessfulStrongAuthUnlockAttempt", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (isUnlockedInnerCall) {
isUnlockedInnerCall = false;
return;
}
isUnlockedWithStrong = true;
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardUpdateMonitorCallback", lpparam.classLoader, "onFingerprintAuthenticated", int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
isUnlockedWithFingerprint = true;
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardHostView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
Object mSecurityContainer = XposedHelpers.getObjectField(param.thisObject, "mSecurityContainer");
Object mCallback = XposedHelpers.getObjectField(mSecurityContainer, "mCallback");
XposedHelpers.callMethod(mCallback, "reportUnlockAttempt", 0, true, 0);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, new IntentFilter(ACTION_PREFIX + "UnlockStrongAuth"));
}
});
Helpers.findAndHookMethod("com.android.systemui.keyguard.KeyguardViewMediator", lpparam.classLoader, "doKeyguardLocked", Bundle.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (forcedOption == 0) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (!isUnlocked(mContext, lpparam.classLoader)) return;
boolean skip = MainModule.mPrefs.getBoolean("system_noscreenlock_skip");
if (skip) {
param.setResult(null);
XposedHelpers.callMethod(param.thisObject, "keyguardDone");
}
isUnlockedInnerCall = true;
XposedHelpers.callMethod(XposedHelpers.getObjectField(param.thisObject, "mUpdateMonitor"), "reportSuccessfulStrongAuthUnlockAttempt");
Intent unlockIntent = new Intent(ACTION_PREFIX + "UnlockStrongAuth");
mContext.sendBroadcast(unlockIntent);
}
});
Helpers.findAndHookMethod("com.android.systemui.keyguard.KeyguardViewMediator", lpparam.classLoader, "setupLocked", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
IntentFilter filter = new IntentFilter();
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(ACTION_PREFIX + "UnlockSetForced");
filter.addAction(ACTION_PREFIX + "UnlockBTConnection");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_PREFIX + "UnlockSetForced"))
forcedOption = intent.getIntExtra("system_noscreenlock_force", -1);
boolean isShowing = (boolean)XposedHelpers.callMethod(param.thisObject, "isShowing");
if (!isShowing) return;
if (!isAuthOnce()) return;
boolean isTrusted = false;
if (forcedOption == 0) isTrusted = false;
else if (forcedOption == 1) isTrusted = true;
else if (MainModule.mPrefs.getStringAsInt("system_noscreenlock", 1) == 3)
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo netInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if (netInfo.getState() != NetworkInfo.State.CONNECTED && netInfo.getState() != NetworkInfo.State.DISCONNECTED) return;
if (netInfo.isConnected()) isTrusted = isTrustedWiFi(mContext);
} else if (action.equals(ACTION_PREFIX + "UnlockBTConnection")) {
isTrusted = isTrustedBt(lpparam.classLoader);
}
XposedHelpers.setAdditionalStaticField(param.thisObject, "isScreenLockDisabled", isTrusted);
if (isTrusted) {
boolean skip = MainModule.mPrefs.getBoolean("system_noscreenlock_skip");
if (skip)
XposedHelpers.callMethod(param.thisObject, "keyguardDone");
else
XposedHelpers.callMethod(param.thisObject, "resetStateLocked");
isUnlockedInnerCall = true;
XposedHelpers.callMethod(XposedHelpers.getObjectField(param.thisObject, "mUpdateMonitor"), "reportSuccessfulStrongAuthUnlockAttempt");
Intent unlockIntent = new Intent(ACTION_PREFIX + "UnlockStrongAuth");
mContext.sendBroadcast(unlockIntent);
} else try {
Object mStatusBar = XposedHelpers.getObjectField(param.thisObject, "mStatusBar");
if (mStatusBar == null) return;
XposedHelpers.callMethod(mStatusBar, "updatePublicMode");
boolean isAnyProfilePublicMode = (boolean)XposedHelpers.callMethod(mStatusBar, "isAnyProfilePublicMode");
Object mStackScroller = XposedHelpers.getObjectField(mStatusBar, "mStackScroller");
XposedHelpers.callMethod(mStackScroller, "setHideSensitive", isAnyProfilePublicMode, true);
XposedHelpers.callMethod(mStatusBar, "updateNotificationViewsOnly");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, filter);
new Helpers.SharedPrefObserver(mContext, new Handler(mContext.getMainLooper())) {
@Override
public void onChange(Uri uri) {
try {
String type = uri.getPathSegments().get(1);
String key = uri.getPathSegments().get(2);
if (!key.contains("pref_key_system_noscreenlock")) return;
switch (type) {
case "string":
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, ""));
break;
case "stringset":
MainModule.mPrefs.put(key, Helpers.getSharedStringSetPref(mContext, key));
break;
case "integer":
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 1));
break;
case "boolean":
MainModule.mPrefs.put(key, Helpers.getSharedBoolPref(mContext, key, false));
break;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardSecurityModel", lpparam.classLoader, "getSecurityMode", int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (forcedOption == 0) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
boolean skip = MainModule.mPrefs.getBoolean("system_noscreenlock_skip");
if (skip) return;
if (!isUnlocked(mContext, lpparam.classLoader)) return;
Class<?> securityModeEnum = XposedHelpers.findClass("com.android.keyguard.KeyguardSecurityModel$SecurityMode", lpparam.classLoader);
Object securityModeNone = XposedHelpers.getStaticObjectField(securityModeEnum, "None");
Object securityModePassword = XposedHelpers.getStaticObjectField(securityModeEnum, "Password");
Object securityModePattern = XposedHelpers.getStaticObjectField(securityModeEnum, "Pattern");
Object securityModePin = XposedHelpers.getStaticObjectField(securityModeEnum, "PIN");
Object secModeResult = param.getResult();
if (securityModePassword.equals(secModeResult) ||
securityModePattern.equals(secModeResult) ||
securityModePin.equals(secModeResult))
param.setResult(securityModeNone);
}
});
Class<?> startClass = findClassIfExists("com.android.keyguard.faceunlock.FaceUnlockManager", lpparam.classLoader);
Method startMethod = XposedHelpers.findMethodExactIfExists(startClass, "startFaceUnlock");
if (!Helpers.is12() && startMethod == null) startClass = findClassIfExists("com.android.keyguard.KeyguardUpdateMonitor", lpparam.classLoader);
if (startClass == null) Helpers.log("NoScreenLockHook", "Face unlock class not found");
if (startClass != null) {
Helpers.hookAllMethods(startClass, "startFaceUnlock", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
boolean skip = MainModule.mPrefs.getBoolean("system_noscreenlock_nofaceunlock");
if (!skip) return;
if (Helpers.is12() && param.args.length == 0) return;
Boolean isScreenLockDisabled = (Boolean)XposedHelpers.getAdditionalStaticField(findClass("com.android.systemui.keyguard.KeyguardViewMediator", lpparam.classLoader), "isScreenLockDisabled");
isScreenLockDisabled = isScreenLockDisabled != null && isScreenLockDisabled;
if (isScreenLockDisabled) param.setResult(null);
}
});
Method showMsgMethod = findMethodExactIfExists(startClass, "isShowMessageWhenFaceUnlockSuccess");
if (showMsgMethod == null) findMethodExactIfExists(startClass, "isFaceUnlockSuccessAndShowMessage");
if (showMsgMethod == null) {
Helpers.log("NoScreenLockHook", "Show notification message method not found");
} else {
Helpers.hookAllMethods(startClass, showMsgMethod.getName(), new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
boolean skip = MainModule.mPrefs.getBoolean("system_noscreenlock_nofaceunlock");
if (!skip || !(boolean)param.getResult()) return;
boolean isScreenLockDisabled = (boolean)XposedHelpers.getAdditionalStaticField(findClass("com.android.systemui.keyguard.KeyguardViewMediator", lpparam.classLoader), "isScreenLockDisabled");
if (isScreenLockDisabled) param.setResult(false);
}
});
}
}
Helpers.hookAllConstructors("com.android.systemui.statusbar.policy.BluetoothControllerImpl", lpparam.classLoader, new MethodHook(10) {
@Override
protected void after(MethodHookParam param) {
Context mContext = (Context)param.args[0];
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mContextMy", mContext);
mContext.registerReceiver(new BroadcastReceiver() {
public void onReceive(final Context context, Intent intent) {
ArrayList<BluetoothDevice> deviceList = new ArrayList<BluetoothDevice>();
Intent updateIntent = new Intent(GlobalActions.EVENT_PREFIX + "CACHEDDEVICESUPDATE");
Collection<?> cachedDevices = (Collection<?>)XposedHelpers.callMethod(param.thisObject, "getCachedDevicesCopy");
if (cachedDevices != null)
for (Object device: cachedDevices) {
BluetoothDevice mDevice = (BluetoothDevice)XposedHelpers.getObjectField(device, "mDevice");
if (mDevice != null) deviceList.add(mDevice);
}
updateIntent.putParcelableArrayListExtra("device_list", deviceList);
updateIntent.setPackage(Helpers.modulePkg);
mContext.sendBroadcast(updateIntent);
}
}, new IntentFilter(ACTION_PREFIX + "FetchCachedDevices"));
}
});
if (!Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.policy.BluetoothControllerImpl", lpparam.classLoader, "updateConnectionState", new MethodHook() {
@Override
protected void after(MethodHookParam param) {
checkBTConnections((Context)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mContextMy"));
}
})) Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BluetoothControllerImpl", lpparam.classLoader, "updateConnected", new MethodHook() {
@Override
protected void after(MethodHookParam param) {
checkBTConnections((Context)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mContextMy"));
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BluetoothControllerImpl", lpparam.classLoader, "onBluetoothStateChanged", int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) {
int state = (int)param.args[0];
if (state != 10) checkBTConnections((Context)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mContextMy"));
}
});
}
private static ImageView createIcon(Context ctx, int baseSize) {
float density = ctx.getResources().getDisplayMetrics().density;
ImageView iv = new ImageView(ctx);
try {
iv.setImageDrawable(ctx.getPackageManager().getApplicationIcon(ctx.getPackageName()));
} catch (Throwable t) {
XposedBridge.log(t);
}
iv.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
int size = Math.round(baseSize * density);
LinearLayout.LayoutParams lpi = new LinearLayout.LayoutParams(size, size);
lpi.setMargins(0, 0, Math.round(8 * density), 0);
lpi.gravity = Gravity.CENTER;
iv.setLayoutParams(lpi);
return iv;
}
private static TextView createLabel(Context ctx, TextView toastText) {
TextView tv = new TextView(ctx);
tv.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
tv.setText(ctx.getApplicationInfo().loadLabel(ctx.getPackageManager()));
tv.setTextColor(Helpers.is11() ? (Helpers.isNightMode(ctx) ? Color.WHITE : Color.BLACK) : Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, toastText.getTextSize());
tv.setTypeface(toastText.getTypeface());
tv.setSingleLine(true);
tv.setAlpha(0.6f);
return tv;
}
private static void modifyIconLabelToast(MethodHookParam param) {
Context ctx = (Context)param.args[0];
float density = ctx.getResources().getDisplayMetrics().density;
int option = Integer.parseInt(Helpers.getSharedStringPref(ctx, "pref_key_system_iconlabletoasts", "1"));
if (option == 1) return;
Object res = param.getResult();
if (res == null) return;
LinearLayout toast = (LinearLayout)XposedHelpers.getObjectField(res, "mNextView");
if (toast == null) return;
toast.setGravity(Gravity.START);
toast.setPadding(toast.getPaddingLeft() - Math.round(5 * density), toast.getPaddingTop() - Math.round(3 * density), toast.getPaddingRight(), toast.getPaddingBottom() - Math.round(3 * density));
TextView toastText = toast.findViewById(android.R.id.message);
if (toastText == null) return;
if (Helpers.is11()) {
toast.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
toastText.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
toastText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 13);
toastText.setLetterSpacing(0.015f);
} else {
toastText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
}
LinearLayout.LayoutParams lpt = (LinearLayout.LayoutParams)toastText.getLayoutParams();
lpt.gravity = Gravity.START;
switch (option) {
case 2:
ImageView iv;
LinearLayout textOnly = new LinearLayout(ctx);
textOnly.setOrientation(LinearLayout.VERTICAL);
if (Helpers.is11()) {
textOnly.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
textOnly.setPadding(0, Math.round(5 * density), 0, Math.round(6 * density));
iv = createIcon(ctx, 22);
} else {
textOnly.setGravity(Gravity.START);
iv = createIcon(ctx, 21);
}
toast.removeAllViews();
textOnly.addView(toastText);
toast.setOrientation(LinearLayout.HORIZONTAL);
toast.addView(iv);
toast.addView(textOnly);
break;
case 3:
TextView tv = createLabel(ctx, toastText);
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)tv.getLayoutParams();
lp.leftMargin = Math.round(5 * density);
lp.rightMargin = Math.round(5 * density);
if (Helpers.is11()) lp.topMargin = Math.round(5 * density);
tv.setLayoutParams(lp);
lp = (LinearLayout.LayoutParams)toastText.getLayoutParams();
lp.leftMargin = Math.round(5 * density);
lp.rightMargin = Math.round(5 * density);
if (Helpers.is11()) lp.bottomMargin = Math.round(5 * density);
toastText.setLayoutParams(lp);
toast.setOrientation(LinearLayout.VERTICAL);
toast.addView(tv, 0);
break;
case 4:
LinearLayout textLabel = new LinearLayout(ctx);
textLabel.setOrientation(LinearLayout.VERTICAL);
if (Helpers.is11()) {
textLabel.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
textLabel.setPadding(0, Math.round(5 * density), 0, Math.round(6 * density));
} else {
textLabel.setGravity(Gravity.START);
}
ImageView iv2 = createIcon(ctx, 42);
TextView tv2 = createLabel(ctx, toastText);
toast.removeAllViews();
textLabel.addView(tv2);
textLabel.addView(toastText);
toast.setOrientation(LinearLayout.HORIZONTAL);
toast.addView(iv2);
toast.addView(textLabel);
break;
}
XposedHelpers.setObjectField(res, "mNextView", toast);
param.setResult(res);
}
public static void IconLabelToastsHook() {
if (!Helpers.findAndHookMethodSilently("android.widget.Toast", null, "makeText", Context.class, Looper.class, CharSequence.class, int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
modifyIconLabelToast(param);
}
})) Helpers.findAndHookMethod("android.widget.Toast", null, "makeText", Context.class, CharSequence.class, int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
modifyIconLabelToast(param);
}
});
Helpers.findAndHookMethod("android.widget.ToastInjector", null, "addAppName", Context.class, CharSequence.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context context = (Context)param.args[0];
int opt = Integer.parseInt(Helpers.getSharedStringPref(context, "pref_key_system_iconlabletoasts", "1"));
if (opt != 1) param.setResult(param.args[1]);
}
});
}
public static void DoubleTapToSleepHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View view = (View)param.thisObject;
XposedHelpers.setAdditionalInstanceField(view, "currentTouchTime", 0L);
XposedHelpers.setAdditionalInstanceField(view, "currentTouchX", 0F);
XposedHelpers.setAdditionalInstanceField(view, "currentTouchY", 0F);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
@SuppressLint("ClickableViewAccessibility")
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() != MotionEvent.ACTION_DOWN) return false;
long currentTouchTime = (long)XposedHelpers.getAdditionalInstanceField(view, "currentTouchTime");
float currentTouchX = (float)XposedHelpers.getAdditionalInstanceField(view, "currentTouchX");
float currentTouchY = (float)XposedHelpers.getAdditionalInstanceField(view, "currentTouchY");
long lastTouchTime = currentTouchTime;
float lastTouchX = currentTouchX;
float lastTouchY = currentTouchY;
currentTouchTime = currentTimeMillis();
currentTouchX = event.getX();
currentTouchY = event.getY();
if (currentTouchTime - lastTouchTime < 250L && Math.abs(currentTouchX - lastTouchX) < 100F && Math.abs(currentTouchY - lastTouchY) < 100F) {
KeyguardManager keyguardMgr = (KeyguardManager)v.getContext().getSystemService(Context.KEYGUARD_SERVICE);
if (keyguardMgr.isKeyguardLocked()) GlobalActions.goToSleep(v.getContext());
currentTouchTime = 0L;
currentTouchX = 0F;
currentTouchY = 0F;
}
XposedHelpers.setAdditionalInstanceField(view, "currentTouchTime", currentTouchTime);
XposedHelpers.setAdditionalInstanceField(view, "currentTouchX", currentTouchX);
XposedHelpers.setAdditionalInstanceField(view, "currentTouchY", currentTouchY);
return false;
}
});
}
});
}
private static int notifVolumeOnResId;
private static int notifVolumeOffResId;
public static void NotificationVolumeDialogRes() {
MainModule.resHooks.setResReplacement("com.android.systemui", "dimen", "miui_volume_content_width_expanded", R.dimen.miui_volume_content_width_expanded);
MainModule.resHooks.setResReplacement("com.android.systemui", "dimen", "miui_volume_ringer_layout_width_expanded", R.dimen.miui_volume_ringer_layout_width_expanded);
notifVolumeOnResId = MainModule.resHooks.addResource("ic_miui_volume_notification", R.drawable.ic_miui_volume_notification);
notifVolumeOffResId = MainModule.resHooks.addResource("ic_miui_volume_notification_mute", R.drawable.ic_miui_volume_notification_mute);
}
private static int settingsNotifResId;
private static int settingsSystemResId;
private static int callsResId;
public static void NotificationVolumeSettingsRes() {
settingsNotifResId = MainModule.resHooks.addResource("ic_audio_notification", R.drawable.ic_audio_notification);
settingsSystemResId = MainModule.resHooks.addResource("ic_audio_system", R.drawable.ic_audio_system);
callsResId = MainModule.resHooks.addResource("ring_volume_option_newtitle", R.string.calls);
}
public static void NotificationVolumeServiceHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.audio.AudioService", lpparam.classLoader, "updateStreamVolumeAlias", boolean.class, String.class, new MethodHook() {
protected void after(MethodHookParam param) throws Throwable {
int[] mStreamVolumeAlias = (int[])XposedHelpers.getObjectField(param.thisObject, "mStreamVolumeAlias");
mStreamVolumeAlias[1] = 1;
mStreamVolumeAlias[5] = 5;
XposedHelpers.setObjectField(param.thisObject, "mStreamVolumeAlias", mStreamVolumeAlias);
}
});
Helpers.findAndHookMethod("com.android.server.audio.AudioService$VolumeStreamState", lpparam.classLoader, "readSettings", new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
int mStreamType = XposedHelpers.getIntField(param.thisObject, "mStreamType");
if (mStreamType != 1) return;
synchronized (param.method.getDeclaringClass()) {
Class<?> audioSystem = findClass("android.media.AudioSystem", null);
int DEVICE_OUT_ALL = XposedHelpers.getStaticIntField(audioSystem, "DEVICE_OUT_ALL");
int DEVICE_OUT_DEFAULT = XposedHelpers.getStaticIntField(audioSystem, "DEVICE_OUT_DEFAULT");
int[] DEFAULT_STREAM_VOLUME = (int[])XposedHelpers.getStaticObjectField(audioSystem, "DEFAULT_STREAM_VOLUME");
int remainingDevices = DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
int device = 1 << i;
if ((device & remainingDevices) == 0) continue;
remainingDevices &= ~device;
String name = (String)XposedHelpers.callMethod(param.thisObject, "getSettingNameForDevice", device);
Object mContentResolver = XposedHelpers.getObjectField(XposedHelpers.getSurroundingThis(param.thisObject), "mContentResolver");
int index = (int)XposedHelpers.callStaticMethod(Settings.System.class, "getIntForUser", mContentResolver, name, device == DEVICE_OUT_DEFAULT ? DEFAULT_STREAM_VOLUME[mStreamType] : -1, -2);
if (index != -1) {
SparseIntArray mIndexMap = (SparseIntArray)XposedHelpers.getObjectField(param.thisObject, "mIndexMap");
mIndexMap.put(device, (Integer)XposedHelpers.callMethod(param.thisObject, "getValidIndex", 10 * index));
XposedHelpers.setObjectField(param.thisObject, "mIndexMap", mIndexMap);
}
}
}
param.setResult(null);
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.server.audio.AudioService", lpparam.classLoader, "shouldZenMuteStream", int.class, new MethodHook() {
protected void after(MethodHookParam param) throws Throwable {
int mStreamType = (int)param.args[0];
if (mStreamType == 5 && !(boolean)param.getResult()) {
int mZenMode = (int)XposedHelpers.callMethod(XposedHelpers.getObjectField(param.thisObject, "mNm"), "getZenMode");
if (mZenMode == 1) param.setResult(true);
}
}
});
}
public static void NotificationVolumeDialogHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.miui.volume.MiuiVolumeDialogImpl", lpparam.classLoader, "initDialog", new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void before(MethodHookParam param) throws Throwable {
List<Object> mColumns = (List<Object>)XposedHelpers.getObjectField(param.thisObject, "mColumns");
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mNoColumns", mColumns == null || mColumns.isEmpty());
}
@Override
protected void after(MethodHookParam param) throws Throwable {
boolean mNoColumns = (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mNoColumns");
if (mNoColumns) XposedHelpers.callMethod(param.thisObject, "addColumn", 5, notifVolumeOnResId, notifVolumeOffResId, true);
}
});
}
public static void NotificationVolumeSettingsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.settings.MiuiSoundSettings", lpparam.classLoader, "onCreate", Bundle.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object fragment = param.thisObject;
Context context = (Context)XposedHelpers.callMethod(fragment, "getActivity");
Resources modRes = Helpers.getModuleRes(context);
int order = 6;
Class<?> vsbCls;
Method[] initSeekBar;
String addPreference = "addPreference";
try {
vsbCls = XposedHelpers.findClassIfExists("com.android.settings.sound.VolumeSeekBarPreference", lpparam.classLoader);
initSeekBar = XposedHelpers.findMethodsByExactParameters(fragment.getClass(), void.class, String.class, int.class, int.class);
if (vsbCls == null || initSeekBar.length == 0) {
Helpers.log("NotificationVolumeSettingsHook", "Unable to find class/method in Settings to hook");
return;
} else {
initSeekBar[0].setAccessible(true);
}
if (Helpers.is12()) {
Class<?> pgCls = XposedHelpers.findClassIfExists("androidx.preference.PreferenceGroup", lpparam.classLoader);
Class<?> pCls = XposedHelpers.findClassIfExists("androidx.preference.Preference", lpparam.classLoader);
Method[] methods = XposedHelpers.findMethodsByExactParameters(pgCls, void.class, pCls);
for (Method method: methods)
if (Modifier.isPublic(method.getModifiers())) {
addPreference = method.getName();
break;
}
}
} catch (Throwable t) {
Helpers.log("NotificationVolumeSettingsHook", "Unable to find class/method in Settings to hook");
return;
}
Object media = XposedHelpers.callMethod(fragment, "findPreference", "media_volume");
if (media != null) order = (int)XposedHelpers.callMethod(media, "getOrder");
Object prefScreen = XposedHelpers.callMethod(fragment, "getPreferenceScreen");
Object pref = XposedHelpers.newInstance(vsbCls, context);
XposedHelpers.callMethod(pref, "setKey", "notification_volume");
XposedHelpers.callMethod(pref, "setTitle", modRes.getString(R.string.system_mods_notifications));
XposedHelpers.callMethod(pref, "setPersistent", true);
XposedHelpers.callMethod(prefScreen, addPreference, pref);
initSeekBar[0].invoke(fragment, "notification_volume", 5, Helpers.is12() ? context.getResources().getIdentifier("ic_audio_notification", "drawable", context.getPackageName()) : settingsNotifResId);
XposedHelpers.callMethod(pref, "setOrder", order);
pref = XposedHelpers.newInstance(vsbCls, context);
XposedHelpers.callMethod(pref, "setKey", "system_volume");
XposedHelpers.callMethod(pref, "setTitle", modRes.getString(R.string.system_volume));
XposedHelpers.callMethod(pref, "setPersistent", true);
XposedHelpers.callMethod(prefScreen, addPreference, pref);
initSeekBar[0].invoke(fragment, "system_volume", 1, Helpers.is12() ? context.getResources().getIdentifier("ic_audio_vol", "drawable", context.getPackageName()) : settingsSystemResId);
XposedHelpers.callMethod(pref, "setOrder", order);
if (Helpers.is12()) {
Object mRingVolume = XposedHelpers.callMethod(param.thisObject, "findPreference", "ring_volume");
XposedHelpers.callMethod(mRingVolume, "setTitle", callsResId);
}
}
});
}
private static String putSecondsIn(CharSequence clockChr) {
NumberFormat df = new DecimalFormat("00");
String clockStr = clockChr.toString();
String clockStrLower = clockStr.toLowerCase();
int colons = clockStr.length() - clockStr.replace(":", "").length();
if (colons >= 2) return clockStr;
//return clockStr.replaceAll("(\\d{1,2}:\\d{1,2}:)\\d{1,2}(?i)(\\s?)((am|pm)?)", "$1" + df.format(Calendar.getInstance().get(Calendar.SECOND)) + "$2$3").trim();
if (clockStrLower.endsWith("am") || clockStrLower.endsWith("pm"))
return clockStr.replaceAll("(?i)(\\s?)(am|pm)", ":" + df.format(Calendar.getInstance().get(Calendar.SECOND)) + "$1$2").trim();
else
return clockStr.trim() + ":" + df.format(Calendar.getInstance().get(Calendar.SECOND));
}
public static void ClockSecondsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new MethodHook(XCallback.PRIORITY_HIGHEST) {
@Override
protected void before(MethodHookParam param) throws Throwable {
TextView clock = (TextView)param.thisObject;
if (clock.getId() != clock.getResources().getIdentifier("clock", "id", "com.android.systemui")) return;
long now = SystemClock.elapsedRealtime();
Long last = (Long)XposedHelpers.getAdditionalInstanceField(clock, "mLastUpdateTime");
if (last == null || now - last > 900)
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mLastUpdateTime", now);
else
param.setResult(null);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
TextView clock = (TextView)param.thisObject;
if (clock.getId() == clock.getResources().getIdentifier("clock", "id", "com.android.systemui"))
clock.setText(putSecondsIn(clock.getText()));
}
});
Helpers.hookAllConstructors("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) {
final TextView clock = (TextView)param.thisObject;
if (clock.getId() != clock.getResources().getIdentifier("clock", "id", "com.android.systemui")) return;
if (XposedHelpers.getAdditionalInstanceField(clock, "mSecondsTimer") != null) return;
final Handler mClockHandler = new Handler(clock.getContext().getMainLooper());
int opt = MainModule.mPrefs.getStringAsInt("system_clockseconds_sync", 0);
long delay = 1000 - SystemClock.elapsedRealtime() % 1000;
delay += opt == 1 ? 50 : 950;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
mClockHandler.post(new Runnable() {
@Override
public void run() {
XposedHelpers.callMethod(clock, "updateClock");
}
});
}
}, delay, 1000);
XposedHelpers.setAdditionalInstanceField(clock, "mSecondsTimer", timer);
}
});
}
public static void ExpandNotificationsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateRowStates", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ViewGroup mStackScroller = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mStackScroller");
for (int i = mStackScroller.getChildCount() - 1; i >= 0; i--) {
View enotificationrow = mStackScroller.getChildAt(i);
if (enotificationrow != null && enotificationrow.getClass().getSimpleName().equalsIgnoreCase("ExpandableNotificationRow")) try {
Object notification = XposedHelpers.getObjectField(XposedHelpers.callMethod(enotificationrow, "getEntry"), "notification");
String pkgName = (String)XposedHelpers.callMethod(notification, "getPackageName");
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_expandnotifs", "1"));
boolean isSelected = MainModule.mPrefs.getStringSet("system_expandnotifs_apps").contains(pkgName);
if (opt == 2 && !isSelected || opt == 3 && isSelected)
XposedHelpers.callMethod(enotificationrow, "setSystemExpanded", true);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
});
}
public static void PopupNotificationsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "addNotification", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (param.args[0] == null) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (MainModule.mPrefs.getBoolean("system_popupnotif_fs"))
if (Settings.Global.getInt(mContext.getContentResolver(), Helpers.modulePkg + ".foreground.fullscreen", 0) == 1) return;
Set<String> selectedApps = Helpers.getSharedStringSetPref(mContext, "pref_key_system_popupnotif_apps");
String pkgName = (String)XposedHelpers.callMethod(param.args[0], "getPackageName");
if (selectedApps.contains(pkgName)) {
Intent expandNotif = new Intent(ACTION_PREFIX + "ExpandNotifications");
expandNotif.putExtra("expand_only", true);
mContext.sendBroadcast(expandNotif);
}
}
});
}
public static void RecentsBlurRatioHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.recents.views.RecentsView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
Handler mHandler = new Handler(mContext.getMainLooper());
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomBlurModifier", MainModule.mPrefs.getInt("system_recents_blur", 100));
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_recents_blur", 100) {
@Override
public void onChange(String name, int defValue) {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomBlurModifier", Helpers.getSharedIntPref(mContext, name, defValue));
}
};
XposedHelpers.setFloatField(param.thisObject, "mDefaultScrimAlpha", 0.15f);
XposedHelpers.setObjectField(param.thisObject, "mBackgroundScrim", new ColorDrawable(Color.argb(38, 0, 0, 0)).mutate());
}
});
Helpers.findAndHookMethod("com.android.systemui.recents.views.RecentsView", lpparam.classLoader, "updateBlurRatio", float.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = (float)param.args[0] * (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCustomBlurModifier") / 100f;
}
});
}
public static void DrawerBlurRatioHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.statusbar.phone.StatusBarWindowManager", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
Handler mHandler = new Handler(mContext.getMainLooper());
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomBlurModifier", MainModule.mPrefs.getInt("system_drawer_blur", 100));
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_drawer_blur", 100) {
@Override
public void onChange(String name, int defValue) {
int opt = Helpers.getSharedIntPref(mContext, name, defValue);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomBlurModifier", opt);
if (Helpers.is12()) {
Object mControlPanelWindowManager = XposedHelpers.callStaticMethod(findClass("com.android.systemui.Dependency", lpparam.classLoader), "get", findClass("com.android.systemui.miui.statusbar.phone.ControlPanelWindowManager", lpparam.classLoader));
XposedHelpers.setAdditionalInstanceField(mControlPanelWindowManager, "mCustomBlurModifier", opt);
}
}
};
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBarWindowManager", lpparam.classLoader, "setBlurRatio", float.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = (float)param.args[0] * (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCustomBlurModifier") / 100f;
}
});
if (!Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "onBlurRatioChanged", float.class, new MethodHook(1000) {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = XposedHelpers.callMethod(param.thisObject, "getAppearFraction");
}
})) Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "updateStatusBarWindowBlur", new MethodHook(100) {
@Override
protected void after(MethodHookParam param) throws Throwable {
int mStatusBarState = XposedHelpers.getIntField(param.thisObject, "mStatusBarState");
if (mStatusBarState != 0) return;
View mThemeBackgroundView = (View)XposedHelpers.getObjectField(param.thisObject, "mThemeBackgroundView");
if (mThemeBackgroundView != null)
mThemeBackgroundView.setAlpha((float)XposedHelpers.callMethod(param.thisObject, "getAppearFraction"));
}
});
if (Helpers.is12()) {
Helpers.hookAllConstructors("com.android.systemui.miui.statusbar.phone.ControlPanelWindowManager", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomBlurModifier", MainModule.mPrefs.getInt("system_drawer_blur", 100));
}
});
Helpers.findAndHookMethod("com.android.systemui.miui.statusbar.phone.ControlPanelWindowManager", lpparam.classLoader, "applyBlurRatio", float.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = (float)param.args[0] * (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCustomBlurModifier") / 100f;
}
});
}
}
public static void DrawerThemeBackgroundHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
Handler mHandler = new Handler(mContext.getMainLooper());
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomOpacityModifier", MainModule.mPrefs.getInt("system_drawer_opacity", 100));
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_drawer_opacity", 100) {
@Override
public void onChange(String name, int defValue) {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCustomOpacityModifier", Helpers.getSharedIntPref(mContext, name, defValue));
}
};
}
});
if (!Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "onBlurRatioChanged", float.class, new MethodHook(100) {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = (float)param.args[0] * (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCustomOpacityModifier") / 100f;
}
})) Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "updateStatusBarWindowBlur", new MethodHook(1000) {
@Override
protected void after(MethodHookParam param) throws Throwable {
int mStatusBarState = XposedHelpers.getIntField(param.thisObject, "mStatusBarState");
if (mStatusBarState != 0) return;
View mThemeBackgroundView = (View)XposedHelpers.getObjectField(param.thisObject, "mThemeBackgroundView");
if (mThemeBackgroundView != null)
mThemeBackgroundView.setAlpha(mThemeBackgroundView.getAlpha() * (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCustomOpacityModifier") / 100f);
}
});
}
private static boolean is4GPlus = false;
public static void HideNetworkTypeHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView$PhoneState", lpparam.classLoader, "updateMobileType", String.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_mobiletypeicon", "1"));
TextView mMobileType = (TextView)XposedHelpers.getObjectField(param.thisObject, "mMobileType");
TextView mSignalDualNotchMobileType = (TextView)XposedHelpers.getObjectField(XposedHelpers.getSurroundingThis(param.thisObject), "mSignalDualNotchMobileType");
boolean isMobileConnected = false;
if (opt == 2) {
ConnectivityManager mgr = (ConnectivityManager)mMobileType.getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
Network net = mgr.getActiveNetwork();
if (net != null) {
NetworkCapabilities netCaps = mgr.getNetworkCapabilities(net);
if (netCaps != null)
isMobileConnected = netCaps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
}
}
if (opt == 3 || (opt == 2 && !isMobileConnected)) {
mMobileType.setText("");
mSignalDualNotchMobileType.setText("");
}
// try {
// View parent = (View)((View)XposedHelpers.getSurroundingThis(param.thisObject)).getParent().getParent().getParent().getParent();
// parent != null && parent.getId() != parent.getResources().getIdentifier("header_content", "id", lpparam.packageName)
// Helpers.log(parent + ", " + parent.getId() + " != " + mMobileType.getResources().getIdentifier("header_content", "id", lpparam.packageName));
// } catch (Throwable t) {
// XposedBridge.log(t);
// }
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView$PhoneState", lpparam.classLoader, "updateMobileTypeForNormal", boolean.class, String.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
is4GPlus = (boolean)param.args[0];
param.args[0] = true;
}
@Override
protected void after(MethodHookParam param) throws Throwable {
param.setResult(is4GPlus);
}
});
}
public static void TrafficSpeedSpacingHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.NetworkSpeedView", lpparam.classLoader, "onAttachedToWindow", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
TextView meter = (TextView)param.thisObject;
if (meter == null) return;
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)meter.getLayoutParams();
int margin = Math.round(meter.getResources().getDisplayMetrics().density * 4);
lp.rightMargin = margin;
lp.leftMargin = margin;
meter.setLayoutParams(lp);
}
});
}
public static void ChargeAnimationHook(LoadPackageParam lpparam) {
Class<?> ccCls;
try {
ccCls = XposedHelpers.findClass("com.android.keyguard.charge.MiuiWirelessChargeController", lpparam.classLoader);
} catch (Throwable t1) {
try {
ccCls = XposedHelpers.findClass("com.android.keyguard.charge.MiuiChargeController", lpparam.classLoader);
} catch (Throwable t2) {
XposedBridge.log(t1);
XposedBridge.log(t2);
return;
}
}
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(ccCls, "showWirelessChargeAnimation", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
Runnable mScreenOffRunnable = (Runnable)XposedHelpers.getObjectField(param.thisObject, "mScreenOffRunnable");
WakeLock mScreenOnWakeLock = (WakeLock)XposedHelpers.getObjectField(param.thisObject, "mScreenOnWakeLock");
if (mContext != null && mHandler != null && mScreenOffRunnable != null && mScreenOnWakeLock != null) {
if (mScreenOnWakeLock.isHeld()) {
int timeout = Helpers.getSharedIntPref(mContext, "pref_key_system_chargeanimtime", 20) * 1000;
mHandler.postDelayed(mScreenOnWakeLock::release, timeout);
mHandler.removeCallbacks(mScreenOffRunnable);
mHandler.postDelayed(mScreenOffRunnable, timeout);
}
} else Helpers.log("ChargeAnimationHook1", "Something is NULL! :)");
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(ccCls, "showRapidChargeAnimation", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
Runnable mScreenOffRunnable = (Runnable)XposedHelpers.getObjectField(param.thisObject, "mScreenOffRunnable");
WakeLock mScreenOnWakeLock = (WakeLock)XposedHelpers.getObjectField(param.thisObject, "mScreenOnWakeLock");
if (mContext != null && mHandler != null && mScreenOffRunnable != null && mScreenOnWakeLock != null) {
if (mScreenOnWakeLock.isHeld()) {
int timeout = Helpers.getSharedIntPref(mContext, "pref_key_system_chargeanimtime", 20) * 1000;
mHandler.postDelayed(mScreenOnWakeLock::release, timeout);
mHandler.removeCallbacks(mScreenOffRunnable);
mHandler.postDelayed(mScreenOffRunnable, timeout);
}
} else Helpers.log("ChargeAnimationHook2", "Something is NULL! :)");
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(ccCls, "showWirelessRapidChargeAnimation", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
Runnable mScreenOffRunnable = (Runnable)XposedHelpers.getObjectField(param.thisObject, "mScreenOffRunnable");
WakeLock mScreenOnWakeLock = (WakeLock)XposedHelpers.getObjectField(param.thisObject, "mScreenOnWakeLock");
if (mContext != null && mHandler != null && mScreenOffRunnable != null && mScreenOnWakeLock != null) {
if (mScreenOnWakeLock.isHeld()) {
int timeout = Helpers.getSharedIntPref(mContext, "pref_key_system_chargeanimtime", 20) * 1000;
mHandler.postDelayed(mScreenOnWakeLock::release, timeout);
mHandler.removeCallbacks(mScreenOffRunnable);
mHandler.postDelayed(mScreenOffRunnable, timeout);
}
} else Helpers.log("ChargeAnimationHook3", "Something is NULL! :)");
}
});
}
public static void VolumeStepsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.audio.AudioService", lpparam.classLoader, "createStreamStates", new MethodHook() {
@Override
protected void before(MethodHookParam param) {
Class<?> audioCls = findClass("com.android.server.audio.AudioService", lpparam.classLoader);
int[] maxStreamVolume = (int[])XposedHelpers.getStaticObjectField(audioCls, "MAX_STREAM_VOLUME");
int mult = MainModule.mPrefs.getInt("system_volumesteps", 0);
if (mult <= 0) return;
for (int i = 0; i < maxStreamVolume.length; i++)
maxStreamVolume[i] = Math.round(maxStreamVolume[i] * mult / 100.0f);
XposedHelpers.setStaticObjectField(audioCls, "MAX_STREAM_VOLUME", maxStreamVolume);
}
});
}
private static int minBrightnessLevel;
private static int maxBrightnessLevel;
private static int constrainValue(int val) {
if (val < 0) return val;
boolean limitmin = MainModule.mPrefs.getBoolean("system_autobrightness_limitmin");
boolean limitmax = MainModule.mPrefs.getBoolean("system_autobrightness_limitmax");
int min_pct = MainModule.mPrefs.getInt("system_autobrightness_min", 25);
int max_pct = MainModule.mPrefs.getInt("system_autobrightness_max", 75);
int range, min, max;
range = maxBrightnessLevel - minBrightnessLevel;
if (maxBrightnessLevel != 255 || MainModule.mPrefs.getBoolean("system_autobrightness_hlg")) {
min = Helpers.convertGammaToLinear(minBrightnessLevel + (int)(range * min_pct / 100f), minBrightnessLevel, maxBrightnessLevel);
max = Helpers.convertGammaToLinear(minBrightnessLevel + (int)(range * max_pct / 100f), minBrightnessLevel, maxBrightnessLevel);
} else {
min = minBrightnessLevel + (int)(range * min_pct / 100f);
max = minBrightnessLevel + (int)(range * max_pct / 100f);
}
if (max <= min) max = min + 1;
if (limitmin && val < min) val = min;
if (limitmax && val > max) val = max;
return val;
}
public static void AutoBrightnessRangeHook(LoadPackageParam lpparam) {
Class<?> bmsCls = findClassIfExists("com.android.server.display.BrightnessMappingStrategy", lpparam.classLoader);
if (bmsCls != null) {
Helpers.hookAllConstructors("com.android.server.display.BrightnessMappingStrategy$SimpleMappingStrategy", lpparam.classLoader, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int[] values = (int[])param.args[1];
for (int i = 0; i < values.length; i++)
values[i] = constrainValue(values[i]);
param.args[1] = values;
}
});
Helpers.hookAllConstructors("com.android.server.display.BrightnessMappingStrategy$PhysicalMappingStrategy", lpparam.classLoader, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int[] values = (int[])param.args[2];
for (int i = 0; i < values.length; i++)
values[i] = constrainValue(values[i]);
param.args[2] = values;
}
});
}
if (!Helpers.isPiePlus())
Helpers.findAndHookMethod("com.android.server.display.AutomaticBrightnessController", lpparam.classLoader, "updateAutoBrightness", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
int val = XposedHelpers.getIntField(param.thisObject, "mScreenAutoBrightness");
int newVal = constrainValue(val);
if (val >= 0 && val != newVal) {
//XposedBridge.log("updateAutoBrightness: " + val + " -> " + newVal);
XposedHelpers.setIntField(param.thisObject, "mScreenAutoBrightness", newVal);
if ((boolean)param.args[0]) {
//XposedHelpers.callStaticMethod(findClass("com.android.server.display.AutomaticBrightnessControllerInjector", lpparam.classLoader), "recordAutoBrightnessChange", newVal);
Object mCallbacks = XposedHelpers.getObjectField(param.thisObject, "mCallbacks");
XposedHelpers.callMethod(mCallbacks, "updateBrightness");
}
}
}
});
else
Helpers.hookAllMethods("com.android.server.display.AutomaticBrightnessControllerInjector", lpparam.classLoader, "changeBrightness", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
int val = (int)param.getResult();
if (val >= 0) param.setResult(constrainValue(val));
}
});
Helpers.hookAllConstructors("com.android.server.display.AutomaticBrightnessController", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
XposedHelpers.setLongField(param.thisObject, "mBrighteningLightDebounceConfig", 500L);
XposedHelpers.setLongField(param.thisObject, "mDarkeningLightDebounceConfig", 500L);
}
});
Helpers.hookAllConstructors("com.android.server.display.DisplayPowerController", lpparam.classLoader, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
Context context = (Context)param.args[0];
Resources res = context.getResources();
minBrightnessLevel = res.getInteger(res.getIdentifier("config_screenBrightnessSettingMinimum", "integer", "android"));
maxBrightnessLevel = res.getInteger(res.getIdentifier("config_screenBrightnessSettingMaximum", "integer", "android"));
}
});
}
private static long measureTime = 0;
private static long txBytesTotal = 0;
private static long rxBytesTotal = 0;
private static long txSpeed = 0;
private static long rxSpeed = 0;
private static Pair<Long, Long> getTrafficBytes(Object thisObject) {
long tx = -1L;
long rx = -1L;
try {
for (Enumeration<NetworkInterface> list = NetworkInterface.getNetworkInterfaces(); list.hasMoreElements();) {
NetworkInterface iface = list.nextElement();
if (iface.isUp() && !iface.isVirtual() && !iface.isLoopback() && !iface.isPointToPoint() && !"".equals(iface.getName())) {
tx += (long)XposedHelpers.callStaticMethod(TrafficStats.class, "getTxBytes", iface.getName());
rx += (long)XposedHelpers.callStaticMethod(TrafficStats.class, "getRxBytes", iface.getName());
}
}
return new Pair<Long, Long>(tx, rx);
} catch (Throwable t) {
XposedBridge.log(t);
}
try {
Context mContext = (Context)XposedHelpers.getObjectField(thisObject, "mContext");
Uri mNetworkUri = (Uri)XposedHelpers.getObjectField(thisObject, "mNetworkUri");
Cursor query = mContext.getContentResolver().query(mNetworkUri, null, null, null, null);
if (query != null) {
try {
if (query.moveToFirst()) {
tx = query.getLong(query.getColumnIndex("total_tx_byte"));
rx = query.getLong(query.getColumnIndex("total_rx_byte"));
}
} catch (Exception e) {
tx = 1L; rx = 1L;
} catch (Throwable th) {
query.close();
}
query.close();
} else {
tx = TrafficStats.getTotalTxBytes();
rx = TrafficStats.getTotalRxBytes();
}
} catch (Throwable t) {
XposedBridge.log(t);
tx = TrafficStats.getTotalTxBytes();
rx = TrafficStats.getTotalRxBytes();
}
return new Pair<Long, Long>(tx, rx);
}
@SuppressLint("DefaultLocale")
private static String humanReadableByteCount(Context ctx, long bytes) {
try {
Resources modRes = Helpers.getModuleRes(ctx);
if (bytes < 1024) return bytes + " " + modRes.getString(R.string.Bs);
int exp = (int) (Math.log(bytes) / Math.log(1024));
char pre = modRes.getString(R.string.speedunits).charAt(exp-1);
DecimalFormat df = new DecimalFormat("0.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH));
df.setMinimumFractionDigits(0);
df.setMaximumFractionDigits(1);
return df.format(bytes / Math.pow(1024, exp)) + " " + String.format("%s" + modRes.getString(R.string.Bs), pre);
} catch (Throwable t) {
XposedBridge.log(t);
return "";
}
}
public static void NetSpeedIntervalHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.NetworkSpeedView", lpparam.classLoader, "onAttachedToWindow", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Settings.System.putInt(mContext.getContentResolver(), "status_bar_network_speed_interval", MainModule.mPrefs.getInt("system_netspeedinterval", 4) * 1000);
}
});
}
public static void DetailedNetSpeedHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.NetworkSpeedView", lpparam.classLoader, "onTextChanged", XC_MethodReplacement.DO_NOTHING);
Helpers.hookAllConstructors("com.android.systemui.statusbar.NetworkSpeedView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
TextView meter = (TextView)param.thisObject;
float density = meter.getResources().getDisplayMetrics().density;
int font = Integer.parseInt(MainModule.mPrefs.getString("system_detailednetspeed_font", "3"));
int icons = Integer.parseInt(MainModule.mPrefs.getString("system_detailednetspeed_icon", "2"));
float size = 8.0f;
float spacing = 0.7f;
int top = 0;
switch (font) {
case 1: size = 10.0f; spacing = 0.75f; top = Math.round(density); break;
case 2: size = 9.0f; break;
case 3: size = 8.0f; break;
case 4: size = 7.0f; break;
}
meter.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size);
meter.setSingleLine(false);
meter.setLines(2);
meter.setMaxLines(2);
meter.setLineSpacing(0, icons == 1 ? 0.85f : spacing);
meter.setPadding(Math.round(meter.getPaddingLeft() + 3 * density), meter.getPaddingTop() - top, meter.getPaddingRight(), meter.getPaddingBottom());
}
});
Class<?> nscCls = XposedHelpers.findClassIfExists("com.android.systemui.statusbar.NetworkSpeedController", lpparam.classLoader);
if (nscCls == null) nscCls = XposedHelpers.findClassIfExists("com.android.systemui.statusbar.NetworkSpeedView", lpparam.classLoader);
if (nscCls == null) {
Helpers.log("DetailedNetSpeedHook", "No NetworkSpeed view or controller");
return;
}
Helpers.hookAllConstructors(nscCls, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Handler mHandler = new Handler(Looper.getMainLooper()) {
public void handleMessage(Message message) {
if (message.what == 200000) try {
boolean show = message.arg1 != 0;
XposedHelpers.callMethod(param.thisObject, "setVisibilityToViewList", show ? View.VISIBLE : View.GONE);
if (show) XposedHelpers.callMethod(param.thisObject, "setTextToViewList", "-");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
XposedHelpers.setObjectField(param.thisObject, "mHandler", mHandler);
}
});
Helpers.findAndHookMethod(nscCls, "getTotalByte", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Pair<Long, Long> bytes = getTrafficBytes(param.thisObject);
txBytesTotal = bytes.first;
rxBytesTotal = bytes.second;
measureTime = nanoTime();
}
});
Method asyncMethod = XposedHelpers.findMethodExactIfExists(nscCls, "updateNetworkSpeedAsync");
Helpers.findAndHookMethod(nscCls, asyncMethod != null ? "updateNetworkSpeedAsync" : "updateNetworkSpeed", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
boolean isConnected = false;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
ConnectivityManager mConnectivityManager = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null)
if (activeNetworkInfo.isConnected()) isConnected = true;
if (isConnected) {
long nanoTime = nanoTime();
long newTime = nanoTime - measureTime;
measureTime = nanoTime;
if (newTime == 0) newTime = Math.round(4 * Math.pow(10, 9));
Pair<Long, Long> bytes = getTrafficBytes(param.thisObject);
long newTxBytes = bytes.first;
long newRxBytes = bytes.second;
long newTxBytesFixed = newTxBytes - txBytesTotal;
long newRxBytesFixed = newRxBytes - rxBytesTotal;
if (newTxBytesFixed < 0 || txBytesTotal == 0) newTxBytesFixed = 0;
if (newRxBytesFixed < 0 || rxBytesTotal == 0) newRxBytesFixed = 0;
txSpeed = Math.round(newTxBytesFixed / (newTime / Math.pow(10, 9)));
rxSpeed = Math.round(newRxBytesFixed / (newTime / Math.pow(10, 9)));
txBytesTotal = newTxBytes;
rxBytesTotal = newRxBytes;
} else {
txSpeed = 0;
rxSpeed = 0;
}
}
});
Helpers.findAndHookMethod(nscCls, "setTextToViewList", CharSequence.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
boolean hideLow = MainModule.mPrefs.getBoolean("system_detailednetspeed_low");
boolean reduceVis = MainModule.mPrefs.getBoolean("system_detailednetspeed_zero");
int lowLevel = MainModule.mPrefs.getInt("system_detailednetspeed_lowlevel", 1) * 1024;
int icons = Integer.parseInt(MainModule.mPrefs.getString("system_detailednetspeed_icon", "2"));
String txarrow = "";
String rxarrow = "";
if (icons == 2) {
txarrow = txSpeed < lowLevel ? "△" : "▲";
rxarrow = rxSpeed < lowLevel ? "▽" : "▼";
} else if (icons == 3) {
txarrow = txSpeed < lowLevel ? " ☖" : " ☗";
rxarrow = rxSpeed < lowLevel ? " ⛉" : " ⛊";
}
String tx = hideLow && txSpeed < lowLevel ? "" : humanReadableByteCount(mContext, txSpeed) + txarrow;
String rx = hideLow && rxSpeed < lowLevel ? "" : humanReadableByteCount(mContext, rxSpeed) + rxarrow;
param.args[0] = tx + "\n" + rx;
if (reduceVis) try {
CopyOnWriteArrayList<?> mViewList = (CopyOnWriteArrayList<?>)XposedHelpers.getObjectField(param.thisObject, "mViewList");
for (Object tv: mViewList)
if (tv != null) ((TextView)tv).setAlpha(rxSpeed == 0 && txSpeed == 0 ? 0.3f : 1.0f);
} catch (Throwable t1) {
try {
ArrayList<?> mViewList = (ArrayList<?>)XposedHelpers.getObjectField(param.thisObject, "mViewList");
for (Object tv: mViewList)
if (tv != null) ((TextView)tv).setAlpha(rxSpeed == 0 && txSpeed == 0 ? 0.3f : 1.0f);
} catch (Throwable t2) {
ArrayList<?> sViewList = (ArrayList<?>)XposedHelpers.getObjectField(param.thisObject, "sViewList");
for (Object tv : sViewList)
if (tv != null) ((TextView)tv).setAlpha(rxSpeed == 0 && txSpeed == 0 ? 0.3f : 1.0f);
}
}
//Helpers.log("DetailedNetSpeedHook", "setTextToViewList: " + tx + ", " + rx);
//Helpers.log("DetailedNetSpeedHook", "class: " + param.thisObject.getClass().getSimpleName());
}
});
}
private static Bitmap processAlbumArt(Context context, Bitmap bitmap) {
if (context == null || bitmap == null) return bitmap;
int rescale = Integer.parseInt(Helpers.getSharedStringPref(context, "pref_key_system_albumartonlock_scale", "1"));
boolean grayscale = Helpers.getSharedBoolPref(context, "pref_key_system_albumartonlock_gray", false);
if (rescale == 1 && !grayscale) return bitmap;
Paint paint = new Paint();
Matrix transformation = new Matrix();
int width = 0;
int height = 0;
if (grayscale) {
width = bitmap.getWidth();
height = bitmap.getHeight();
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
paint.setColorFilter(new ColorMatrixColorFilter(matrix));
}
if (rescale != 1) {
Display display = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
Point point = new Point();
display.getRealSize(point);
width = point.x;
height = point.y;
float originalWidth = bitmap.getWidth();
float originalHeight = bitmap.getHeight();
float scale = rescale == 2 ? Math.min(width / originalWidth, height / originalHeight) : Math.max(width / originalWidth, height / originalHeight);
float xTranslation = (width - originalWidth * scale) / 2.0f;
float yTranslation = (height - originalHeight * scale) / 2.0f;
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
paint.setFilterBitmap(true);
}
Bitmap processed = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(processed);
canvas.drawBitmap(bitmap, transformation, paint);
return processed;
}
public static void LockScreenAlbumArtHook(LoadPackageParam lpparam) {
Method getLockWallpaperPreview = null;
Class<?> utilClsTmp = XposedHelpers.findClassIfExists("com.android.keyguard.wallpaper.KeyguardWallpaperUtils", lpparam.classLoader);
if (utilClsTmp != null)
getLockWallpaperPreview = XposedHelpers.findMethodExactIfExists(utilClsTmp, "getLockWallpaperPreview", Context.class);
if (getLockWallpaperPreview == null) {
utilClsTmp = XposedHelpers.findClassIfExists("com.android.keyguard.MiuiKeyguardUtils", lpparam.classLoader);
if (utilClsTmp != null)
getLockWallpaperPreview = XposedHelpers.findMethodExactIfExists(utilClsTmp, "getLockWallpaperPreview", Context.class);
}
if (utilClsTmp == null || getLockWallpaperPreview == null) {
Helpers.log("LockScreenAlbumArtHook", "Method getLockWallpaperPreview not found");
return;
}
Method getLockWallpaper = XposedHelpers.findMethodExactIfExists(utilClsTmp, "getLockWallpaper", Context.class);
Method getLockWallpaperCache = XposedHelpers.findMethodExactIfExists(utilClsTmp, "getLockWallpaperCache", Context.class);
if (getLockWallpaper == null && getLockWallpaperCache == null) {
Helpers.log("LockScreenAlbumArtHook", "No getLockWallpaper(Cache) methods found");
return;
}
final Class<?> utilCls = utilClsTmp;
Helpers.hookMethod(getLockWallpaperPreview, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Bitmap mAlbumArt = (Bitmap)XposedHelpers.getAdditionalStaticField(utilCls, "mAlbumArt");
if (mAlbumArt != null) param.setResult(new BitmapDrawable(((Context)param.args[0]).getResources(), mAlbumArt));
}
});
if (getLockWallpaper != null)
Helpers.hookMethod(getLockWallpaper, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Bitmap mAlbumArt = (Bitmap)XposedHelpers.getAdditionalStaticField(utilCls, "mAlbumArt");
if (mAlbumArt != null) param.setResult(new Pair<File, Drawable>(new File(""), new BitmapDrawable(((Context)param.args[0]).getResources(), mAlbumArt)));
}
});
if (getLockWallpaperCache != null)
Helpers.hookMethod(getLockWallpaperCache, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Bitmap mAlbumArt = (Bitmap)XposedHelpers.getAdditionalStaticField(utilCls, "mAlbumArt");
if (mAlbumArt != null) param.setResult(new Pair<File, Drawable>(new File(""), new BitmapDrawable(((Context)param.args[0]).getResources(), mAlbumArt)));
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateMediaMetaData", boolean.class, boolean.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
// com.miui.internal.policy.impl.AwesomeLockScreenImp.WallpaperScreenElement
if (new File("/data/system/theme/lockscreen").exists()) {
XposedHelpers.setAdditionalStaticField(utilCls, "mAlbumArtSource", null);
XposedHelpers.setAdditionalStaticField(utilCls, "mAlbumArt", null);
return;
}
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
MediaMetadata mMediaMetadata = (MediaMetadata)XposedHelpers.getObjectField(param.thisObject, "mMediaMetadata");
Bitmap art = null;
if (mMediaMetadata != null) {
art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
if (art == null) art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
if (art == null) art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
}
Bitmap mAlbumArt = (Bitmap)XposedHelpers.getAdditionalStaticField(utilCls, "mAlbumArtSource");
try {
if (art == null && mAlbumArt == null) return;
if (art != null && art.sameAs(mAlbumArt)) return;
} catch (Throwable ignore) {}
XposedHelpers.setAdditionalStaticField(utilCls, "mAlbumArtSource", art);
int blur = Helpers.getSharedIntPref(mContext, "pref_key_system_albumartonlock_blur", 0);
XposedHelpers.setAdditionalStaticField(utilCls, "mAlbumArt", processAlbumArt(mContext, art != null && blur > 0 ? Helpers.fastBlur(art, blur + 1) : art));
Intent setWallpaper = new Intent("com.miui.keyguard.setwallpaper");
setWallpaper.putExtra("set_lock_wallpaper_result", true);
mContext.sendBroadcast(setWallpaper);
}
});
// Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "setKeyguardOtherViewVisibility", int.class, new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// (int)param.args[0] == 1 ? View.VISIBLE : View.GONE
// }
// });
}
public static void BetterPopupsHideDelaySysHook() {
Helpers.findAndHookMethod(MiuiNotification.class, "getFloatTime", XC_MethodReplacement.returnConstant(0));
}
public static void BetterPopupsHideDelayHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
int delay = MainModule.mPrefs.getInt("system_betterpopups_delay", 0) * 1000;
if (delay == 0) delay = 5000;
XposedHelpers.setIntField(param.thisObject, "mMinimumDisplayTime", delay);
XposedHelpers.setIntField(param.thisObject, "mHeadsUpNotificationDecay", delay);
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_betterpopups_delay", 0) {
@Override
public void onChange(String name, int defValue) {
int delay = Helpers.getSharedIntPref(mContext, name, defValue) * 1000;
if (delay == 0) delay = 5000;
XposedHelpers.setIntField(param.thisObject, "mMinimumDisplayTime", delay);
XposedHelpers.setIntField(param.thisObject, "mHeadsUpNotificationDecay", delay);
}
};
}
});
}
public static void BetterPopupsNoHideHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, "removeHeadsUpNotification", XC_MethodReplacement.DO_NOTHING);
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, "removeOldHeadsUpNotification", XC_MethodReplacement.DO_NOTHING);
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager$HeadsUpEntry", lpparam.classLoader, "updateEntry", boolean.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
XposedHelpers.setObjectField(param.thisObject, "mRemoveHeadsUpRunnable", new Runnable() {
@Override
public void run() {}
});
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, "onExpandingFinished", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
XposedHelpers.setBooleanField(param.thisObject, "mReleaseOnExpandFinish", true);
}
});
// Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, "onReorderingAllowed", new MethodHook() {
// @Override
// protected void before(final MethodHookParam param) throws Throwable {
// Helpers.log("BetterPopupsNoHideHook", "onReorderingAllowed");
// }
// });
}
public static void BetterPopupsSwipeDownHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.HeadsUpTouchHelper", lpparam.classLoader, "onInterceptTouchEvent", MotionEvent.class, new MethodHook() {
@Override
@SuppressWarnings("ConstantConditions")
protected void after(final MethodHookParam param) throws Throwable {
MotionEvent me = (MotionEvent)param.args[0];
if (me.getActionMasked() == MotionEvent.ACTION_DOWN) {
boolean mAllowSwipingDown = true;
if (Helpers.is12()) try {
Object mPickedChild = XposedHelpers.getObjectField(param.thisObject, "mPickedChild");
if (mPickedChild != null) {
View mMiniBar = (View)XposedHelpers.callMethod(mPickedChild, "getMiniWindowBar");
if (mMiniBar != null && mMiniBar.getVisibility() == View.VISIBLE) mAllowSwipingDown = false;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mAllowSwipingDown", mAllowSwipingDown);
}
if (me.getActionMasked() == MotionEvent.ACTION_MOVE) {
Object mAllowSwipingDown = XposedHelpers.getAdditionalInstanceField(param.thisObject, "mAllowSwipingDown");
if (mAllowSwipingDown instanceof Boolean && !(boolean)mAllowSwipingDown) return;
boolean mTouchingHeadsUpView = (boolean)XposedHelpers.getObjectField(param.thisObject, "mTouchingHeadsUpView");
if (!mTouchingHeadsUpView) return;
float mTouchSlop = (float)XposedHelpers.getObjectField(param.thisObject, "mTouchSlop");
float mInitialTouchY = (float)XposedHelpers.getObjectField(param.thisObject, "mInitialTouchY");
if (me.getY() - mInitialTouchY > mTouchSlop) {
XposedHelpers.setObjectField(param.thisObject, "mTouchingHeadsUpView", false);
ViewGroup mStackScroller = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mStackScroller");
Context mContext = mStackScroller != null ? mStackScroller.getContext() : null;
if (mContext == null) {
Helpers.log("BetterPopupsSwipeDownHook", "Cannot get context!");
return;
}
Intent expandNotif = new Intent(ACTION_PREFIX + "ExpandNotifications");
expandNotif.putExtra("expand_only", true);
mContext.sendBroadcast(expandNotif);
}
}
}
});
}
public static void RotationAnimationRes() {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_rotateanim", "1"));
int enter = 0;
int exit = 0;
if (opt == 2) {
enter = R.anim.no_enter;
exit = R.anim.no_exit;
} else if (opt == 3) {
enter = R.anim.xfade_enter;
exit = R.anim.xfade_exit;
}
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_0_enter", enter);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_0_exit", exit);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_180_enter", enter);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_180_exit", exit);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_minus_90_enter", enter);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_minus_90_exit", exit);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_plus_90_enter", enter);
MainModule.resHooks.setResReplacement("android", "anim", "screen_rotate_plus_90_exit", exit);
}
public static void RotationAnimatinoHook(LoadPackageParam lpparam) {
MethodHook animEnter = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_rotateanim", "1"));
Animation anim = (Animation)param.getResult();
if (opt == 2) {
anim.setDuration(0);
param.setResult(anim);
} else if (opt == 3) {
Animation alphaAnim = new AlphaAnimation(1.0f, 1.0f);
alphaAnim.setInterpolator((Interpolator)XposedHelpers.getStaticObjectField(XposedHelpers.findClass("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader), "QUART_EASE_OUT_INTERPOLATOR"));
alphaAnim.setDuration(300);
alphaAnim.setFillAfter(true);
alphaAnim.setFillBefore(true);
alphaAnim.setFillEnabled(true);
param.setResult(alphaAnim);
}
}
};
MethodHook animExit = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_rotateanim", "1"));
Animation anim = (Animation)param.getResult();
if (opt == 2) {
anim.setDuration(0);
} else if (opt == 3) {
AlphaAnimation alphaAnim = new AlphaAnimation(1.0f, 0.0f);
alphaAnim.setInterpolator((Interpolator)XposedHelpers.getStaticObjectField(XposedHelpers.findClass("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader), "QUART_EASE_OUT_INTERPOLATOR"));
alphaAnim.setDuration(300);
alphaAnim.setFillAfter(true);
alphaAnim.setFillBefore(true);
alphaAnim.setFillEnabled(true);
param.setResult(alphaAnim);
}
}
};
Helpers.findAndHookMethod("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader, "createRotation180Enter", animEnter);
Helpers.findAndHookMethod("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader, "createRotation180Exit", animExit);
Helpers.hookAllMethods("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader, "createRotationEnter", animEnter);
Helpers.hookAllMethods("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader, "createRotationEnterWithBackColor", animEnter);
Helpers.hookAllMethods("com.android.server.wm.ScreenRotationAnimationInjector", lpparam.classLoader, "createRotationExit", animExit);
}
public static void NoVersionCheckHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "checkDowngrade", XC_MethodReplacement.DO_NOTHING);
}
public static void ColorizedNotificationTitlesHook() {
Helpers.hookAllMethods("android.app.Notification.Builder", null, "bindNotificationHeader", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (!Helpers.isNougat()) try {
Object mN = XposedHelpers.getObjectField(param.thisObject, "mN");
if (mN != null)
if ((boolean)XposedHelpers.callMethod(mN, "isColorizedMedia")) return;
} catch (Throwable ignore) {}
RemoteViews rv = (RemoteViews)param.args[0];
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
int contrastColor;
if (Helpers.isQPlus())
contrastColor = (int)XposedHelpers.callMethod(param.thisObject, "resolveContrastColor", param.args[1]);
else
contrastColor = (int)XposedHelpers.callMethod(param.thisObject, "resolveContrastColor");
if (rv != null && mContext != null)
rv.setTextColor(mContext.getResources().getIdentifier("app_name_text", "id", "android"), contrastColor);
}
});
// Helpers.hookAllMethods("android.app.Notification.Builder", null, "bindHeaderAppName", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// XposedBridge.log("bindHeaderAppName");
// }
// });
//
// Helpers.findAndHookMethod("android.app.Notification.Builder", null, "bindHeaderAppName", RemoteViews.class, "android.app.Notification.StandardTemplateParams", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// XposedBridge.log("bindHeaderAppName2");
// }
// });
}
public static int abHeight = 39;
public static void CompactNotificationsRes() {
MainModule.resHooks.setDensityReplacement("android", "dimen", "notification_action_height", abHeight);
MainModule.resHooks.setDensityReplacement("android", "dimen", "android_notification_action_height", abHeight);
MainModule.resHooks.setDensityReplacement("android", "dimen", "notification_action_list_height", abHeight);
MainModule.resHooks.setDensityReplacement("com.android.systemui", "dimen", "notification_row_extra_padding", 0);
}
public static void CompactNotificationsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.notification.NotificationViewWrapper", lpparam.classLoader, "wrap", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (param.args.length > 3) return;
Object res = param.getResult();
if (res == null) return;
View mView = (View)XposedHelpers.getObjectField(res, "mView");
if (mView == null) return;
//if (mView.getId() != mView.getResources().getIdentifier("status_bar_latest_event_content", "id", "android")) return;
FrameLayout container = mView.findViewById(mView.getResources().getIdentifier("actions_container", "id", "android"));
if (container == null) return;
float density = mView.getResources().getDisplayMetrics().density;
int height = Math.round(density * abHeight);
ViewGroup actions = (ViewGroup)container.getChildAt(0);
FrameLayout.LayoutParams lp1 = (FrameLayout.LayoutParams)actions.getLayoutParams();
lp1.height = height;
actions.setLayoutParams(lp1);
actions.setPadding(0, 0, 0, 0);
for (int c = 0; c < actions.getChildCount(); c++) {
View button = actions.getChildAt(c);
ViewGroup.MarginLayoutParams lp2 = (ViewGroup.MarginLayoutParams)button.getLayoutParams();
lp2.height = height;
lp2.bottomMargin = 0;
lp2.topMargin = 0;
}
}
});
if (Helpers.is12()) {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View view = (View)param.args[0];
FrameLayout container = view.findViewById(view.getResources().getIdentifier("actions_container", "id", "android"));
if (container == null || container.getVisibility() != View.VISIBLE) return;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)view.getLayoutParams();
if ("MiuiStyleProcessor".equals(param.thisObject.getClass().getSimpleName())) {
float density = container.getResources().getDisplayMetrics().density;
lp.bottomMargin = Math.round(lp.bottomMargin * 0.666f);
ViewGroup.LayoutParams lpc = container.getLayoutParams();
lpc.height = Math.round(density * abHeight);
container.setLayoutParams(lpc);
} else {
lp.bottomMargin = 0;
}
view.setLayoutParams(lp);
}
};
Helpers.findAndHookMethod("com.android.systemui.statusbar.notification.NotificationTemplateViewWrapper$GoogleStyleProcessor", lpparam.classLoader, "setGoogleContentMargins", View.class, hook);
Helpers.findAndHookMethod("com.android.systemui.statusbar.notification.NotificationTemplateViewWrapper$MiuiStyleProcessor", lpparam.classLoader, "setMiuiContentMargins", View.class, hook);
}
}
public static void HideFromRecentsHook(LoadPackageParam lpparam) {
String taskRecordClass = Helpers.isQPlus() ? "com.android.server.wm.TaskRecord" : "com.android.server.am.TaskRecord";
Helpers.hookAllConstructors(taskRecordClass, lpparam.classLoader, new MethodHook() {
@Override
@SuppressLint("WrongConstant")
protected void after(final MethodHookParam param) throws Throwable {
//boolean mBooted = XposedHelpers.getBooleanField(param.args[0], "mBooted");
//if (!mBooted) return;
String pkgName = null;
ComponentName origActivity = (ComponentName)XposedHelpers.getObjectField(param.thisObject, "origActivity");
ComponentName realActivity = (ComponentName)XposedHelpers.getObjectField(param.thisObject, "realActivity");
String mCallingPackage = (String)XposedHelpers.getObjectField(param.thisObject, "mCallingPackage");
if (realActivity != null) pkgName = realActivity.getPackageName();
if (pkgName == null && origActivity != null) pkgName = origActivity.getPackageName();
if (pkgName == null) pkgName = mCallingPackage;
//Context mContext = (Context)XposedHelpers.getObjectField(param.args[0], "mContext");
//Set selectedApps = Helpers.getSharedStringSetPref(mContext, "pref_key_system_hidefromrecents_apps");
Set<String> selectedApps = MainModule.mPrefs.getStringSet("system_hidefromrecents_apps");
if (selectedApps.contains(pkgName)) {
Intent intent = (Intent)XposedHelpers.getObjectField(param.thisObject, "intent");
Intent affinityIntent = (Intent)XposedHelpers.getObjectField(param.thisObject, "affinityIntent");
if (intent != null) intent.addFlags(8388608);
if (affinityIntent != null) affinityIntent.addFlags(8388608);
}
}
});
}
private static final List<String> hookedTiles = new ArrayList<String>();
@SuppressLint("MissingPermission")
public static void QSHapticHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.qs.tileimpl.QSFactoryImpl", lpparam.classLoader, "createTileInternal", String.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Object tile = param.getResult();
if (tile == null) return;
String tileClass = tile.getClass().getCanonicalName();
if (!hookedTiles.contains(tileClass)) {
Helpers.findAndHookMethod(tileClass, lpparam.classLoader, "handleClick", new MethodHook(20) {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
boolean ignoreSystem = Helpers.getSharedBoolPref(mContext, "pref_key_system_qshaptics_ignore", false);
int opt = Integer.parseInt(Helpers.getSharedStringPref(mContext, "pref_key_system_qshaptics", "1"));
if (opt == 2)
Helpers.performLightVibration(mContext, ignoreSystem);
else if (opt == 3)
Helpers.performStrongVibration(mContext, ignoreSystem);
}
});
hookedTiles.add(tileClass);
}
}
});
}
public static void AutoGroupNotificationsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.notification.GroupHelper", lpparam.classLoader, "adjustAutogroupingSummary", int.class, String.class, String.class, boolean.class, new MethodHook() {
@Override
@SuppressWarnings({"unchecked", "SuspiciousMethodCalls"})
protected void before(final MethodHookParam param) throws Throwable {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_autogroupnotif", "1"));
if (opt == 2) {
param.setResult(null);
return;
}
Map<Integer, Map<String, LinkedHashSet<String>>> mUngroupedNotifications = (Map<Integer, Map<String, LinkedHashSet<String>>>)XposedHelpers.getObjectField(param.thisObject, "mUngroupedNotifications");
Map<String, LinkedHashSet<String>> obj = mUngroupedNotifications.get(param.args[0]);
if (obj != null) {
LinkedHashSet<String> list = obj.get(param.args[1]);
if (list != null && list.size() < opt) param.setResult(null);
}
}
});
Helpers.findAndHookMethod("com.android.server.notification.GroupHelper", lpparam.classLoader, "adjustNotificationBundling", List.class, boolean.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
List<?> list = (List<?>)param.args[0];
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_autogroupnotif", "1"));
if (opt == 2 || (list != null && list.size() < opt)) param.setResult(null);
}
});
}
public static void NoMoreIconHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationIconAreaController", lpparam.classLoader, "setIconsVisibility", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
Object mMoreIcon = XposedHelpers.getObjectField(param.thisObject, "mMoreIcon");
if (mMoreIcon != null) XposedHelpers.setBooleanField(param.thisObject, "mForceHideMoreIcon", true);
}
});
}
public static void ShowNotificationsAfterUnlockHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.miui.statusbar.ExpandedNotification", lpparam.classLoader, "hasShownAfterUnlock", XC_MethodReplacement.returnConstant(false));
Helpers.findAndHookMethod("com.android.systemui.miui.statusbar.ExpandedNotification", lpparam.classLoader, "setHasShownAfterUnlock", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
XposedHelpers.setBooleanField(param.thisObject, "mHasShownAfterUnlock", false);
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.notification.MiuiNotificationCompat", lpparam.classLoader, "isKeptOnKeyguard", Notification.class, XC_MethodReplacement.returnConstant(true));
}
private static int appInfoIconResId;
private static int forceCloseIconResId;
public static void NotificationRowMenuRes() {
appInfoIconResId = MainModule.resHooks.addResource("ic_appinfo", Helpers.is12()? R.drawable.ic_appinfo12 : R.drawable.ic_appinfo);
forceCloseIconResId = MainModule.resHooks.addResource("ic_forceclose", Helpers.is12()? R.drawable.ic_forceclose12 : R.drawable.ic_forceclose);
if (!Helpers.is12())
MainModule.resHooks.setDensityReplacement("com.android.systemui", "dimen", "notification_menu_icon_size", 36);
MainModule.resHooks.setDensityReplacement("com.android.systemui", "dimen", "notification_menu_icon_padding", 0);
}
public static void NotificationRowMenuHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationMenuRow", lpparam.classLoader, "createMenuViews", boolean.class, new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
ArrayList<Object> mMenuItems = (ArrayList<Object>)XposedHelpers.getObjectField(param.thisObject, "mMenuItems");
Class<?> nmiCls = findClass("com.android.systemui.statusbar.NotificationMenuRow.NotificationMenuItem", lpparam.classLoader);
Object infoBtn = null;
Object forceCloseBtn = null;
int nInfoResId = mContext.getResources().getIdentifier("notification_info", "layout", lpparam.packageName);
try {
infoBtn = XposedHelpers.newInstance(nmiCls, mContext, "Application info", nInfoResId, appInfoIconResId);
forceCloseBtn = XposedHelpers.newInstance(nmiCls, mContext, "Force close", nInfoResId, forceCloseIconResId);
} catch (Throwable t1) {
try {
infoBtn = XposedHelpers.newInstance(nmiCls, mContext, "Application info", LayoutInflater.from(mContext).inflate(nInfoResId, null, false), appInfoIconResId);
forceCloseBtn = XposedHelpers.newInstance(nmiCls, mContext, "Force close", LayoutInflater.from(mContext).inflate(nInfoResId, null, false), forceCloseIconResId);
} catch (Throwable t2) {
XposedBridge.log(t2);
}
}
if (infoBtn == null || forceCloseBtn == null) return;
mMenuItems.add(infoBtn);
mMenuItems.add(forceCloseBtn);
XposedHelpers.setObjectField(param.thisObject, "mMenuItems", mMenuItems);
FrameLayout mMenuContainer = (FrameLayout)XposedHelpers.getObjectField(param.thisObject, "mMenuContainer");
if (mMenuContainer != null)
if (Helpers.is12()) {
View mInfoBtn = (View)XposedHelpers.callMethod(infoBtn, "getMenuView");
View mForceCloseBtn = (View)XposedHelpers.callMethod(forceCloseBtn, "getMenuView");
mInfoBtn.setOnClickListener((View.OnClickListener)param.thisObject);
mForceCloseBtn.setOnClickListener((View.OnClickListener)param.thisObject);
XposedHelpers.callMethod(mMenuContainer, "addMenuView", mInfoBtn);
XposedHelpers.callMethod(mMenuContainer, "addMenuView",mForceCloseBtn);
} else {
XposedHelpers.callMethod(param.thisObject, "addMenuView", infoBtn, mMenuContainer);
XposedHelpers.callMethod(param.thisObject, "addMenuView", forceCloseBtn, mMenuContainer);
//XposedHelpers.callMethod(param.thisObject, "setMenuLocation");
}
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationMenuRow", lpparam.classLoader, "onClick", View.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
View view = (View)param.args[0];
if (view == null || view.getTag() == null || !(view.getTag() instanceof Integer)) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Object mParent = XposedHelpers.getObjectField(param.thisObject, "mParent");
Object notification = XposedHelpers.callMethod(mParent, "getStatusBarNotification");
String pkgName = (String)XposedHelpers.callMethod(notification, "getPackageName");
int uid = (int)XposedHelpers.callMethod(notification, "getAppUid");
int user = 0;
try {
user = (int)XposedHelpers.callStaticMethod(UserHandle.class, "getUserId", uid);
} catch (Throwable t) {
XposedBridge.log(t);
}
int iconResId = (int)view.getTag();
if (iconResId == appInfoIconResId) {
param.setResult(null);
Helpers.openAppInfo(mContext, pkgName, user);
mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
} else if (iconResId == forceCloseIconResId) {
param.setResult(null);
ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
if (user != 0)
XposedHelpers.callMethod(am, "forceStopPackageAsUser", pkgName, user);
else
XposedHelpers.callMethod(am, "forceStopPackage", pkgName);
CharSequence appName = pkgName;
try {
appName = mContext.getPackageManager().getApplicationLabel(mContext.getPackageManager().getApplicationInfo(pkgName, 0));
} catch (Throwable ignore) {}
Toast.makeText(mContext, Helpers.getModuleRes(mContext).getString(R.string.force_closed, appName), Toast.LENGTH_SHORT).show();
}
}
});
if (!Helpers.is12()) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationMenuRow", lpparam.classLoader, "onHeightUpdate", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
FrameLayout mMenuContainer = (FrameLayout)XposedHelpers.getObjectField(param.thisObject, "mMenuContainer");
if (mMenuContainer != null) mMenuContainer.setTranslationY(0);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationMenuRow", lpparam.classLoader, "setMenuLocation", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
param.setResult(null);
float mHorizSpaceForIcon = XposedHelpers.getFloatField(param.thisObject, "mHorizSpaceForIcon");
boolean mSnapping = XposedHelpers.getBooleanField(param.thisObject, "mSnapping");
FrameLayout mMenuContainer = (FrameLayout)XposedHelpers.getObjectField(param.thisObject, "mMenuContainer");
Object mParent = XposedHelpers.getObjectField(param.thisObject, "mParent");
if (mMenuContainer == null || mParent == null) return;
int width = (int)XposedHelpers.callMethod(mParent, "getWidth");
int height = (int)XposedHelpers.callMethod(mParent, "getIntrinsicHeight");
boolean hasExtraTopPadding = (boolean)XposedHelpers.callMethod(mParent, "hasExtraTopPadding");
int extraTopPadding = hasExtraTopPadding ? (int)XposedHelpers.callMethod(mParent, "getPaddingTop") : 0;
float density = mMenuContainer.getResources().getDisplayMetrics().density;
float padding = 10 * density;
float startingHeight = height / 2.0f - mHorizSpaceForIcon - padding - extraTopPadding;
Object sbNotification = XposedHelpers.callMethod(mParent, "getStatusBarNotification");
int mImportance = XposedHelpers.getIntField(sbNotification, "mImportance");
if (!mSnapping && mMenuContainer.isAttachedToWindow()) {
int childCount = mMenuContainer.getChildCount();
int row = 0;
int col = 0;
if (mImportance == 1) mHorizSpaceForIcon = 24 * density;
for (int i = 0; i < childCount; i++)
if (mImportance == 1) {
View childAt = mMenuContainer.getChildAt(i);
childAt.setX((float)width - padding - (mHorizSpaceForIcon + padding) * (col + 1));
childAt.setY(height / 2.0f - mHorizSpaceForIcon / 2.0f - padding / 2.0f - extraTopPadding);
col++;
} else {
View childAt = mMenuContainer.getChildAt(i);
childAt.setX((float)width - (mHorizSpaceForIcon + (col == 0 ? 2 * padding : 1.5f * padding)) * (col + 1));
childAt.setY(startingHeight + mHorizSpaceForIcon * row + padding);
col++;
if (i % 2 == 1) {
col = 0;
row++;
}
}
}
}
});
}
}
@SuppressWarnings("unchecked")
private static boolean checkVibration(String pkgName, Object thisObject) {
try {
int opt = (int)XposedHelpers.getAdditionalInstanceField(thisObject, "mVibrationMode");
Set<String> selectedApps = (Set<String>)XposedHelpers.getAdditionalInstanceField(thisObject, "mVibrationApps");
boolean isSelected = selectedApps != null && selectedApps.contains(pkgName);
return opt == 2 && !isSelected || opt == 3 && isSelected;
} catch (Throwable t) {
XposedBridge.log(t);
return false;
}
}
public static void SelectiveVibrationHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.VibratorService", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = new Handler(mContext.getMainLooper());
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mVibrationMode", Integer.parseInt(MainModule.mPrefs.getString("system_vibration", "1")));
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_vibration", "1") {
@Override
public void onChange(String name, String defValue) {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mVibrationMode", Integer.parseInt(Helpers.getSharedStringPref(mContext, name, defValue)));
}
};
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mVibrationApps", MainModule.mPrefs.getStringSet("system_vibration_apps"));
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_vibration_apps") {
@Override
public void onChange(String name) {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mVibrationApps", Helpers.getSharedStringSetPref(mContext, name));
}
};
}
});
Helpers.hookAllMethods("com.android.server.VibratorService", lpparam.classLoader, "vibrate", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
//XposedBridge.log(Arrays.toString(new Throwable().getStackTrace()));
String pkgName = (String)param.args[1];
if (pkgName == null) return;
if (checkVibration(pkgName, param.thisObject)) param.setResult(null);
}
});
if (Helpers.isNougat())
Helpers.hookAllMethods("com.android.server.VibratorService", lpparam.classLoader, "vibratePattern", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
String pkgName = (String)param.args[1];
if (pkgName == null) return;
if (checkVibration(pkgName, param.thisObject)) param.setResult(null);
}
});
}
public static void QQSGridRes() {
int cols = MainModule.mPrefs.getInt("system_qqsgridcolumns", 2);
int colsResId = R.integer.quick_quick_settings_num_rows_5;
switch (cols) {
case 3: colsResId = R.integer.quick_quick_settings_num_rows_3; break;
case 4: colsResId = R.integer.quick_quick_settings_num_rows_4; break;
case 5: colsResId = R.integer.quick_quick_settings_num_rows_5; break;
case 6: colsResId = R.integer.quick_quick_settings_num_rows_6; break;
case 7: colsResId = R.integer.quick_quick_settings_num_rows_7; break;
}
MainModule.resHooks.setObjectReplacement("com.android.systemui", "integer", "quick_settings_qqs_count_portrait", cols);
MainModule.resHooks.setResReplacement("com.android.systemui", "integer", "quick_settings_qqs_count", colsResId);
}
public static void QSGridRes() {
int cols = MainModule.mPrefs.getInt("system_qsgridcolumns", 2);
int rows = MainModule.mPrefs.getInt("system_qsgridrows", 1);
int colsRes = R.integer.quick_settings_num_columns_3;
int rowsRes = R.integer.quick_settings_num_rows_4;
switch (cols) {
case 3: colsRes = R.integer.quick_settings_num_columns_3; break;
case 4: colsRes = R.integer.quick_settings_num_columns_4; break;
case 5: colsRes = R.integer.quick_settings_num_columns_5; break;
case 6: colsRes = R.integer.quick_settings_num_columns_6; break;
case 7: colsRes = R.integer.quick_settings_num_columns_7; break;
}
switch (rows) {
case 2: rowsRes = R.integer.quick_settings_num_rows_2; break;
case 3: rowsRes = R.integer.quick_settings_num_rows_3; break;
case 4: rowsRes = R.integer.quick_settings_num_rows_4; break;
case 5: rowsRes = R.integer.quick_settings_num_rows_5; break;
}
if (cols > 2) MainModule.resHooks.setResReplacement("com.android.systemui", "integer", "quick_settings_num_columns", colsRes);
if (rows > 1) MainModule.resHooks.setResReplacement("com.android.systemui", "integer", "quick_settings_num_rows", rowsRes);
}
private static void updateLabelsVisibility(Object mRecord, int mRows, int orientation) {
if (mRecord == null) return;
Object tileView = XposedHelpers.getObjectField(mRecord, "tileView");
if (tileView != null) {
ViewGroup mLabelContainer = (ViewGroup)XposedHelpers.getObjectField(tileView, "mLabelContainer");
if (mLabelContainer != null)
mLabelContainer.setVisibility(
MainModule.mPrefs.getBoolean("system_qsnolabels") ||
orientation == Configuration.ORIENTATION_PORTRAIT && mRows >= 5 ||
orientation == Configuration.ORIENTATION_LANDSCAPE && mRows >= 3 ? View.GONE : View.VISIBLE
);
}
}
public static void QSGridLabelsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.qs.TileLayout", lpparam.classLoader, "addTile", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
updateLabelsVisibility(param.args[0], XposedHelpers.getIntField(param.thisObject, "mRows"), ((ViewGroup)param.thisObject).getResources().getConfiguration().orientation);
}
});
Helpers.hookAllMethods("com.android.systemui.qs.PagedTileLayout", lpparam.classLoader, "addTile", new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void before(MethodHookParam param) throws Throwable {
ArrayList<Object> mPages = (ArrayList<Object>)XposedHelpers.getObjectField(param.thisObject, "mPages");
if (mPages == null) return;
int mRows = 0;
if (mPages.size() > 0) mRows = XposedHelpers.getIntField(mPages.get(0), "mRows");
updateLabelsVisibility(param.args[0], mRows, ((ViewGroup)param.thisObject).getResources().getConfiguration().orientation);
}
});
Helpers.findAndHookMethod("com.android.systemui.qs.TileLayout", lpparam.classLoader, "updateResources", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (MainModule.mPrefs.getInt("system_qsgridrows", 1) != 2) return;
if (!(boolean)param.getResult()) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (mContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) return;
XposedHelpers.setIntField(param.thisObject, "mContentHeight", Math.round(XposedHelpers.getIntField(param.thisObject, "mContentHeight") / 1.5f));
((ViewGroup)param.thisObject).requestLayout();
}
});
if (MainModule.mPrefs.getInt("system_qsgridrows", 1) == 4)
Helpers.findAndHookMethod("com.android.systemui.qs.tileimpl.QSTileView", lpparam.classLoader, "createLabel", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ViewGroup mLabelContainer = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mLabelContainer");
if (mLabelContainer != null) mLabelContainer.setPadding(
mLabelContainer.getPaddingLeft(),
Math.round(mLabelContainer.getResources().getDisplayMetrics().density * 2),
mLabelContainer.getPaddingRight(),
mLabelContainer.getPaddingBottom()
);
}
});
}
public static void NoDuckingHook(LoadPackageParam lpparam) {
//Helpers.hookAllMethods("com.android.server.audio.PlaybackActivityMonitor", lpparam.classLoader, "duckPlayers", XC_MethodReplacement.returnConstant(true));
//Helpers.hookAllMethods("com.android.server.audio.PlaybackActivityMonitor$DuckingManager", lpparam.classLoader, "addDuck", XC_MethodReplacement.DO_NOTHING);
Helpers.hookAllMethods("com.android.server.audio.FocusRequester", lpparam.classLoader, "handleFocusLoss", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if ((int)param.args[0] == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) param.setResult(null);
}
});
}
public static void OrientationLockHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_qs_autorotate_state", 0) {
@Override
public void onChange(String name, int defValue) {
MainModule.mPrefs.put(name, Helpers.getSharedIntPref(mContext, name, defValue));
}
};
}
});
String windowClass = Helpers.isQPlus() ? "com.android.server.wm.DisplayRotation" : "com.android.server.policy.PhoneWindowManager";
String rotMethod = Helpers.isQPlus() ? "rotationForOrientation" : "rotationForOrientationLw";
Helpers.hookAllMethods(windowClass, lpparam.classLoader, rotMethod, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
//Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
//Helpers.log("rotationForOrientationLw: " + param.args[0] + ", " + param.args[1] + " = " + param.getResult());
if ((int)param.args[0] == -1) {
int opt = MainModule.mPrefs.getInt("qs_autorotate_state", 0);
int prevOrient = (int)param.args[1];
if (opt == 1) {
if (prevOrient != 0 && prevOrient != 2) prevOrient = 0;
if ((int)param.getResult() == 1 || (int)param.getResult() == 3) param.setResult(prevOrient);
} else if (opt == 2) {
if (prevOrient != 1 && prevOrient != 3) prevOrient = 1;
if ((int)param.getResult() == 0 || (int)param.getResult() == 2) param.setResult(prevOrient);
}
}
}
});
}
public static void StatusBarHeightRes() {
int opt = MainModule.mPrefs.getInt("system_statusbarheight", 19);
int heightDpi = opt == 19 ? 27 : opt;
MainModule.resHooks.setDensityReplacement("*", "dimen", "status_bar_height", heightDpi);
MainModule.resHooks.setDensityReplacement("*", "dimen", "status_bar_height_portrait", heightDpi);
MainModule.resHooks.setDensityReplacement("*", "dimen", "status_bar_height_landscape", heightDpi);
}
private static void applyHeight(Object thisObject) {
if (thisObject == null) return;
ViewGroup view = (ViewGroup)thisObject;
ViewGroup.LayoutParams lp = view.getLayoutParams();
Resources res = view.getResources();
lp.height = res.getDimensionPixelSize(res.getIdentifier("status_bar_height", "dimen", "android"));
view.setLayoutParams(lp);
}
public static void StatusBarHeightHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.KeyguardStatusBarView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
applyHeight(param.thisObject);
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.PhoneStatusBarView", lpparam.classLoader, "setBar", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
applyHeight(param.thisObject);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
try {
ViewGroup mSignalDualNotchGroup = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mSignalDualNotchGroup");
applyHeight(mSignalDualNotchGroup.findViewById(mSignalDualNotchGroup.getResources().getIdentifier("notch_mobile", "id", lpparam.packageName)));
} catch (Throwable t) {
XposedBridge.log(t);
}
try {
ViewGroup mSignalSimpleDualMobileContainer = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mSignalSimpleDualMobileContainer");
applyHeight(mSignalSimpleDualMobileContainer);
} catch (Throwable ignore) {}
}
});
}
@SuppressWarnings("ConstantConditions")
public static void HideMemoryCleanHook(LoadPackageParam lpparam, boolean isInLauncher) {
String raClass = isInLauncher ? "com.miui.home.recents.views.RecentsContainer" : "com.android.systemui.recents.RecentsActivity";
if (isInLauncher && findClassIfExists(raClass, lpparam.classLoader) == null) return;
Helpers.findAndHookMethod(raClass, lpparam.classLoader, "setupVisible", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ViewGroup mMemoryAndClearContainer = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mMemoryAndClearContainer");
if (mMemoryAndClearContainer != null) mMemoryAndClearContainer.setVisibility(View.GONE);
}
});
}
public static void ExtendedPowerMenuHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.server.policy.MiuiGlobalActions", lpparam.classLoader, new MethodHook() {
@Override
@SuppressWarnings("ResultOfMethodCallIgnored")
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
String powermenuPath = Helpers.getCacheFilePath("extended_power_menu");
File powermenu = powermenuPath == null ? null : new File(powermenuPath);
if (powermenu == null) {
Helpers.log("ExtendedPowerMenuHook", "No writable path found!");
return;
}
if (powermenu.exists()) powermenu.delete();
InputStream inputStream;
FileOutputStream outputStream;
byte[] fileBytes;
Resources resources = Helpers.getModuleRes(mContext);
inputStream = resources.openRawResource(resources.getIdentifier("extended_power_menu", "raw", Helpers.modulePkg));
fileBytes = new byte[inputStream.available()];
inputStream.read(fileBytes);
outputStream = new FileOutputStream(powermenu);
outputStream.write(fileBytes);
outputStream.close();
inputStream.close();
if (!powermenu.exists()) {
Helpers.log("ExtendedPowerMenuHook", "MAML file not found in cache");
return;
}
Class<?> ResourceManager = XposedHelpers.findClass("miui.maml.ResourceManager", lpparam.classLoader);
Class<?> ZipResourceLoader = XposedHelpers.findClass("miui.maml.util.ZipResourceLoader", lpparam.classLoader);
Class<?> ScreenContext = XposedHelpers.findClass("miui.maml.ScreenContext", lpparam.classLoader);
Class<?> ScreenElementRoot = XposedHelpers.findClass("miui.maml.ScreenElementRoot", lpparam.classLoader);
XposedHelpers.setObjectField(param.thisObject, "mResourceManager", XposedHelpers.newInstance(ResourceManager, XposedHelpers.newInstance(ZipResourceLoader, powermenu.getPath())));
Object mResourceManager = XposedHelpers.getObjectField(param.thisObject, "mResourceManager");
Object mScreenElementRoot = XposedHelpers.newInstance(ScreenElementRoot, XposedHelpers.newInstance(ScreenContext, mContext, mResourceManager));
XposedHelpers.setObjectField(param.thisObject, "mScreenElementRoot", mScreenElementRoot);
XposedHelpers.callMethod(mScreenElementRoot, "setOnExternCommandListener", XposedHelpers.getObjectField(param.thisObject, "mCommandListener"));
XposedHelpers.callMethod(mScreenElementRoot, "setKeepResource", true);
XposedHelpers.callMethod(mScreenElementRoot, "load");
XposedHelpers.callMethod(mScreenElementRoot, "init");
}
});
}
public static void ExtendedPowerMenuHook() {
Helpers.findAndHookMethod("miui.maml.ScreenElementRoot", null, "issueExternCommand", String.class, Double.class, String.class, new MethodHook() {
@Override
@SuppressLint("MissingPermission")
protected void before(MethodHookParam param) throws Throwable {
String cmd = (String)param.args[0];
Object scrContext = XposedHelpers.getObjectField(param.thisObject, "mContext");
Context mContext = (Context)XposedHelpers.getObjectField(scrContext, "mContext");
// Handler mHandler = (Handler)XposedHelpers.getObjectField(scrContext, "mHandler");
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
Object mService = XposedHelpers.getObjectField(pm, "mService");
Object mSystemExternCommandListener = XposedHelpers.getObjectField(param.thisObject, "mSystemExternCommandListener");
boolean custom = false;
if ("recovery".equals(cmd)) {
XposedHelpers.callMethod(mService, "reboot", false, "recovery", false);
custom = true;
} else if ("bootloader".equals(cmd)) {
XposedHelpers.callMethod(mService, "reboot", false, "bootloader", false);
custom = true;
} else if ("softreboot".equals(cmd)) {
SystemProperties.set("ctl.restart", "surfaceflinger");
SystemProperties.set("ctl.restart", "zygote");
custom = true;
} else if ("killsysui".equals(cmd)) {
mContext.sendBroadcast(new Intent(ACTION_PREFIX + "RestartSystemUI"));
// final WallpaperManager wm = (WallpaperManager)mContext.getSystemService(Context.WALLPAPER_SERVICE);
// Drawable drawable = wm.getDrawable();
// ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
// XposedHelpers.callMethod(am, "forceStopPackage", "com.android.systemui");
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// if (drawable != null && drawable.getClass() == BitmapDrawable.class) try {
// wm.setBitmap(((BitmapDrawable)drawable).getBitmap());
// } catch (Throwable t) {
// XposedBridge.log(t);
// }
// }
// }, 1000);
custom = true;
} else if ("killlauncher".equals(cmd)) {
ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
ResolveInfo launcherInfo = mContext.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (launcherInfo != null) {
String pkgName = launcherInfo.activityInfo.packageName;
if (pkgName != null) XposedHelpers.callMethod(am, "forceStopPackage", pkgName);
}
custom = true;
}
if (custom) {
if (mSystemExternCommandListener != null) XposedHelpers.callMethod(mSystemExternCommandListener, "onCommand", param.args[0], param.args[1], param.args[2]);
param.setResult(null);
}
}
});
}
public static void HideDismissViewHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "inflateDismissView", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mDismissView = (View)XposedHelpers.getObjectField(param.thisObject, "mDismissView");
if (mDismissView != null) mDismissView.setVisibility(View.GONE);
}
});
if (!Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "updateDismissView", boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mDismissView = (View)XposedHelpers.getObjectField(param.thisObject, "mDismissView");
if (mDismissView != null) mDismissView.setVisibility(View.GONE);
}
})) Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "updateDismissView", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mDismissView = (View)XposedHelpers.getObjectField(param.thisObject, "mDismissView");
if (mDismissView != null) mDismissView.setVisibility(View.GONE);
}
});
}
public static void ReplaceShortcutAppHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.HeaderView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mShortcut = (View)XposedHelpers.getObjectField(param.thisObject, "mShortcut");
mShortcut.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int user = Helpers.getSharedIntPref(v.getContext(), "pref_key_system_shortcut_app_user", 0);
String pkgAppName = Helpers.getSharedStringPref(v.getContext(), "pref_key_system_shortcut_app", "");
if (pkgAppName == null || pkgAppName.equals("")) try {
View.OnClickListener mOnClickListener = (View.OnClickListener)XposedHelpers.getObjectField(param.thisObject, "mOnClickListener");
if (mOnClickListener != null) mOnClickListener.onClick(v);
} catch (Throwable t) {
XposedHelpers.callMethod(param.thisObject, "onClick", v);
}
String[] pkgAppArray = pkgAppName.split("\\|");
if (pkgAppArray.length < 2) return;
ComponentName name = new ComponentName(pkgAppArray[0], pkgAppArray[1]);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setComponent(name);
Object mActStarter = XposedHelpers.getObjectField(param.thisObject, "mActStarter");
if (user != 0) try {
XposedHelpers.callMethod(mActStarter, "collapsePanels");
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
XposedHelpers.callMethod(mContext, "startActivityAsUser", intent, XposedHelpers.newInstance(UserHandle.class, user));
} catch (Throwable t) {
XposedBridge.log(t);
} else {
XposedHelpers.callMethod(mActStarter, "startActivity", intent, true);
}
}
});
}
});
}
public static void ReplaceClockAppHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.HeaderView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mClock = (View)XposedHelpers.getObjectField(param.thisObject, "mClock");
View mDateView = (View)XposedHelpers.getObjectField(param.thisObject, "mDateView");
View mView = mClock.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? mDateView : mClock;
mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int user = Helpers.getSharedIntPref(v.getContext(), "pref_key_system_clock_app_user", 0);
String pkgAppName = Helpers.getSharedStringPref(v.getContext(), "pref_key_system_clock_app", "");
if (pkgAppName == null || pkgAppName.equals("")) try {
View.OnClickListener mOnClickListener = (View.OnClickListener)XposedHelpers.getObjectField(param.thisObject, "mOnClickListener");
if (mOnClickListener != null) mOnClickListener.onClick(v);
} catch (Throwable t) {
XposedHelpers.callMethod(param.thisObject, "onClick", v);
}
String[] pkgAppArray = pkgAppName.split("\\|");
if (pkgAppArray.length < 2) return;
ComponentName name = new ComponentName(pkgAppArray[0], pkgAppArray[1]);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setComponent(name);
Object mActStarter = XposedHelpers.getObjectField(param.thisObject, "mActStarter");
if (user != 0) try {
XposedHelpers.callMethod(mActStarter, "collapsePanels");
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
XposedHelpers.callMethod(mContext, "startActivityAsUser", intent, XposedHelpers.newInstance(UserHandle.class, user));
} catch (Throwable t) {
XposedBridge.log(t);
} else {
XposedHelpers.callMethod(mActStarter, "startActivity", intent, true);
}
}
});
}
});
}
public static void ReplaceCalendarAppHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.HeaderView", lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mDateView = (View)XposedHelpers.getObjectField(param.thisObject, "mDateView");
if (mDateView.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) return;
mDateView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int user = Helpers.getSharedIntPref(v.getContext(), "pref_key_system_calendar_app_user", 0);
String pkgAppName = Helpers.getSharedStringPref(v.getContext(), "pref_key_system_calendar_app", "");
if (pkgAppName == null || pkgAppName.equals("")) try {
View.OnClickListener mOnClickListener = (View.OnClickListener)XposedHelpers.getObjectField(param.thisObject, "mOnClickListener");
if (mOnClickListener != null) mOnClickListener.onClick(v);
} catch (Throwable t) {
XposedHelpers.callMethod(param.thisObject, "onClick", v);
}
String[] pkgAppArray = pkgAppName.split("\\|");
if (pkgAppArray.length < 2) return;
ComponentName name = new ComponentName(pkgAppArray[0], pkgAppArray[1]);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
intent.setComponent(name);
Object mActStarter = XposedHelpers.getObjectField(param.thisObject, "mActStarter");
if (user != 0) try {
XposedHelpers.callMethod(mActStarter, "collapsePanels");
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
XposedHelpers.callMethod(mContext, "startActivityAsUser", intent, XposedHelpers.newInstance(UserHandle.class, user));
} catch (Throwable t) {
XposedBridge.log(t);
} else {
XposedHelpers.callMethod(mActStarter, "startActivity", intent, true);
}
}
});
}
});
}
private static final int NOCOLOR = 0x01010101;
private static int actionBarColor = NOCOLOR;
private static boolean isIgnored(Context context) {
return MainModule.mPrefs.getStringSet("system_statusbarcolor_apps").contains(context.getPackageName());
}
private static int getActionBarColor(Window window, int oldColor) {
if (actionBarColor != NOCOLOR) return actionBarColor;
TypedValue outValue = new TypedValue();
window.getContext().getTheme().resolveAttribute(android.R.attr.actionBarStyle, outValue, true);
TypedArray abStyle = window.getContext().getTheme().obtainStyledAttributes(outValue.resourceId, new int[] { android.R.attr.background });
Drawable bg = abStyle.getDrawable(0);
abStyle.recycle();
if (bg instanceof ColorDrawable)
return ((ColorDrawable)bg).getColor();
else
return oldColor;
}
@SuppressWarnings("unchecked")
private static void hookToolbar(Object thisObject, Drawable bg) {
if (!(bg instanceof ColorDrawable)) return;
actionBarColor = ((ColorDrawable)bg).getColor();
Object mDecorToolbar = XposedHelpers.getObjectField(thisObject, "mDecorToolbar");
ViewGroup mToolbar = (ViewGroup)XposedHelpers.getObjectField(mDecorToolbar, "mToolbar");
Context mDecorContext = mToolbar.getRootView().getContext();
if (mDecorContext != null) {
WeakReference<Context> mActivityContext = (WeakReference<Context>)XposedHelpers.getObjectField(mDecorContext, "mActivityContext");
Context mContext = mActivityContext.get();
if (mContext != null && !isIgnored(mContext))
((Activity)mContext).getWindow().setStatusBarColor(actionBarColor);
}
}
private static void hookWindowDecor(Object thisObject, Drawable bg) {
if (!(bg instanceof ColorDrawable)) return;
actionBarColor = ((ColorDrawable)bg).getColor();
Activity mActivity = (Activity)XposedHelpers.getObjectField(thisObject, "mActivity");
if (mActivity != null && !isIgnored(mActivity))
mActivity.getWindow().setStatusBarColor(actionBarColor);
}
public static void StatusBarBackgroundHook() {
Helpers.findAndHookMethod("com.android.internal.policy.PhoneWindow", null, "generateLayout", "com.android.internal.policy.DecorView", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Window wnd = (Window)param.thisObject;
if (isIgnored(wnd.getContext())) return;
int mStatusBarColor = XposedHelpers.getIntField(param.thisObject, "mStatusBarColor");
if (mStatusBarColor == -16777216) return;
int newColor = getActionBarColor(wnd, mStatusBarColor);
if (newColor != mStatusBarColor)
XposedHelpers.callMethod(param.thisObject, "setStatusBarColor", newColor);
}
});
Helpers.findAndHookMethod("com.android.internal.policy.PhoneWindow", null, "setStatusBarColor", int.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Window wnd = (Window)param.thisObject;
if (isIgnored(wnd.getContext())) return;
if (actionBarColor != NOCOLOR) param.args[0] = actionBarColor;
else if (Color.alpha((int)param.args[0]) < 255) param.args[0] = Color.TRANSPARENT;
}
});
Helpers.findAndHookMethod("com.android.internal.app.ToolbarActionBar", null, "setBackgroundDrawable", Drawable.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookToolbar(param.thisObject, (Drawable)param.args[0]);
}
});
Helpers.findAndHookMethod("com.android.internal.app.WindowDecorActionBar", null, "setBackgroundDrawable", Drawable.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookWindowDecor(param.thisObject, (Drawable)param.args[0]);
}
});
}
public static void StatusBarBackgroundCompatHook(LoadPackageParam lpparam) {
boolean androidx = false;
// androidx
Method sbdMethod = null;
Class<?> tabCls = findClassIfExists("androidx.appcompat.app.ToolbarActionBar", lpparam.classLoader);
if (tabCls != null) sbdMethod = findMethodExactIfExists(tabCls, "setBackgroundDrawable", Drawable.class);
if (sbdMethod != null) androidx = true;
if (sbdMethod != null)
Helpers.hookMethod(sbdMethod, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookToolbar(param.thisObject, (Drawable)param.args[0]);
}
});
sbdMethod = null;
Class<?> wdabCls = findClassIfExists("androidx.appcompat.app.WindowDecorActionBar", lpparam.classLoader);
if (wdabCls != null) sbdMethod = findMethodExactIfExists(wdabCls, "setBackgroundDrawable", Drawable.class);
if (sbdMethod != null) androidx = true;
if (sbdMethod != null)
Helpers.hookMethod(sbdMethod, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookWindowDecor(param.thisObject, (Drawable)param.args[0]);
}
});
// old appcompat lib
if (!androidx) {
sbdMethod = null;
Class<?> tabv7Cls = findClassIfExists("android.support.v7.internal.app.ToolbarActionBar", lpparam.classLoader);
if (tabv7Cls != null) sbdMethod = findMethodExactIfExists(tabv7Cls, "setBackgroundDrawable", Drawable.class);
if (sbdMethod != null)
Helpers.hookMethod(sbdMethod, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookToolbar(param.thisObject, (Drawable)param.args[0]);
}
});
sbdMethod = null;
Class<?> wdabv7Cls = findClassIfExists("android.support.v7.internal.app.WindowDecorActionBar", lpparam.classLoader);
if (wdabv7Cls != null) sbdMethod = findMethodExactIfExists(wdabv7Cls, "setBackgroundDrawable", Drawable.class);
if (sbdMethod != null)
Helpers.hookMethod(sbdMethod, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
hookWindowDecor(param.thisObject, (Drawable)param.args[0]);
}
});
}
}
private static boolean checkToast(Context mContext, String pkgName) {
try {
int opt = Integer.parseInt(Helpers.getSharedStringPref(mContext, "pref_key_system_blocktoasts", "1"));
Set<String> selectedApps = Helpers.getSharedStringSetPref(mContext, "pref_key_system_blocktoasts_apps");
boolean isSelected = selectedApps != null && selectedApps.contains(pkgName);
return opt == 2 && !isSelected || opt == 3 && isSelected;
} catch (Throwable t) {
XposedBridge.log(t);
return false;
}
}
public static void SelectiveToastsHook() {
Helpers.findAndHookMethod("android.widget.Toast", null, "show", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
String pkgName = (String)XposedHelpers.callMethod(mContext, "getOpPackageName");
if (pkgName == null) return;
if (checkToast(mContext, pkgName)) param.setResult(null);
}
});
}
@SuppressWarnings("ConstantConditions")
public static void CustomRecommendedHook(LoadPackageParam lpparam, boolean isInLauncher) {
String rrvClass = isInLauncher ? "com.miui.home.recents.views.RecentsRecommendView" : "com.android.systemui.recents.views.RecentsRecommendView";
if (isInLauncher && findClassIfExists(rrvClass, lpparam.classLoader) == null) return;
Helpers.findAndHookConstructor(rrvClass, lpparam.classLoader, Context.class, AttributeSet.class, int.class, int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
Handler mHandler = new Handler(mContext.getMainLooper());
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if (key.contains("pref_key_system_recommended"))
XposedHelpers.callMethod(param.thisObject, "onFinishInflate");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.findAndHookMethod(rrvClass, lpparam.classLoader, "initItem", int.class, int.class, int.class, new MethodHook() {
@Override
@SuppressLint("WrongConstant")
protected void after(MethodHookParam param) throws Throwable {
LinearLayout view = (LinearLayout)param.thisObject;
Context context = view.getContext();
Resources resources = view.getResources();
Resources modRes = Helpers.getModuleRes(context);
int itemFirstResId = resources.getIdentifier("first_item", "id", lpparam.packageName);
int itemSecondResId = resources.getIdentifier("second_item", "id", lpparam.packageName);
int itemThirdResId = resources.getIdentifier("third_item", "id", lpparam.packageName);
int itemFourthResId = resources.getIdentifier("fourth_item", "id", lpparam.packageName);
int itemIconResId = resources.getIdentifier("item_icon", "id", lpparam.packageName);
int itemTitleResId = resources.getIdentifier("item_title", "id", lpparam.packageName);
int action = 1;
String title = null;
if ((int)param.args[0] == itemFirstResId) {
action = Helpers.getSharedIntPref(context, "pref_key_system_recommended_first_action", 1);
title = Helpers.getActionName(context, "pref_key_system_recommended_first");
} else if ((int)param.args[0] == itemSecondResId) {
action = Helpers.getSharedIntPref(context, "pref_key_system_recommended_second_action", 1);
title = Helpers.getActionName(context, "pref_key_system_recommended_second");
} else if ((int)param.args[0] == itemThirdResId) {
action = Helpers.getSharedIntPref(context, "pref_key_system_recommended_third_action", 1);
title = Helpers.getActionName(context, "pref_key_system_recommended_third");
} else if ((int)param.args[0] == itemFourthResId) {
action = Helpers.getSharedIntPref(context, "pref_key_system_recommended_fourth_action", 1);
title = Helpers.getActionName(context, "pref_key_system_recommended_fourth");
}
if (action <= 1) return;
int icon = R.drawable.recents_icon_custom;
if (action == 8 || action == 9 || action == 20) icon = R.drawable.recents_icon_launch;
else if (action == 10) icon = R.drawable.recents_icon_toggle;
View item = view.findViewById((int)param.args[0]);
ImageView item_icon = item.findViewById(itemIconResId);
item_icon.setMinimumWidth(item_icon.getDrawable().getIntrinsicWidth());
item_icon.setMinimumHeight(item_icon.getDrawable().getIntrinsicHeight());
item_icon.setImageDrawable(modRes.getDrawable(icon, view.getContext().getTheme()));
TextView item_title = item.findViewById(itemTitleResId);
item_title.setText(title == null ? "-" : title);
if (((String)item_title.getText()).contains(" ")) {
item_title.setSingleLine(false);
item_title.setMaxLines(2);
} else {
item_title.setMaxLines(1);
item_title.setSingleLine(true);
}
item_title.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY);
item_title.setEllipsize(TextUtils.TruncateAt.END);
}
});
Helpers.findAndHookMethod(rrvClass, lpparam.classLoader, "onClick", View.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
View view = ((View)param.args[0]);
if (view == null) return;
Context context = view.getContext();
Resources resources = view.getResources();
int itemFirstResId = resources.getIdentifier("first_item", "id", lpparam.packageName);
int itemSecondResId = resources.getIdentifier("second_item", "id", lpparam.packageName);
int itemThirdResId = resources.getIdentifier("third_item", "id", lpparam.packageName);
int itemFourthResId = resources.getIdentifier("fourth_item", "id", lpparam.packageName);
String key = null;
if (view.getId() == itemFirstResId)
key = "pref_key_system_recommended_first";
else if (view.getId() == itemSecondResId)
key = "pref_key_system_recommended_second";
else if (view.getId() == itemThirdResId)
key = "pref_key_system_recommended_third";
else if (view.getId() == itemFourthResId)
key = "pref_key_system_recommended_fourth";
int action = Helpers.getSharedIntPref(context, key + "_action", 1);
if (action <= 1) return;
// Close recents after app/shortcut launch
if (action == 8 || action == 9 || action == 20) {
GlobalActions.IntentType intentType = GlobalActions.IntentType.APP;
if (action == 9)
intentType = GlobalActions.IntentType.SHORTCUT;
else if (action == 20)
intentType = GlobalActions.IntentType.ACTIVITY;
Intent intent = GlobalActions.getIntent(context, key, intentType, false);
if (intent != null) {
param.setResult(null);
TaskStackBuilder.create(context.getApplicationContext()).addNextIntentWithParentStack(intent).startActivities();
return;
}
}
// Do not close after other actions
if (GlobalActions.handleAction(context, key)) param.setResult(null);
}
});
}
public static void UnblockThirdLaunchersHook(LoadPackageParam lpparam) {
String thirdCls = Helpers.is11() ? "com.miui.securitycenter.provider.ThirdMonitorProvider" : "com.miui.securitycenter.provider.ThirdDesktopProvider";
Helpers.hookAllMethods(thirdCls, lpparam.classLoader, "call", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Bundle bundle = new Bundle();
bundle.putInt("mode", 1);
bundle.putStringArrayList("list", new ArrayList<String>());
param.setResult(bundle);
}
});
}
public static void CleanShareMenuHook() {
Helpers.hookAllMethods("miui.securityspace.XSpaceResolverActivityHelper.ResolverActivityRunner", null, "run", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Intent mOriginalIntent = (Intent)XposedHelpers.getObjectField(param.thisObject, "mOriginalIntent");
if (mOriginalIntent == null) return;
String action = mOriginalIntent.getAction();
if (action == null) return;
if (!action.equals(Intent.ACTION_SEND) && !action.equals(Intent.ACTION_SENDTO) && !action.equals(Intent.ACTION_SEND_MULTIPLE)) return;
if (mOriginalIntent.getDataString() != null && mOriginalIntent.getDataString().contains(":")) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
String mAimPackageName = (String)XposedHelpers.getObjectField(param.thisObject, "mAimPackageName");
if (mContext == null || mAimPackageName == null) return;
Set<String> selectedApps = Helpers.getSharedStringSetPref(mContext, "pref_key_system_cleanshare_apps");
View mRootView = (View)XposedHelpers.getObjectField(param.thisObject, "mRootView");
int appResId1 = mContext.getResources().getIdentifier("app1", "id", "android.miui");
int appResId2 = mContext.getResources().getIdentifier("app2", "id", "android.miui");
boolean removeOriginal = selectedApps.contains(mAimPackageName) || selectedApps.contains(mAimPackageName + "|0");
boolean removeDual = selectedApps.contains(mAimPackageName + "|999");
View originalApp = mRootView.findViewById(appResId1);
View dualApp = mRootView.findViewById(appResId2);
if (removeOriginal)dualApp.performClick();
else if (removeDual) originalApp.performClick();
}
});
}
public static void CleanShareMenuServiceHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.pm.PackageManagerService", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_cleanshare_apps") {
@Override
public void onChange(String name) {
MainModule.mPrefs.put(name, Helpers.getSharedStringSetPref(mContext, name));
}
};
}
});
MethodHook hook = new MethodHook() {
@Override
@SuppressWarnings("unchecked")
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 (action == null) return;
if (!action.equals(Intent.ACTION_SEND) && !action.equals(Intent.ACTION_SENDTO) && !action.equals(Intent.ACTION_SEND_MULTIPLE)) return;
if (intent.getDataString() != null && intent.getDataString().contains(":")) return;
if (intent.hasExtra("CustoMIUIzer") && intent.getBooleanExtra("CustoMIUIzer", false)) return;
Set<String> selectedApps = MainModule.mPrefs.getStringSet("system_cleanshare_apps");
List<ResolveInfo> resolved = (List<ResolveInfo>)param.getResult();
ResolveInfo resolveInfo;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
PackageManager pm = mContext.getPackageManager();
Iterator<ResolveInfo> itr = resolved.iterator();
while (itr.hasNext()) {
resolveInfo = itr.next();
boolean removeOriginal = selectedApps.contains(resolveInfo.activityInfo.packageName) || selectedApps.contains(resolveInfo.activityInfo.packageName + "|0");
boolean removeDual = selectedApps.contains(resolveInfo.activityInfo.packageName + "|999");
boolean hasDual = false;
try {
hasDual = XposedHelpers.callMethod(pm, "getPackageInfoAsUser", resolveInfo.activityInfo.packageName, 0, 999) != null;
} catch (Throwable ignore) {}
if ((removeOriginal && !hasDual) || removeOriginal && hasDual && removeDual) itr.remove();
}
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);
}
private static boolean hideMimeType(int mimeFlags, String mimeType) {
int dataType = MimeType.OTHERS;
if (mimeType != null)
if (mimeType.startsWith("image/")) dataType = MimeType.IMAGE;
else if (mimeType.startsWith("audio/")) dataType = MimeType.AUDIO;
else if (mimeType.startsWith("video/")) dataType = MimeType.VIDEO;
else if (mimeType.startsWith("text/") ||
mimeType.startsWith("application/pdf") ||
mimeType.startsWith("application/msword") ||
mimeType.startsWith("application/vnd.ms-") ||
mimeType.startsWith("application/vnd.openxmlformats-")) dataType = MimeType.DOCUMENT;
else if (mimeType.startsWith("application/vnd.android.package-archive") ||
mimeType.startsWith("application/zip") ||
mimeType.startsWith("application/x-zip") ||
mimeType.startsWith("application/octet-stream") ||
mimeType.startsWith("application/rar") ||
mimeType.startsWith("application/x-rar") ||
mimeType.startsWith("application/x-tar") ||
mimeType.startsWith("application/x-bzip") ||
mimeType.startsWith("application/gzip") ||
mimeType.startsWith("application/x-lz") ||
mimeType.startsWith("application/x-compress") ||
mimeType.startsWith("application/x-7z") ||
mimeType.startsWith("application/java-archive")) dataType = MimeType.ARCHIVE;
else if (mimeType.startsWith("link/")) dataType = MimeType.LINK;
return (mimeFlags & dataType) == dataType;
}
private static String getContentType(Context context, Intent intent) {
String scheme = intent.getScheme();
boolean linkSchemes = "http".equals(scheme) || "https".equals(scheme) || "vnd.youtube".equals(scheme);
String mimeType = intent.getType();
if (mimeType == null && linkSchemes) mimeType = "link/*";
if (mimeType == null && intent.getData() != null) try {
mimeType = context.getContentResolver().getType(intent.getData());
} catch (Throwable ignore) {}
return mimeType;
}
private static Pair<Boolean, Boolean> isRemoveApp(boolean dynamic, Context context, String pkgName, Set<String> selectedApps, String mimeType) {
String key = "system_cleanopenwith_apps";
int mimeFlags0;
int mimeFlags999;
if (dynamic) {
mimeFlags0 = Helpers.getSharedIntPref(context, "pref_key_" + key + "_" + pkgName + "|0", MimeType.ALL);
mimeFlags999 = Helpers.getSharedIntPref(context, "pref_key_" + key + "_" + pkgName + "|999", MimeType.ALL);
} else {
mimeFlags0 = MainModule.mPrefs.getInt(key + "_" + pkgName + "|0", MimeType.ALL);
mimeFlags999 = MainModule.mPrefs.getInt(key + "_" + pkgName + "|999", MimeType.ALL);
}
boolean removeOriginal = (selectedApps.contains(pkgName) || selectedApps.contains(pkgName + "|0")) && hideMimeType(mimeFlags0, mimeType);
boolean removeDual = selectedApps.contains(pkgName + "|999") && hideMimeType(mimeFlags999, mimeType);
return new Pair<Boolean, Boolean>(removeOriginal, removeDual);
}
public static void CleanOpenWithMenuHook() {
Helpers.hookAllMethods("miui.securityspace.XSpaceResolverActivityHelper.ResolverActivityRunner", null, "run", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Intent mOriginalIntent = (Intent)XposedHelpers.getObjectField(param.thisObject, "mOriginalIntent");
if (mOriginalIntent == null) return;
String action = mOriginalIntent.getAction();
if (!Intent.ACTION_VIEW.equals(action)) return;
//if (mOriginalIntent.getDataString() != null && mOriginalIntent.getDataString().contains(":")) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
String mAimPackageName = (String)XposedHelpers.getObjectField(param.thisObject, "mAimPackageName");
if (mContext == null || mAimPackageName == null) return;
Set<String> selectedApps = Helpers.getSharedStringSetPref(mContext, "pref_key_system_cleanopenwith_apps");
String mimeType = getContentType(mContext, mOriginalIntent);
Pair<Boolean, Boolean> isRemove = isRemoveApp(true, mContext, mAimPackageName, selectedApps, mimeType);
View mRootView = (View)XposedHelpers.getObjectField(param.thisObject, "mRootView");
int appResId1 = mContext.getResources().getIdentifier("app1", "id", "android.miui");
int appResId2 = mContext.getResources().getIdentifier("app2", "id", "android.miui");
View originalApp = mRootView.findViewById(appResId1);
View dualApp = mRootView.findViewById(appResId2);
if (isRemove.first) dualApp.performClick();
else if (isRemove.second) originalApp.performClick();
}
});
}
public static void CleanOpenWithMenuServiceHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.pm.PackageManagerService", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String type = uri.getPathSegments().get(1);
String key = uri.getPathSegments().get(2);
if (!key.contains("pref_key_system_cleanopenwith_apps")) return;
switch (type) {
case "stringset":
MainModule.mPrefs.put(key, Helpers.getSharedStringSetPref(mContext, key));
break;
case "integer":
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 0));
break;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
MethodHook hook = new MethodHook() {
@Override
@SuppressWarnings("unchecked")
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();
//XposedBridge.log(action + ": " + intent.getType() + " | " + intent.getDataString());
if (!Intent.ACTION_VIEW.equals(action)) return;
if (intent.hasExtra("CustoMIUIzer") && intent.getBooleanExtra("CustoMIUIzer", false)) return;
String scheme = intent.getScheme();
boolean validSchemes = "http".equals(scheme) || "https".equals(scheme) || "vnd.youtube".equals(scheme);
if (intent.getType() == null && !validSchemes) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
String mimeType = getContentType(mContext, intent);
//XposedBridge.log("mimeType: " + mimeType);
String key = "system_cleanopenwith_apps";
Set<String> selectedApps = MainModule.mPrefs.getStringSet(key);
List<ResolveInfo> resolved = (List<ResolveInfo>)param.getResult();
ResolveInfo resolveInfo;
PackageManager pm = mContext.getPackageManager();
Iterator<ResolveInfo> itr = resolved.iterator();
while (itr.hasNext()) {
resolveInfo = itr.next();
Pair<Boolean, Boolean> isRemove = isRemoveApp(false, mContext, resolveInfo.activityInfo.packageName, selectedApps, mimeType);
boolean hasDual = false;
try {
hasDual = XposedHelpers.callMethod(pm, "getPackageInfoAsUser", resolveInfo.activityInfo.packageName, 0, 999) != null;
} catch (Throwable ignore) {}
if ((isRemove.first && !hasDual) || isRemove.first && hasDual && isRemove.second) itr.remove();
}
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 VolumeTimerValuesRes() {
MainModule.resHooks.setResReplacement("com.android.systemui", "array", "miui_volume_timer_segments", R.array.miui_volume_timer_segments);
MainModule.resHooks.setResReplacement("com.android.systemui", "array", "miui_volume_timer_segments_title", R.array.miui_volume_timer_segments_title);
}
public static void AppLockHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.miui.server.SecurityManagerService", lpparam.classLoader, "removeAccessControlPassLocked", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (!"*".equals(param.args[1])) return;
int mode = (int)XposedHelpers.callMethod(param.thisObject, "getAccessControlLockMode", param.args[0]);
if (mode != 1) param.setResult(null);
}
});
}
@SuppressWarnings("unchecked")
private static void saveLastCheck(Object thisObject, String pkgName, int userId) {
boolean enabled = false;
if (pkgName != null && !"com.miui.home".equals(pkgName)) enabled = (boolean)XposedHelpers.callMethod(thisObject, "getApplicationAccessControlEnabledAsUser", pkgName, userId);
Object userState = XposedHelpers.callMethod(thisObject, "getUserStateLocked", userId);
XposedHelpers.setAdditionalInstanceField(userState, "mAccessControlLastCheckSaved",
enabled ? new ArrayMap<String, Long>((ArrayMap<String, Long>)XposedHelpers.getObjectField(userState, "mAccessControlLastCheck")) : null
);
}
@SuppressWarnings({"unchecked"})
private static void checkLastCheck(Object thisObject, int userId) {
Object userState = XposedHelpers.callMethod(thisObject, "getUserStateLocked", userId);
ArrayMap<String, Long> mAccessControlLastCheckSaved = (ArrayMap<String, Long>)XposedHelpers.getAdditionalInstanceField(userState, "mAccessControlLastCheckSaved");
if (mAccessControlLastCheckSaved == null) return;
ArrayMap<String, Long> mAccessControlLastCheck = (ArrayMap<String, Long>)XposedHelpers.getObjectField(userState, "mAccessControlLastCheck");
if (mAccessControlLastCheck.size() == 0) return;
long timeout = MainModule.mPrefs.getInt("system_applock_timeout", 1) * 60L * 1000L;
for (Map.Entry<String, Long> pair: mAccessControlLastCheck.entrySet()) {
String pkg = pair.getKey();
Long time = pair.getValue();
if (mAccessControlLastCheckSaved.containsKey(pkg)) {
Long oldTime = mAccessControlLastCheckSaved.get(pkg);
if (!time.equals(oldTime)) {
mAccessControlLastCheck.put(pkg, time + (timeout - 60000L));
XposedHelpers.setObjectField(userState, "mAccessControlLastCheck", mAccessControlLastCheck);
}
} else {
mAccessControlLastCheck.put(pkg, time + (timeout - 60000L));
XposedHelpers.setObjectField(userState, "mAccessControlLastCheck", mAccessControlLastCheck);
}
}
}
public static void AppLockTimeoutHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.miui.server.SecurityManagerService", lpparam.classLoader, "addAccessControlPassForUser", String.class, int.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
saveLastCheck(param.thisObject, (String)param.args[0], (int)param.args[1]);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
checkLastCheck(param.thisObject, (int)param.args[1]);
}
});
Helpers.findAndHookMethod("com.miui.server.SecurityManagerService", lpparam.classLoader, "checkAccessControlPassLocked", String.class, Intent.class, int.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
saveLastCheck(param.thisObject, (String)param.args[0], (int)param.args[2]);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
checkLastCheck(param.thisObject, (int)param.args[2]);
}
});
Helpers.findAndHookMethod("com.miui.server.SecurityManagerService", lpparam.classLoader, "activityResume", Intent.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Intent intent = (Intent)param.args[0];
if (intent.getComponent() != null)
saveLastCheck(param.thisObject, intent.getComponent().getPackageName(), 0);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
Intent intent = (Intent)param.args[0];
if (intent.getComponent() != null)
checkLastCheck(param.thisObject, 0);
}
});
}
private static AudioVisualizer audioViz = null;
private static boolean isKeyguardShowing = false;
private static boolean isNotificationPanelExpanded = false;
private static MediaController mMediaController = null;
private static void updateAudioVisualizerState(Context context) {
if (audioViz == null || context == null) return;
AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
boolean isMusicPlaying = am != null && am.isMusicActive();
boolean isPlaying = false;
if (mMediaController == null || mMediaController.getPlaybackState() == null || mMediaController.getPlaybackState().getState() != PlaybackState.STATE_PLAYING) {
if (!audioViz.showWithControllerOnly) isPlaying = isMusicPlaying;
} else {
isPlaying = isMusicPlaying && mMediaController.getPlaybackState().getState() == PlaybackState.STATE_PLAYING;
}
audioViz.updateViewState(isPlaying, isKeyguardShowing, isNotificationPanelExpanded);
}
public static void AudioVisualizerHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "makeStatusBarView", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
ViewGroup mNotificationPanel = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mNotificationPanel");
if (mNotificationPanel == null) {
Helpers.log("AudioVisualizerHook", "Cannot find mNotificationPanel");
return;
}
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
ViewGroup visFrame = new FrameLayout(mContext);
visFrame.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
audioViz = new AudioVisualizer(mContext);
audioViz.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, Gravity.BOTTOM));
audioViz.setClickable(false);
visFrame.addView(audioViz);
visFrame.setClickable(false);
View wallpaper = mNotificationPanel.findViewById(mContext.getResources().getIdentifier("wallpaper", "id", lpparam.packageName));
View themebkg = mNotificationPanel.findViewById(mContext.getResources().getIdentifier("theme_background", "id", lpparam.packageName));
View awesome = mNotificationPanel.findViewById(mContext.getResources().getIdentifier("awesome_lock_screen_container", "id", lpparam.packageName));
int order = 0;
if (awesome != null) order = Math.max(order, mNotificationPanel.indexOfChild(awesome));
if (themebkg != null) order = Math.max(order, mNotificationPanel.indexOfChild(themebkg));
if (wallpaper != null) order = Math.max(order, mNotificationPanel.indexOfChild(wallpaper));
mNotificationPanel.addView(visFrame, order + 1);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "onScreenTurnedOff", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if (audioViz != null) audioViz.updateScreenOn(false);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateKeyguardState", boolean.class, boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Object mStatusBarKeyguardViewManager = XposedHelpers.getObjectField(param.thisObject, "mStatusBarKeyguardViewManager");
boolean isKeyguardShowingNew = (boolean)XposedHelpers.callMethod(mStatusBarKeyguardViewManager, "isShowing");
if (isKeyguardShowing != isKeyguardShowingNew) {
isKeyguardShowing = isKeyguardShowingNew;
isNotificationPanelExpanded = false;
updateAudioVisualizerState((Context)XposedHelpers.getObjectField(param.thisObject, "mContext"));
}
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "onExpandingFinished", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isNotificationPanelExpandedNew = XposedHelpers.getBooleanField(param.thisObject, "mPanelExpanded");
if (isNotificationPanelExpanded != isNotificationPanelExpandedNew) {
isNotificationPanelExpanded = isNotificationPanelExpandedNew;
updateAudioVisualizerState((Context)XposedHelpers.getObjectField(param.thisObject, "mContext"));
}
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateMediaMetaData", boolean.class, boolean.class, new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
if (audioViz == null) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
PowerManager powerMgr = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = powerMgr.isInteractive();
if (!isScreenOn) {
audioViz.updateScreenOn(false);
return;
} else audioViz.isScreenOn = true;
MediaMetadata mMediaMetadata = (MediaMetadata)XposedHelpers.getObjectField(param.thisObject, "mMediaMetadata");
Bitmap art = null;
if (mMediaMetadata != null) {
art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
if (art == null) art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
if (art == null) art = mMediaMetadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON);
}
if (art == null) {
WallpaperManager wallpaperMgr = WallpaperManager.getInstance(mContext);
Drawable wallpaperDrawable = wallpaperMgr.getDrawable();
if (wallpaperDrawable instanceof BitmapDrawable)
art = ((BitmapDrawable)wallpaperDrawable).getBitmap();
}
mMediaController = (MediaController)XposedHelpers.getObjectField(param.thisObject, "mMediaController");
updateAudioVisualizerState(mContext);
audioViz.updateMusicArt(art);
}
});
}
private static String audioFocusPkg = null;
@SuppressWarnings("unchecked")
private static void removeListener(Object thisObject) {
ArrayList<Object> mRecords = (ArrayList<Object>)XposedHelpers.getObjectField(thisObject, "mRecords");
if (mRecords == null) return;
for (Object record: mRecords) {
String callingPackage = (String)XposedHelpers.getObjectField(record, "callingPackage");
int events = XposedHelpers.getIntField(record, "events");
if ((events & PhoneStateListener.LISTEN_CALL_STATE) == PhoneStateListener.LISTEN_CALL_STATE &&
callingPackage != null && MainModule.mPrefs.getStringSet("system_ignorecalls_apps").contains(callingPackage)) {
events &= ~PhoneStateListener.LISTEN_CALL_STATE;
XposedHelpers.setIntField(record, "events", events);
}
}
}
public static void NoCallInterruptionHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.audio.AudioService", lpparam.classLoader, "requestAudioFocus", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if ("AudioFocus_For_Phone_Ring_And_Calls".equals(param.args[4]) && audioFocusPkg != null && MainModule.mPrefs.getStringSet("system_ignorecalls_apps").contains(audioFocusPkg))
param.setResult(1);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
int res = (int)param.getResult();
if (res != AudioManager.AUDIOFOCUS_REQUEST_FAILED && !"AudioFocus_For_Phone_Ring_And_Calls".equals(param.args[4]))
audioFocusPkg = (String)param.args[5];
}
});
Helpers.findAndHookMethod("com.android.server.TelephonyRegistry", lpparam.classLoader, "notifyCallState", int.class, String.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
removeListener(param.thisObject);
}
});
Helpers.findAndHookMethod("com.android.server.TelephonyRegistry", lpparam.classLoader, "notifyCallStateForPhoneId", int.class, int.class, int.class, String.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
removeListener(param.thisObject);
}
});
}
public static void AllRotationsRes() {
MainModule.resHooks.setObjectReplacement("android", "bool", "config_allowAllRotations", MainModule.mPrefs.getStringAsInt("system_allrotations2", 1) == 2);
}
public static void AllRotationsHook(LoadPackageParam lpparam) {
if (Helpers.isQPlus())
Helpers.hookAllConstructors("com.android.server.wm.DisplayRotation", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
XposedHelpers.setIntField(param.thisObject, "mAllowAllRotations", MainModule.mPrefs.getStringAsInt("system_allrotations2", 1) == 2 ? 1 : 0);
}
});
else
Helpers.hookAllMethods("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "init", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
XposedHelpers.setIntField(param.thisObject, "mAllowAllRotations", MainModule.mPrefs.getStringAsInt("system_allrotations2", 1) == 2 ? 1 : 0);
}
});
}
private static boolean mUSBConnected = false;
public static void USBConfigHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.power.PowerManagerService", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (mContext != null)
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
boolean mConnected = intent.getBooleanExtra("connected", false);
if (mConnected && mConnected != mUSBConnected) try {
int mPlugType = XposedHelpers.getIntField(param.thisObject, "mPlugType");
if (mPlugType != BatteryManager.BATTERY_PLUGGED_USB) return;
String func = MainModule.mPrefs.getString("system_defaultusb", "none");
if ("none".equals(func) || "1".equals(func)) return;
UsbManager usbMgr = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
if ((boolean)XposedHelpers.callMethod(usbMgr, "isFunctionEnabled", func))
return;
XposedHelpers.callMethod(usbMgr, "setCurrentFunction", func, MainModule.mPrefs.getBoolean("system_defaultusb_unsecure"));
} catch (Throwable t) {
XposedBridge.log(t);
}
mUSBConnected = mConnected;
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, new IntentFilter("android.hardware.usb.action.USB_STATE"));
}
});
if (!Helpers.isNougat() && MainModule.mPrefs.getBoolean("system_defaultusb_unsecure")) {
if (!Helpers.findAndHookMethodSilently("com.android.server.usb.UsbDeviceManager$UsbHandler", lpparam.classLoader, "isUsbDataTransferActive", long.class, XC_MethodReplacement.returnConstant(true)))
Helpers.findAndHookMethod("com.android.server.usb.UsbDeviceManager$UsbHandler", lpparam.classLoader, "isUsbDataTransferActive", XC_MethodReplacement.returnConstant(true));
Helpers.findAndHookMethod("com.android.server.usb.UsbDeviceManager$UsbHandler", lpparam.classLoader, "handleMessage", Message.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Message msg = (Message)param.args[0];
int setUnlockedFunc = 12;
try {
setUnlockedFunc = XposedHelpers.getStaticIntField(findClass("com.android.server.usb.UsbDeviceManager", lpparam.classLoader), "MSG_SET_SCREEN_UNLOCKED_FUNCTIONS");
} catch (Throwable t) {
}
if (msg.what == setUnlockedFunc) {
msg.obj = 0L;
param.args[0] = msg;
}
}
});
}
}
public static void USBConfigSettingsHook(LoadPackageParam lpparam) {
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.settings.connecteddevice.usb.UsbModeChooserReceiver", lpparam.classLoader, "onReceive", Context.class, Intent.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
String func = MainModule.mPrefs.getString("system_defaultusb", "none");
if (!"none".equals(func) && !"1".equals(func)) param.setResult(null);
}
});
}
public static void HideIconsBattery1Hook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.BatteryMeterView", lpparam.classLoader, "update", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ImageView mBatteryIconView = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mBatteryIconView");
mBatteryIconView.setVisibility(View.GONE);
}
});
}
public static void HideIconsBattery2Hook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.BatteryMeterView", lpparam.classLoader, "update", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
TextView mBatteryTextDigitView = (TextView)XposedHelpers.getObjectField(param.thisObject, "mBatteryTextDigitView");
mBatteryTextDigitView.setVisibility(View.GONE);
}
});
}
public static void HideIconsBattery3Hook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.BatteryMeterView", lpparam.classLoader, "updateChargingIconView", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ImageView mBatteryChargingView = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mBatteryChargingView");
mBatteryChargingView.setVisibility(View.GONE);
try {
ImageView mBatteryChargingInView = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mBatteryChargingInView");
mBatteryChargingInView.setVisibility(View.GONE);
} catch (Throwable ignore) {}
}
});
}
private static boolean lastState = false;
private static void updateAlarmVisibility(Object thisObject, boolean state) {
try {
Object mIconController = XposedHelpers.getObjectField(thisObject, "mIconController");
if (!state) {
XposedHelpers.callMethod(mIconController, "setIconVisibility", "alarm_clock", false);
return;
}
Context mContext = (Context)XposedHelpers.getObjectField(thisObject, "mContext");
long nowTime = java.lang.System.currentTimeMillis();
long nextTime;
try {
nextTime = (long)XposedHelpers.getAdditionalInstanceField(thisObject, "mNextAlarmTime");
} catch (Throwable t) {
nextTime = Helpers.getNextMIUIAlarmTime(mContext);
}
if (nextTime == 0) nextTime = Helpers.getNextStockAlarmTime(mContext);
long diffMSec = nextTime - nowTime;
if (diffMSec < 0) diffMSec += 7 * 24 * 60 *60 * 1000;
float diffHours = (diffMSec - 59 * 1000) / (1000f * 60f * 60f);
XposedHelpers.callMethod(mIconController, "setIconVisibility", "alarm_clock", diffHours <= MainModule.mPrefs.getInt("system_statusbaricons_alarmn", 0));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void HideIconsSelectiveAlarmHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.statusbar.phone.PhoneStatusBarPolicy", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mNextAlarmTime", Helpers.getNextMIUIAlarmTime(mContext));
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));
updateAlarmVisibility(param.thisObject, lastState);
}
};
resolver.registerContentObserver(Settings.System.getUriFor("next_alarm_clock_formatted"), false, alarmObserver);
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.TIME_TICK");
filter.addAction("android.intent.action.TIME_SET");
filter.addAction("android.intent.action.TIMEZONE_CHANGED");
filter.addAction("android.intent.action.LOCALE_CHANGED");
final Object thisObject = param.thisObject;
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updateAlarmVisibility(thisObject, lastState);
}
}, filter);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBarPolicy", lpparam.classLoader, "updateAlarm", boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
lastState = (boolean)param.args[0];
updateAlarmVisibility(param.thisObject, lastState);
}
});
}
public static void HideIconsBluetoothHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBarPolicy", lpparam.classLoader, "updateBluetooth", String.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = Integer.parseInt(MainModule.mPrefs.getString("system_statusbaricons_bluetooth", "1"));
boolean isBluetoothConnected = (boolean)XposedHelpers.callMethod(XposedHelpers.getObjectField(param.thisObject, "mBluetooth"), "isBluetoothConnected");
if (opt == 3 || (opt == 2 && !isBluetoothConnected)) {
Object mIconController = XposedHelpers.getObjectField(param.thisObject, "mIconController");
XposedHelpers.callMethod(mIconController, "setIconVisibility", "bluetooth", false);
}
}
});
}
public static void HideIconsSignalHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "apply", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View[] mMobileSignalGroup = (View[])XposedHelpers.getObjectField(param.thisObject, "mMobileSignalGroup");
for (View mMobileSignal: mMobileSignalGroup) if (mMobileSignal != null) mMobileSignal.setVisibility(View.GONE);
}
});
}
public static void HideIconsVPNHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "apply", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mVpn = (View)XposedHelpers.getObjectField(param.thisObject, "mVpn");
if (mVpn != null) mVpn.setVisibility(View.GONE);
}
});
}
public static void HideIconsNoSIMsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "apply", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
try {
View mNoSimsCombo = (View)XposedHelpers.getObjectField(param.thisObject, "mNoSimsCombo");
if (mNoSimsCombo != null) mNoSimsCombo.setVisibility(View.GONE);
} catch (Throwable t) {
View mNoSims = (View)XposedHelpers.getObjectField(param.thisObject, "mNoSims");
if (mNoSims != null) mNoSims.setVisibility(View.GONE);
}
}
});
}
public static void HideIconsNoWiFiHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "apply", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mWifiGroup = (View)XposedHelpers.getObjectField(param.thisObject, "mWifiGroup");
if (mWifiGroup != null) mWifiGroup.setVisibility(View.GONE);
}
});
}
public static void HideIconsVoWiFiHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "apply", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View[] mVowifi = (View[])XposedHelpers.getObjectField(param.thisObject, "mVowifi");
if (mVowifi == null) return;
if (mVowifi[0] != null) mVowifi[0].setVisibility(View.GONE);
if (mVowifi[1] != null) mVowifi[1].setVisibility(View.GONE);
}
});
}
public static void HideIconsHotspotHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.SignalClusterView", lpparam.classLoader, "onHotspotChanged", boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mWifiAp = (View)XposedHelpers.getObjectField(param.thisObject, "mWifiAp");
if (mWifiAp != null) mWifiAp.setVisibility(View.GONE);
}
});
}
private static boolean checkSlot(String slotName) {
try {
return "headset".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_headset") ||
"volume".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_sound") ||
"quiet".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_dnd") ||
"mute".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_mute") ||
"speakerphone".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_speaker") ||
"call_record".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_record") ||
"alarm_clock".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_alarm") ||
"managed_profile".equals(slotName) && MainModule.mPrefs.getBoolean("system_statusbaricons_profile");
} catch (Throwable t) {
XposedBridge.log(t);
return false;
}
}
public static void HideIconsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBarIconControllerImpl", lpparam.classLoader, "setIconVisibility", String.class, boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (checkSlot((String)param.args[0])) param.args[1] = false;
}
});
}
public static void HideIconsSystemHook() {
Helpers.findAndHookMethod("android.app.StatusBarManager", null, "setIconVisibility", String.class, boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (checkSlot((String)param.args[0])) param.args[1] = false;
}
});
}
public static void BatteryIndicatorHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "makeStatusBarView", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
FrameLayout mStatusBarWindow = (FrameLayout)XposedHelpers.getObjectField(param.thisObject, "mStatusBarWindow");
BatteryIndicator indicator = new BatteryIndicator(mContext);
View panel = mStatusBarWindow.findViewById(mContext.getResources().getIdentifier("notification_panel", "id", lpparam.packageName));
mStatusBarWindow.addView(indicator, panel != null ? mStatusBarWindow.indexOfChild(panel) + 1 : Math.max(mStatusBarWindow.getChildCount() - 1, 8));
indicator.setAdjustViewBounds(false);
indicator.init(param.thisObject);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mBatteryIndicator", indicator);
Object mNotificationIconAreaController = XposedHelpers.getObjectField(param.thisObject, "mNotificationIconAreaController");
XposedHelpers.setAdditionalInstanceField(mNotificationIconAreaController, "mBatteryIndicator", indicator);
Object mBatteryController = XposedHelpers.getObjectField(param.thisObject, "mBatteryController");
XposedHelpers.setAdditionalInstanceField(mBatteryController, "mBatteryIndicator", indicator);
XposedHelpers.callMethod(mBatteryController, "fireBatteryLevelChanged");
XposedHelpers.callMethod(mBatteryController, "firePowerSaveChanged");
XposedHelpers.callMethod(mBatteryController, "fireExtremePowerSaveChanged");
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setPanelExpanded", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isKeyguardShowing = (boolean)XposedHelpers.callMethod(param.thisObject, "isKeyguardShowing");
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onExpandingChanged(!isKeyguardShowing && (boolean)param.args[0]);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setQsExpanded", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isKeyguardShowing = (boolean)XposedHelpers.callMethod(param.thisObject, "isKeyguardShowing");
if (!isKeyguardShowing) return;
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onExpandingChanged((boolean)param.args[0]);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateKeyguardState", boolean.class, boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isKeyguardShowing = (boolean)XposedHelpers.callMethod(param.thisObject, "isKeyguardShowing");
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onKeyguardStateChanged(isKeyguardShowing);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationIconAreaController", lpparam.classLoader, "onDarkChanged", Rect.class, float.class, int.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onDarkModeChanged((float)param.args[1], (int)param.args[2]);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BatteryControllerImpl", lpparam.classLoader, "fireBatteryLevelChanged", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
int mLevel = XposedHelpers.getIntField(param.thisObject, "mLevel");
boolean mCharging = XposedHelpers.getBooleanField(param.thisObject, "mCharging");
boolean mCharged = XposedHelpers.getBooleanField(param.thisObject, "mCharged");
if (indicator != null) indicator.onBatteryLevelChanged(mLevel, mCharging, mCharged);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BatteryControllerImpl", lpparam.classLoader, "firePowerSaveChanged", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onPowerSaveChanged(XposedHelpers.getBooleanField(param.thisObject, "mIsPowerSaveMode"));
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BatteryControllerImpl", lpparam.classLoader, "fireExtremePowerSaveChanged", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
BatteryIndicator indicator = (BatteryIndicator)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mBatteryIndicator");
if (indicator != null) indicator.onExtremePowerSaveChanged(XposedHelpers.getBooleanField(param.thisObject, "mIsExtremePowerSaveMode"));
}
});
}
private static boolean obtainMagnifierShowCoordinates(Object mEditor, int type, final MotionEvent event, final PointF showPosInView) {
TextView mTextView = (TextView)XposedHelpers.getObjectField(mEditor, "mTextView");
final int offset;
final int otherHandleOffset;
switch (type) {
case 0:
offset = mTextView.getSelectionStart();
otherHandleOffset = -1;
break;
case 1:
offset = mTextView.getSelectionStart();
otherHandleOffset = mTextView.getSelectionEnd();
break;
case 2:
offset = mTextView.getSelectionEnd();
otherHandleOffset = mTextView.getSelectionStart();
break;
default:
offset = -1;
otherHandleOffset = -1;
break;
}
if (offset == -1) return false;
final Layout layout = mTextView.getLayout();
final int lineNumber = layout.getLineForOffset(offset);
final boolean sameLineSelection = otherHandleOffset != -1 && lineNumber == layout.getLineForOffset(otherHandleOffset);
final boolean rtl = sameLineSelection && (offset < otherHandleOffset) != (mTextView.getLayout().getPrimaryHorizontal(offset) < mTextView.getLayout().getPrimaryHorizontal(otherHandleOffset));
final int[] textViewLocationOnScreen = new int[2];
mTextView.getLocationOnScreen(textViewLocationOnScreen);
final float touchXInView = event.getRawX() - textViewLocationOnScreen[0];
float leftBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
float rightBound = mTextView.getTotalPaddingLeft() - mTextView.getScrollX();
if (sameLineSelection && ((type == 2) ^ rtl))
leftBound += mTextView.getLayout().getPrimaryHorizontal(otherHandleOffset);
else
leftBound += mTextView.getLayout().getLineLeft(lineNumber);
if (sameLineSelection && ((type == 1) ^ rtl))
rightBound += mTextView.getLayout().getPrimaryHorizontal(otherHandleOffset);
else
rightBound += mTextView.getLayout().getLineRight(lineNumber);
showPosInView.x = Math.max(leftBound - 1, Math.min(rightBound + 1, touchXInView));
showPosInView.y = (mTextView.getLayout().getLineTop(lineNumber) + mTextView.getLayout().getLineBottom(lineNumber)) / 2.0f + mTextView.getTotalPaddingTop() - mTextView.getScrollY();
return true;
}
@SuppressLint("NewApi")
private static void processHandleMotionEvent(Object handleView, int type, MotionEvent ev) {
int action = ev.getActionMasked();
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_MOVE) {
Object mEditor = XposedHelpers.getSurroundingThis(handleView);
Magnifier mMagnifier = (Magnifier)XposedHelpers.getAdditionalInstanceField(mEditor, "mMagnifier");
if (mMagnifier == null) return;
PointF coords = new PointF();
if (obtainMagnifierShowCoordinates(mEditor, type, ev, coords))
mMagnifier.show(coords.x, coords.y);
else
mMagnifier.dismiss();
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
Magnifier mMagnifier = (Magnifier)XposedHelpers.getAdditionalInstanceField(XposedHelpers.getSurroundingThis(handleView), "mMagnifier");
if (mMagnifier != null) mMagnifier.dismiss();
}
}
public static void TextMagnifierHook() {
Helpers.findAndHookMethod("android.widget.Magnifier", null, "obtainContentCoordinates", float.class, float.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Point mClampedCenterZoomCoords = (Point)XposedHelpers.getObjectField(param.thisObject, "mClampedCenterZoomCoords");
if (Helpers.isQPlus()) {
Object mView = XposedHelpers.getObjectField(param.thisObject, "mView");
float f = (float)param.args[0];
int x;
if (mView instanceof SurfaceView) {
x = Math.round(f);
} else {
int[] mViewCoordinatesInSurface = (int[])XposedHelpers.getObjectField(param.thisObject, "mViewCoordinatesInSurface");
x = Math.round(f + (float)mViewCoordinatesInSurface[0]);
}
mClampedCenterZoomCoords.x = x;
} else {
Point mCenterZoomCoords = (Point)XposedHelpers.getObjectField(param.thisObject, "mCenterZoomCoords");
mClampedCenterZoomCoords.x = mCenterZoomCoords.x;
}
}
});
Helpers.findAndHookConstructor("android.widget.Editor", null, TextView.class, new MethodHook() {
@Override
@SuppressLint("NewApi")
protected void after(final MethodHookParam param) throws Throwable {
TextView mTextView = (TextView)XposedHelpers.getObjectField(param.thisObject, "mTextView");
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mMagnifier", new Magnifier(mTextView));
}
});
Helpers.findAndHookMethod("android.widget.Editor$InsertionHandleView", null, "onTouchEvent", MotionEvent.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
processHandleMotionEvent(param.thisObject, 0, (MotionEvent)param.args[0]);
}
});
Helpers.findAndHookMethod("android.widget.Editor$SelectionHandleView", null, "onTouchEvent", MotionEvent.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
processHandleMotionEvent(param.thisObject, "SelectionEndHandleView".equals(param.thisObject.getClass().getSimpleName()) ? 2 : 1, (MotionEvent)param.args[0]);
}
});
}
public static void ForceCloseHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(final MethodHookParam param) throws Throwable {
HashSet<String> mSystemKeyPackages = (HashSet<String>)XposedHelpers.getObjectField(param.thisObject, "mSystemKeyPackages");
mSystemKeyPackages.remove("com.miui.securitycenter");
mSystemKeyPackages.remove("com.miui.securityadd");
mSystemKeyPackages.remove("com.android.phone");
mSystemKeyPackages.remove("com.android.mms");
mSystemKeyPackages.remove("com.android.contacts");
mSystemKeyPackages.remove("com.miui.home");
mSystemKeyPackages.remove("com.jeejen.family.miui");
mSystemKeyPackages.remove("com.miui.backup");
mSystemKeyPackages.remove("com.xiaomi.mihomemanager");
mSystemKeyPackages.addAll(MainModule.mPrefs.getStringSet("system_forceclose_apps"));
}
});
}
public static void DisableAnyNotificationBlockHook() {
Helpers.hookAllConstructors("android.app.NotificationChannel", null, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
XposedHelpers.setBooleanField(param.thisObject, "mBlockableSystem", true);
}
});
Helpers.findAndHookMethod("android.app.NotificationChannel", null, "setBlockableSystem", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
XposedHelpers.setBooleanField(param.thisObject, "mBlockableSystem", true);
}
});
}
public static void DisableAnyNotificationHook() {
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "isNotificationForcedEnabled", Context.class, String.class, XC_MethodReplacement.returnConstant(false));
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "isNotificationForcedEnabled", Context.class, String.class, String.class, XC_MethodReplacement.returnConstant(false));
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "isNotificationForcedFor", Context.class, String.class, XC_MethodReplacement.returnConstant(false));
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "canSystemNotificationBeBlocked", String.class, XC_MethodReplacement.returnConstant(true));
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "containNonBlockableChannel", String.class, XC_MethodReplacement.returnConstant(false));
Helpers.findAndHookMethod("miui.util.NotificationFilterHelper", null, "getNotificationForcedEnabledList", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
param.setResult(new HashSet<String>());
}
});
}
private static boolean modifyCameraImage(Context mContext, View mKeyguardRightView, boolean mDarkMode) {
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_off")) {
restoreCameraImage(mKeyguardRightView);
return false;
}
final String key = "pref_key_system_lockscreenshortcuts_right";
int action = Helpers.getSharedIntPref(mContext, key + "_action", 1);
if (action <= 1) {
restoreCameraImage(mKeyguardRightView);
return false;
}
String str = Helpers.getActionName(mContext, key);
if (str == null) {
restoreCameraImage(mKeyguardRightView);
return false;
}
Drawable icon = Helpers.getActionImage(mContext, key);
mKeyguardRightView.setBackgroundColor(Color.TRANSPARENT);
mKeyguardRightView.setForeground(icon);
mKeyguardRightView.setForegroundGravity(Gravity.CENTER);
float density = mContext.getResources().getDisplayMetrics().density;
int size = Math.round(mContext.getResources().getConfiguration().smallestScreenWidthDp * density);
Bitmap bmp = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShadowLayer(2 * density, 0, 0, mDarkMode ? Color.argb(90, 255, 255, 255) : Color.argb(90, 0, 0, 0));
paint.setTextSize(20 * density);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(density);
paint.setColor(mDarkMode ? Color.WHITE : Color.BLACK);
paint.setAlpha(90);
Rect bounds = new Rect();
paint.getTextBounds(str, 0, str.length(), bounds);
float x = size / 2f - bounds.width() / 2f;
float y = size / 2f + bounds.height() / 2f + (icon == null ? 0 : icon.getIntrinsicHeight() / 2f + 30 * density);
canvas.drawText(str, x, y, paint);
paint.setStyle(Paint.Style.FILL);
// paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));
paint.clearShadowLayer();
paint.setColor(mDarkMode ? Color.BLACK : Color.WHITE);
paint.setAlpha(mDarkMode ? 160 : 230);
canvas.drawText(str, x, y, paint);
BitmapDrawable bmpDrawable = new BitmapDrawable(mContext.getResources(), bmp);
if (mKeyguardRightView instanceof ImageView) {
((ImageView)mKeyguardRightView).setScaleType(ImageView.ScaleType.CENTER);
((ImageView)mKeyguardRightView).setImageDrawable(bmpDrawable);
} else {
bmpDrawable.setGravity(Gravity.CENTER);
mKeyguardRightView.setBackground(bmpDrawable);
}
return true;
}
private static void restoreCameraImage(View mKeyguardRightView) {
mKeyguardRightView.setBackgroundColor(Color.BLACK);
mKeyguardRightView.setForeground(null);
if (mKeyguardRightView instanceof ImageView)
((ImageView)mKeyguardRightView).setScaleType(ImageView.ScaleType.FIT_END);
}
private static void initLeftView(final Object thisObject) {
Context mContext = (Context)XposedHelpers.getObjectField(thisObject, "mContext");
try { XposedHelpers.setObjectField(thisObject, "mMiWalletCardNum", new TextView(mContext)); } catch (Throwable ignore) {}
try { XposedHelpers.setObjectField(thisObject, "mRemoteControllerNum", new TextView(mContext)); } catch (Throwable ignore) {}
try { XposedHelpers.setObjectField(thisObject, "mSmartHomeNum", new TextView(mContext)); } catch (Throwable ignore) {}
Handler mHandler = (Handler)XposedHelpers.getAdditionalInstanceField(thisObject, "mHandler");
mHandler.removeMessages(1);
Message msg = new Message();
msg.what = 1;
msg.obj = thisObject;
mHandler.sendMessageDelayed(msg, 1000);
}
private static Object notificationPanelView = null;
public static void LockScreenShortcutHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.KeyguardBottomAreaView$DefaultLeftButton", lpparam.classLoader, "getIcon", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object img = param.getResult();
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_off"))
XposedHelpers.setObjectField(img, "drawable", null);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.KeyguardBottomAreaView$DefaultRightButton", lpparam.classLoader, "getIcon", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object img = param.getResult();
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_off")) {
XposedHelpers.setObjectField(img, "drawable", null);
return;
}
Object thisObject = XposedHelpers.getSurroundingThis(param.thisObject);
Context mContext = (Context)XposedHelpers.getObjectField(thisObject, "mContext");
boolean opt = MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_image");
if (!opt) return;
boolean mDarkMode = XposedHelpers.getBooleanField(thisObject, "mDarkMode");
boolean isNewLS = findClassIfExists("com.android.keyguard.KeyguardCameraView", lpparam.classLoader) != null;
XposedHelpers.setObjectField(img, "drawable", Helpers.getModuleRes(mContext).getDrawable(mDarkMode ?
(isNewLS ? R.drawable.keyguard_bottom_miuizer_img_dark : R.drawable.keyguard_bottom_miuizer_oldimg_dark) :
(isNewLS ? R.drawable.keyguard_bottom_miuizer_img_light : R.drawable.keyguard_bottom_miuizer_oldimg_light), mContext.getTheme()
));
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.KeyguardBottomAreaView", lpparam.classLoader, "initTipsView", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
boolean opt = MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_image");
if (!opt) return;
TextView mRightAffordanceViewTips = (TextView)XposedHelpers.getObjectField(param.thisObject, "mRightAffordanceViewTips");
if (mRightAffordanceViewTips != null) mRightAffordanceViewTips.setText(Helpers.getModuleRes(mRightAffordanceViewTips.getContext()).getString(R.string.system_lockscreenshortcuts_right_image_hint));
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.KeyguardBottomAreaView", lpparam.classLoader, "launchCamera", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (GlobalActions.handleAction(mContext, "pref_key_system_lockscreenshortcuts_right", true)) {
param.setResult(null);
final View mNotificationPanelView = (View)XposedHelpers.getObjectField(param.thisObject, "mNotificationPanelView");
mNotificationPanelView.postDelayed(new Runnable() {
@Override
public void run() {
XposedHelpers.callMethod(mNotificationPanelView, "resetViews");
}
}, 500);
}
}
});
if (findClassIfExists("com.android.keyguard.KeyguardCameraView", lpparam.classLoader) != null) {
Helpers.hookAllMethods("com.android.keyguard.KeyguardCameraView", lpparam.classLoader, "setDarkMode", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
XposedHelpers.callMethod(param.thisObject, "updatePreViewBackground");
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardCameraView", lpparam.classLoader, "updatePreView", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
View mPreViewContainer = (View)XposedHelpers.getObjectField(param.thisObject, "mPreViewContainer");
if ("active".equals(mPreViewContainer.getTag())) {
XposedHelpers.setFloatField(param.thisObject, "mIconCircleAlpha", 0.0f);
((View)param.thisObject).invalidate();
}
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardCameraView", lpparam.classLoader, "updatePreViewBackground", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
boolean mDarkMode = XposedHelpers.getBooleanField(param.thisObject, "mDarkMode");
ImageView mIconView = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mIconView");
if (mIconView != null)
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_image"))
mIconView.setImageDrawable(Helpers.getModuleRes(mContext).getDrawable(mDarkMode ? R.drawable.keyguard_bottom_miuizer_img_dark : R.drawable.keyguard_bottom_miuizer_img_light, mContext.getTheme()));
else
mIconView.setImageDrawable(mContext.getDrawable(mDarkMode ? mContext.getResources().getIdentifier("keyguard_bottom_camera_img_dark", "drawable", lpparam.packageName) : mContext.getResources().getIdentifier("keyguard_bottom_camera_img", "drawable", lpparam.packageName)));
View mPreView = (View)XposedHelpers.getObjectField(param.thisObject, "mPreView");
View mPreViewContainer = (View)XposedHelpers.getObjectField(param.thisObject, "mPreViewContainer");
View mBackgroundView = (View)XposedHelpers.getObjectField(param.thisObject, "mBackgroundView");
Paint mIconCircleStrokePaint = (Paint)XposedHelpers.getObjectField(param.thisObject, "mIconCircleStrokePaint");
ViewOutlineProvider mPreViewOutlineProvider = (ViewOutlineProvider)XposedHelpers.getObjectField(param.thisObject, "mPreViewOutlineProvider");
boolean result = modifyCameraImage(mContext, mPreView, mDarkMode);
if (result) param.setResult(null);
if (mPreViewContainer != null) {
mPreViewContainer.setBackgroundColor(result ? Color.TRANSPARENT : Color.BLACK);
mPreViewContainer.setOutlineProvider(result ? null : mPreViewOutlineProvider);
mPreViewContainer.setTag(result ? "active" : "inactive");
}
if (mBackgroundView != null) mBackgroundView.setBackgroundColor(result ? Color.TRANSPARENT : Color.BLACK);
if (mIconCircleStrokePaint != null) mIconCircleStrokePaint.setColor(result ? Color.TRANSPARENT : Color.WHITE);
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardCameraView", lpparam.classLoader, "handleMoveDistanceChanged", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
View mIconView = (View)XposedHelpers.getObjectField(param.thisObject, "mIconView");
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_off")) {
if (mIconView != null) mIconView.setVisibility(View.GONE);
param.setResult(null);
} else if (mIconView != null) mIconView.setVisibility(View.VISIBLE);
}
});
Helpers.findAndHookMethod("com.android.keyguard.KeyguardCameraView", lpparam.classLoader, "startFullScreenAnim", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int action = MainModule.mPrefs.getInt("system_lockscreenshortcuts_right_action", 1);
if (action <= 1) return;
AnimatorSet mAnimatorSet = (AnimatorSet)XposedHelpers.getObjectField(param.thisObject, "mAnimatorSet");
if (mAnimatorSet == null) return;
param.setResult(null);
mAnimatorSet.pause();
mAnimatorSet.removeAllListeners();
mAnimatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
GlobalActions.handleAction(mContext, "pref_key_system_lockscreenshortcuts_right", true);
Object mCallBack = XposedHelpers.getObjectField(param.thisObject, "mCallBack");
if (mCallBack != null) XposedHelpers.callMethod(mCallBack, "onCompletedAnimationEnd");
XposedHelpers.setBooleanField(param.thisObject, "mIsPendingStartCamera", false);
XposedHelpers.callMethod(param.thisObject, "dismiss");
View mBackgroundView = (View)XposedHelpers.getObjectField(param.thisObject, "mBackgroundView");
if (mBackgroundView != null) mBackgroundView.setAlpha(1.0f);
}
});
mAnimatorSet.resume();
}
});
} else {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "updateWallpaper", boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if ((boolean)param.args[0]) try {
XposedHelpers.callMethod(param.thisObject, "setCameraImage", false);
} catch (Throwable t1) {
XposedHelpers.callMethod(param.thisObject, "setCameraImage");
}
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "setCameraImage", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
View mView = (View)XposedHelpers.getObjectField(param.thisObject, "mKeyguardRightView");
Object mUpdateMonitor = XposedHelpers.getObjectField(param.thisObject, "mUpdateMonitor");
boolean mDarkMode = (boolean)XposedHelpers.callMethod(mUpdateMonitor, "isLightWallpaperBottom");
if (modifyCameraImage(mContext, mView, mDarkMode)) {
try {
XposedHelpers.setBooleanField(param.thisObject, "mGetCameraImageSucceed", false);
} catch (Throwable ignore) {}
param.setResult(null);
}
}
});
}
Helpers.hookAllConstructors("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
notificationPanelView = param.thisObject;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
new Helpers.SharedPrefObserver(mContext, new Handler(mContext.getMainLooper())) {
@Override
public void onChange(Uri uri) {
try {
String type = uri.getPathSegments().get(1);
String key = uri.getPathSegments().get(2);
if (!key.contains("pref_key_system_lockscreenshortcuts")) return;
switch (type) {
case "string":
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, ""));
break;
case "integer":
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 1));
break;
case "boolean":
MainModule.mPrefs.put(key, Helpers.getSharedBoolPref(mContext, key, false));
break;
}
if (key.contains("pref_key_system_lockscreenshortcuts_right"))
try {
XposedHelpers.callMethod(notificationPanelView, "setCameraImage", false);
} catch (Throwable t1) {
try {
XposedHelpers.callMethod(notificationPanelView, "setCameraImage");
} catch (Throwable t2) {}
}
if (key.contains("pref_key_system_lockscreenshortcuts_left")) {
Object leftView = null;
try {
leftView = XposedHelpers.getObjectField(XposedHelpers.getObjectField(notificationPanelView, "mKeyguardLeftView"), "mKeyguardMoveLeftView");
} catch (Throwable t) {
XposedBridge.log(t);
}
if (leftView != null) try {
XposedHelpers.callMethod(leftView, "reloadListItems");
} catch (Throwable t1) {
try {
XposedHelpers.callMethod(leftView, "updateShortcuts");
} catch (Throwable t2) {
try {
XposedHelpers.callMethod(leftView, "initKeyguardLeftItems");
} catch (Throwable t3) {
try {
XposedHelpers.callMethod(leftView, "initKeyguardLeftItemInfos");
} catch (Throwable t4) {
XposedBridge.log(t4);
}
}
}
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.KeyguardMoveHelper", lpparam.classLoader, "setTranslation", float.class, boolean.class, boolean.class, boolean.class, boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int mCurrentScreen = XposedHelpers.getIntField(param.thisObject, "mCurrentScreen");
if (mCurrentScreen != 1) return;
if ((float)param.args[0] < 0 && MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_off")) param.args[0] = 0.0f;
else if ((float)param.args[0] > 0 && MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_off")) param.args[0] = 0.0f;
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.KeyguardMoveHelper", lpparam.classLoader, "fling", float.class, boolean.class, boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int mCurrentScreen = XposedHelpers.getIntField(param.thisObject, "mCurrentScreen");
if (mCurrentScreen != 1) return;
if ((float)param.args[0] < 0 && MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_right_off")) param.setResult(null);
else if ((float)param.args[0] > 0 && MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_off")) param.setResult(null);
}
});
View.OnClickListener mListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int action = MainModule.mPrefs.getInt(v.getTag() + "_action", 1);
boolean skip = MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_skiplock");
if (!skip && (action == 8 || action == 9 || action == 20))
XposedHelpers.callStaticMethod(findClass("com.android.systemui.SystemUICompat", lpparam.classLoader), "dismissKeyguardOnNextActivity");
GlobalActions.handleAction(v.getContext(), "pref_key_" + v.getTag(), skip);
}
};
class LeftControlCenterHandler extends Handler {
LeftControlCenterHandler(Looper looper) {
super(looper);
}
public void handleMessage(Message msg) {
if (msg.what == 1) try {
ViewGroup leftView = (ViewGroup)msg.obj;
Context mContext = (Context)XposedHelpers.getObjectField(leftView, "mContext");
int listResId = mContext.getResources().getIdentifier("keyguard_move_left", "id", lpparam.packageName);
ViewGroup oldList = leftView.findViewById(listResId);
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams)oldList.getLayoutParams();
ScrollView container = new ScrollView(oldList.getContext());
container.setVerticalScrollBarEnabled(false);
ViewGroup parent = ((ViewGroup)oldList.getParent());
LinearLayout leftList = new LinearLayout(oldList.getContext());
parent.removeView(oldList);
leftList.setLayoutParams(new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT, ScrollView.LayoutParams.WRAP_CONTENT));
leftList.setOrientation(LinearLayout.VERTICAL);
try {
float density = mContext.getResources().getDisplayMetrics().density;
int align = MainModule.mPrefs.getStringAsInt("system_lockscreenshortcuts_left_align", 2);
int margin = Math.round(density * 40);
lp.topMargin = lp.bottomMargin;
if (lp.topMargin < margin) lp.topMargin = margin;
if (lp.bottomMargin < margin) lp.bottomMargin = margin;
boolean center = MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_center");
lp.leftMargin = Math.round((center ? 36.33f : 20) * density);
lp.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
if (align == 1)
lp.addRule(RelativeLayout.ALIGN_PARENT_TOP);
else
lp.removeRule(RelativeLayout.ALIGN_PARENT_TOP);
container.setLayoutParams(lp);
} catch (Throwable t) {
XposedBridge.log(t);
}
container.addView(leftList);
container.setId(listResId);
parent.addView(container);
LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int layoutResId = mContext.getResources().getIdentifier("miui_keyguard_left_view_control_center_item", "layout", lpparam.packageName);
if (layoutResId == 0) layoutResId = mContext.getResources().getIdentifier("miui_keyguard_left_view_item", "layout", lpparam.packageName);
int imgResId = mContext.getResources().getIdentifier("keyguard_left_list_item_img", "id", lpparam.packageName);
int nameResId = mContext.getResources().getIdentifier("keyguard_left_list_item_name", "id", lpparam.packageName);
//int numberResId = mContext.getResources().getIdentifier("keyguard_left_list_item_number", "id", lpparam.packageName);
int margin = mContext.getResources().getDimensionPixelSize(mContext.getResources().getIdentifier("keyguard_move_left_item_margin", "dimen", lpparam.packageName));
String key = "system_lockscreenshortcuts_left";
String itemStr = MainModule.mPrefs.getString(key, "");
if (itemStr == null || itemStr.isEmpty()) return;
String[] itemArr = itemStr.trim().split("\\|");
int i = 0;
for (String uuid: itemArr) {
LinearLayout item = (LinearLayout)inflater.inflate(layoutResId, leftList, false);
item.setTag(key + "_" + uuid);
leftList.addView(item);
ImageView img = item.findViewById(imgResId);
int size = (int)(32 * img.getResources().getDisplayMetrics().density);
ViewGroup.LayoutParams lp1 = img.getLayoutParams();
lp1.width = size;
lp1.height = size;
img.setLayoutParams(lp1);
Drawable image = Helpers.getActionImage(mContext, "pref_key_" + key + "_" + uuid);
img.setImageDrawable(image != null ? image : mContext.getPackageManager().getApplicationIcon(Helpers.modulePkg));
img.setBackgroundResource(0);
TextView title = item.findViewById(nameResId);
title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 15);
title.setText(Helpers.getActionName(mContext, "pref_key_" + key + "_" + uuid));
LinearLayout.LayoutParams lp2 = (LinearLayout.LayoutParams)item.getLayoutParams();
if (i > 0) lp2.topMargin = margin;
lp2.height = LinearLayout.LayoutParams.WRAP_CONTENT;
item.setLayoutParams(lp2);
int padding = (int)(14 * img.getResources().getDisplayMetrics().density);
item.setPadding(padding, padding, padding, padding);
i++;
item.setOnClickListener(mListener);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
String leftViewCls = "com.android.keyguard.negative.MiuiKeyguardMoveLeftControlCenterView";
if (XposedHelpers.findClassIfExists(leftViewCls, lpparam.classLoader) == null)
leftViewCls = "com.android.keyguard.MiuiKeyguardMoveLeftView";
Helpers.findAndHookConstructor(leftViewCls, lpparam.classLoader, Context.class, AttributeSet.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = new LeftControlCenterHandler(mContext.getMainLooper());
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mHandler", mHandler);
}
});
if (!Helpers.findAndHookMethodSilently(leftViewCls, lpparam.classLoader, "reloadListItems", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
initLeftView(param.thisObject);
param.setResult(null);
}
})) if (!Helpers.findAndHookMethodSilently(leftViewCls, lpparam.classLoader, "updateShortcuts", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
initLeftView(param.thisObject);
param.setResult(null);
}
})) if (!Helpers.findAndHookMethodSilently(leftViewCls, lpparam.classLoader, "initKeyguardLeftItems", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
initLeftView(param.thisObject);
param.setResult(null);
}
})) Helpers.findAndHookMethod(leftViewCls, lpparam.classLoader, "initKeyguardLeftItemInfos", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
initLeftView(param.thisObject);
param.setResult(null);
}
});
if (!Helpers.findAndHookMethodSilently(leftViewCls, lpparam.classLoader, "onClick", View.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (handleStockShortcut((View)param.args[0])) param.setResult(null);
}
})) Helpers.findAndHookMethod(leftViewCls, lpparam.classLoader, "onFinishInflate", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mSmartHomeLinearLayout = (View)XposedHelpers.getObjectField(param.thisObject, "mSmartHomeLinearLayout");
View mRemoteCenterLinearLayout = (View)XposedHelpers.getObjectField(param.thisObject, "mRemoteCenterLinearLayout");
final View.OnClickListener mListener = (View.OnClickListener)XposedHelpers.getObjectField(param.thisObject, "mListener");
View.OnClickListener mNewListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!handleStockShortcut(view))
if (mListener != null) mListener.onClick(view);
}
};
mSmartHomeLinearLayout.setOnClickListener(mNewListener);
mRemoteCenterLinearLayout.setOnClickListener(mNewListener);
}
});
}
private static boolean handleStockShortcut(View view) {
if (view == null) return false;
boolean skip = MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_skiplock");
if (!skip) return false;
Context context = view.getContext();
int id = view.getId();
try {
if (id == view.getResources().getIdentifier("keyguard_remote_controller_info", "id", context.getPackageName())) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage("com.duokan.phone.remotecontroller");
if (intent == null) return false;
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_skiplock")) {
intent.putExtra("ShowCameraWhenLocked", true);
intent.putExtra("StartActivityWhenLocked", true);
}
context.startActivity(intent);
return true;
} else if (id == view.getResources().getIdentifier("keyguard_smarthome_info", "id", context.getPackageName())) {
Intent intent = new Intent();
intent.setPackage("com.xiaomi.smarthome");
intent.setData(Uri.parse("http://home.mi.com/main"));
intent.setAction("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("source", 11);
if (MainModule.mPrefs.getBoolean("system_lockscreenshortcuts_left_skiplock")) {
intent.putExtra("ShowCameraWhenLocked", true);
intent.putExtra("StartActivityWhenLocked", true);
}
context.startActivity(intent);
return true;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
return false;
}
public static void LockScreenSecureLaunchHook() {
Helpers.findAndHookMethod(Activity.class, "onCreate", Bundle.class, new MethodHook() {
@SuppressWarnings("ConstantConditions")
protected void after(MethodHookParam param) throws Throwable {
Activity act = (Activity)param.thisObject;
if (act == null) return;
Intent intent = act.getIntent();
if (intent == null) return;
boolean mFromSecureKeyguard = intent.getBooleanExtra("StartActivityWhenLocked", false);
boolean mStartedFromLockScreen = false;
try {
mStartedFromLockScreen = (boolean)XposedHelpers.getAdditionalInstanceField(act.getApplication(), "wasStartedFromLockScreen");
} catch (Throwable ignore) {}
if (mFromSecureKeyguard || mStartedFromLockScreen) {
XposedHelpers.setAdditionalInstanceField(act.getApplication(), "wasStartedFromLockScreen", true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
act.setShowWhenLocked(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
act.setInheritShowWhenLocked(true);
} else {
act.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
}
}
});
}
private static Handler stateHandler;
public static class StateRunnable implements Runnable {
Context context;
MediaController controller;
StateRunnable(Context ctx, MediaController ctrl) {
context = ctx;
controller = ctrl;
}
@Override
public void run() {
try {
if (stateHandler != null) stateHandler.postDelayed(this, 1000);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
public static class SeekBarReceiver extends BroadcastReceiver {
View parent;
TextView posDur;
SeekBar seekBar;
SeekBarReceiver(View view, SeekBar sBar, TextView pos) {
parent = view;
posDur = pos;
seekBar = sBar;
}
@Override
public void onReceive(Context context, Intent intent) {}
}
public static class MediaControllerReceiver extends BroadcastReceiver {
MediaController.TransportControls transportControls;
MediaControllerReceiver(MediaController.TransportControls transport) {
transportControls = transport;
}
@Override
public void onReceive(Context context, Intent intent) {}
}
private static void sendSeekBarUpdate(Context mContext, MediaController controller) {
try {
if (mContext == null) return;
String pkgName = (String)XposedHelpers.callMethod(controller, "getPackageName");
Intent intent = new Intent(ACTION_PREFIX + "UpdateMediaPosition:" + pkgName);
MediaMetadata medaData = controller.getMetadata();
if (medaData == null) return;
intent.putExtra(MediaMetadata.METADATA_KEY_DURATION, medaData.getLong(MediaMetadata.METADATA_KEY_DURATION));
intent.putExtra("android.media.metadata.POSITION", controller.getPlaybackState().getPosition());
mContext.sendBroadcast(intent);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void MediaNotificationSeekBarHook() {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
stateHandler = new Handler();
MediaController mController = (MediaController)XposedHelpers.callMethod(param.thisObject, "getController");
MediaController.TransportControls mTransportControls = (MediaController.TransportControls)XposedHelpers.getObjectField(mController, "mTransportControls");
MediaControllerReceiver mSeekToReceiver = new MediaControllerReceiver(mTransportControls) {
@Override
public void onReceive(Context context, Intent intent) {
if (transportControls == null) return;
long position = intent.getLongExtra("android.media.metadata.POSITION", 0L);
transportControls.seekTo(position);
}
};
StateRunnable mStateRunnable = new StateRunnable((Context)param.args[0], mController) {
@Override
public void run() {
if (context != null && controller != null) try {
sendSeekBarUpdate(context, controller);
PlaybackState state = controller.getPlaybackState();
if (state != null && state.getState() != PlaybackState.STATE_PLAYING) return;
} catch (Throwable t) {
XposedBridge.log(t);
}
super.run();
}
};
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mSeekToReceiver", mSeekToReceiver);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mStateRunnable", mStateRunnable);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mContext", param.args[0]);
}
};
if (Helpers.isQPlus())
Helpers.findAndHookConstructor("android.media.session.MediaSession", null, Context.class, String.class, Bundle.class, hook);
else
Helpers.findAndHookConstructor("android.media.session.MediaSession", null, Context.class, String.class, int.class, hook);
Helpers.findAndHookMethod("android.media.session.MediaSession", null, "setActive", boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
boolean mActive = XposedHelpers.getBooleanField(param.thisObject, "mActive");
boolean newActive = (boolean)param.args[0];
if (mActive == newActive) return;
Context mContext = (Context)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mContext");
if (mContext == null) return;
MediaControllerReceiver mSeekToReceiver = (MediaControllerReceiver)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSeekToReceiver");
if (newActive)
mContext.registerReceiver(mSeekToReceiver, new IntentFilter(ACTION_PREFIX + "SeekToMediaPosition:" + mContext.getPackageName()));
else
mContext.unregisterReceiver(mSeekToReceiver);
}
});
Helpers.findAndHookMethod("android.media.session.MediaSession", null, "setPlaybackState", PlaybackState.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mContext");
if (mContext == null) return;
MediaController mController = (MediaController)XposedHelpers.callMethod(param.thisObject, "getController");
if (mController == null) return;
StateRunnable mStateRunnable = (StateRunnable)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mStateRunnable");
if (mStateRunnable == null) return;
stateHandler.removeCallbacks(mStateRunnable);
if (((PlaybackState)param.args[0]).getState() == PlaybackState.STATE_PLAYING)
stateHandler.postDelayed(mStateRunnable, 100);
else
sendSeekBarUpdate(mContext, mController);
}
});
}
@SuppressLint("DefaultLocale")
private static String msToStr(long timeMillis) {
return String.format("%d:%02d", TimeUnit.MILLISECONDS.toMinutes(timeMillis), TimeUnit.MILLISECONDS.toSeconds(timeMillis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeMillis)));
}
public static void MediaNotificationSeekBarSysUIHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.notification.NotificationViewWrapper", lpparam.classLoader, "wrap", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (param.args.length > 3) return;
Object res = param.getResult();
if (res == null) return;
String cls = res.getClass().getSimpleName();
if (!"NotificationMediaTemplateViewWrapper".equals(cls) && !"NotificationMediaCustomTemplateViewWrapper".equals(cls)) return;
View mView = (View)XposedHelpers.getObjectField(res, "mView");
Object mRow = XposedHelpers.getObjectField(res, "mRow");
if (mView == null || mRow == null || !"bigMediaNarrow".equals(mView.getTag())) return;
if (mView.getId() != mView.getResources().getIdentifier("status_bar_latest_event_content", "id", "android")) return;
LinearLayout mediaLayout = mView.findViewById(mView.getResources().getIdentifier("notification_main_column", "id", "android"));
if (mediaLayout == null || mediaLayout.findViewWithTag("notifmediaseekbar") != null) return;
mediaLayout.setClipToPadding(false);
mediaLayout.setClipChildren(false);
float density = mView.getResources().getDisplayMetrics().density;
String pkgName = (String)XposedHelpers.callMethod(XposedHelpers.callMethod(mRow, "getStatusBarNotification"), "getPackageName");
Context ctx = mView.getContext();
FrameLayout container = new FrameLayout(ctx);
container.setTag("notifmediaseekbar");
container.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
container.setClipToPadding(false);
container.setClipChildren(false);
container.setPadding(0, Math.round(10 * density), 0, 0);
//container.setTranslationY(-Math.round(7 * density));
final TextView posDur = new TextView(ctx);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.END;
posDur.setLayoutParams(lp);
posDur.setGravity(Gravity.END);
posDur.setTranslationY(-Math.round(15 * density));
posDur.setPadding(0, 0, Math.round(16 * density), 0);
try {
posDur.setTextColor(mView.getResources().getColor(mView.getResources().getIdentifier("media_notification_app_name_text_color", "color", "android"), ctx.getTheme()));
posDur.setTextSize(TypedValue.COMPLEX_UNIT_PX, mView.getResources().getDimensionPixelSize(mView.getResources().getIdentifier("media_notification_app_name_text_size", "dimen", "android")));
} catch (Throwable t) {
TextView appName = mView.findViewById(mView.getResources().getIdentifier("media_app_name", "id", "android"));
if (appName != null) {
posDur.setTextColor(appName.getCurrentTextColor());
posDur.setTextSize(TypedValue.COMPLEX_UNIT_PX, appName.getTextSize());
}
}
final SeekBar seekBar = new SeekBar(ctx);
boolean opt = MainModule.mPrefs.getBoolean("system_notifmediaseekbar_full");
if (opt) {
seekBar.setPadding(Math.round(15 * density), Math.round(5 * density), Math.round(15 * density), Math.round(5 * density));
} else {
seekBar.setProgressDrawable(Helpers.getModuleRes(ctx).getDrawable(R.drawable.seekbar, ctx.getTheme()));
seekBar.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, Math.round(10 * density)));
seekBar.setThumb(null);
seekBar.setBackground(null);
seekBar.setPadding(Math.round(16 * density), 0, Math.round(16 * density), 0);
}
seekBar.setMax(100);
seekBar.setProgress(0);
seekBar.setTag(false);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) posDur.setText(msToStr(progress).concat(" / ").concat(msToStr(seekBar.getMax())));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
seekBar.setTag(true);
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
seekBar.setTag(false);
Intent intent = new Intent(ACTION_PREFIX + "SeekToMediaPosition:" + pkgName);
intent.putExtra("android.media.metadata.POSITION", Long.valueOf(seekBar.getProgress()));
seekBar.getContext().sendBroadcast(intent);
}
});
long rnd = Math.round(Math.random() * 1000);
seekBar.setContentDescription(String.valueOf(rnd));
container.addView(seekBar);
container.addView(posDur);
mediaLayout.addView(container, 1, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
SeekBarReceiver seekBarUpdate = new SeekBarReceiver(mView, seekBar, posDur) {
@Override
public void onReceive(Context context, Intent intent) {
try {
if (!parent.isAttachedToWindow() || !seekBar.isAttachedToWindow()) {
context.unregisterReceiver(this);
seekBar = null;
parent = null;
return;
}
if (seekBar == null || (boolean)seekBar.getTag() || intent == null || intent.getExtras() == null) return;
long dur = intent.getLongExtra(MediaMetadata.METADATA_KEY_DURATION, 0L);
long pos = intent.getLongExtra("android.media.metadata.POSITION", 0L);
seekBar.setMax((int)dur);
seekBar.setProgress((int)pos);
posDur.setText(msToStr(pos).concat(" / ").concat(msToStr(dur)));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
mView.getContext().registerReceiver(seekBarUpdate, new IntentFilter(ACTION_PREFIX + "UpdateMediaPosition:" + pkgName));
}
});
}
public static void Network4GtoLTEHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.policy.TelephonyIcons", lpparam.classLoader, "getNetworkTypeName", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
String net = (String)param.getResult();
if ("4G".equals(net)) param.setResult("LTE");
else if ("4G+".equals(net)) param.setResult("LTE+");
}
});
}
private static final TextView[] lux = { null, null, null };
private static class LuxListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
long cTime = currentTimeMillis();
String caption = null;
if (lux[0] != null && lux[0].isAttachedToWindow()) try {
Long last = (Long)lux[0].getTag();
if (last != null && cTime - last < 750) return;
caption = Helpers.getModuleRes(lux[0].getContext()).getString(R.string.lux, String.valueOf(Math.round(event.values[0])));
lux[0].setText(caption);
lux[0].setTag(cTime);
} catch (Throwable t) {
XposedBridge.log(t);
}
if (lux[1] != null && lux[1].isAttachedToWindow()) try {
Long last = (Long)lux[1].getTag();
if (last != null && cTime - last < 750) return;
if (caption == null)
caption = Helpers.getModuleRes(lux[1].getContext()).getString(R.string.lux, String.valueOf(Math.round(event.values[0])));
lux[1].setText(caption);
lux[1].setTag(cTime);
} catch (Throwable t) {
XposedBridge.log(t);
}
if (lux[2] != null && lux[2].isAttachedToWindow()) try {
Long last = (Long)lux[2].getTag();
if (last != null && cTime - last < 750) return;
if (caption == null)
caption = Helpers.getModuleRes(lux[2].getContext()).getString(R.string.lux, String.valueOf(Math.round(event.values[0])));
lux[2].setText(caption);
lux[2].setTag(cTime);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}
// private static View getBrightnessSlider(Object statusBar) {
// try {
// View mStatusBarWindow = (View)XposedHelpers.getObjectField(statusBar, "mStatusBarWindow");
// if (mStatusBarWindow == null) return null;
// ViewGroup mQSFragment = mStatusBarWindow.findViewById(mStatusBarWindow.getResources().getIdentifier("qs_frame", "id", "com.android.systemui"));
// if (mQSFragment == null || mQSFragment.getChildCount() == 0) return null;
// Object mContainer = mQSFragment.getChildAt(0);
// if (mContainer == null) return null;
// return (View)XposedHelpers.callMethod(mContainer, "getBrightnessView");
// } catch (Throwable t) {
// XposedBridge.log(t);
// return null;
// }
// }
private static void registerLuxListener(Object statusBar) {
try {
Context mContext = (Context)XposedHelpers.getObjectField(statusBar, "mContext");
PowerManager powerMgr = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
if (!powerMgr.isInteractive()) return;
boolean sBootCompleted = XposedHelpers.getBooleanField(statusBar, "sBootCompleted");
if (!sBootCompleted) return;
SensorManager sensorMgr = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
LuxListener mLuxListener = (LuxListener)XposedHelpers.getAdditionalInstanceField(statusBar, "mLuxListener");
sensorMgr.registerListener(mLuxListener, sensorMgr.getDefaultSensor(Sensor.TYPE_LIGHT), SensorManager.SENSOR_DELAY_NORMAL);
XposedHelpers.setAdditionalInstanceField(statusBar, "mListenerEnabled", true);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
private static void unregisterLuxListener(Object statusBar) {
try {
Context mContext = (Context)XposedHelpers.getObjectField(statusBar, "mContext");
SensorManager sensorMgr = (SensorManager)mContext.getSystemService(Context.SENSOR_SERVICE);
LuxListener mLuxListener = (LuxListener)XposedHelpers.getAdditionalInstanceField(statusBar, "mLuxListener");
sensorMgr.unregisterListener(mLuxListener);
XposedHelpers.setAdditionalInstanceField(statusBar, "mListenerEnabled", false);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void setTextColors(Context context, TextView textView) {
textView.setTextColor(Helpers.isNightMode(context) ? 0xFFDDDDDD : 0xFF606060);
if (Helpers.isNightMode(context))
textView.setShadowLayer(context.getResources().getDisplayMetrics().density, 1f, 1f, 0xEE222224);
else
textView.setShadowLayer(0, 0, 0, Color.WHITE);
}
public static void BrightnessLuxHook(LoadPackageParam lpparam) {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context context = (Context)param.args[0];
ViewGroup container = (ViewGroup)param.thisObject;
int port = context.getResources().getIdentifier("qs_brightness", "id", lpparam.packageName);
int land = context.getResources().getIdentifier("qs_brightness_land", "id", lpparam.packageName);
if (container.getId() != port && container.getId() != land) return;
TextView clux = new TextView(context);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.alignWithParent = true;
lp.addRule(RelativeLayout.CENTER_IN_PARENT);
clux.setLayoutParams(lp);
clux.setGravity(Gravity.CENTER);
boolean isAlt = MainModule.mPrefs.getBoolean("system_showlux_style");
setTextColors(context, clux);
if (isAlt) {
clux.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
clux.setAlpha(0.33f);
}
container.addView(clux);
if (Helpers.is12() && "QCToggleSliderView".equals(param.thisObject.getClass().getSimpleName())) {
if (container.getId() == land)
lux[2] = clux;
else
lux[1] = clux;
} else {
lux[0] = clux;
}
}
};
Helpers.findAndHookConstructor("com.android.systemui.settings.ToggleSliderView", lpparam.classLoader, Context.class, AttributeSet.class, int.class, hook);
if (Helpers.is12())
Helpers.findAndHookConstructor("com.android.systemui.miui.controlcenter.QCToggleSliderView", lpparam.classLoader, Context.class, AttributeSet.class, int.class, hook);
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "makeStatusBarView", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
LuxListener mLuxListener = new LuxListener();
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mLuxListener", mLuxListener);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mListenerEnabled", false);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setPanelExpanded", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isExpanded = (boolean)param.args[0];
boolean mListenerEnabled = (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mListenerEnabled");
if (isExpanded && !mListenerEnabled)
registerLuxListener(param.thisObject);
else if (!isExpanded && mListenerEnabled)
unregisterLuxListener(param.thisObject);
}
});
if (Helpers.is12()) {
Helpers.findAndHookMethod("com.android.systemui.miui.controlcenter.QSControlCenterPanel", lpparam.classLoader, "setListening", boolean.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean isExpanded = (boolean)param.args[0];
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Object mApplication = XposedHelpers.callMethod(mContext.getApplicationContext(), "getSystemUIApplication");
Object mStatusBar = XposedHelpers.callMethod(mApplication, "getComponent", findClassIfExists("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader));
boolean mListenerEnabled = (boolean)XposedHelpers.getAdditionalInstanceField(mStatusBar, "mListenerEnabled");
if (isExpanded && !mListenerEnabled)
registerLuxListener(mStatusBar);
else if (!isExpanded && mListenerEnabled)
unregisterLuxListener(mStatusBar);
}
});
Helpers.findAndHookMethod("com.android.systemui.miui.controlcenter.QSControlCenterPanel", lpparam.classLoader, "updateResources", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (lux[1] != null) setTextColors(mContext, lux[1]);
if (lux[2] != null) setTextColors(mContext, lux[2]);
}
});
}
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "onScreenTurnedOff", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
unregisterLuxListener(param.thisObject);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "onScreenTurnedOn", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean mPanelExpanded = XposedHelpers.getBooleanField(param.thisObject, "mPanelExpanded");
boolean mListenerEnabled = (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mListenerEnabled");
if (mPanelExpanded && !mListenerEnabled) registerLuxListener(param.thisObject);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "onBootCompleted", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
boolean mPanelExpanded = XposedHelpers.getBooleanField(param.thisObject, "mPanelExpanded");
boolean mListenerEnabled = (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mListenerEnabled");
if (mPanelExpanded && !mListenerEnabled) registerLuxListener(param.thisObject);
}
});
}
@SuppressLint("StaticFieldLeak")
private static TextView mPct = null;
private static void initPct(ViewGroup container, int source) {
Context context = container.getContext();
Resources res = container.getResources();
if (mPct == null) {
mPct = new TextView(context);
mPct.setTag("mirrorBrightnessPct");
mPct.setTextSize(TypedValue.COMPLEX_UNIT_SP, 40);
mPct.setGravity(Gravity.CENTER);
mPct.setTypeface(Typeface.create("sans-serif-light", Typeface.NORMAL));
float density = res.getDisplayMetrics().density;
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT);
lp.topMargin = Math.round(MainModule.mPrefs.getInt("system_showpct_top", 26) * density);
lp.gravity = Gravity.CENTER_HORIZONTAL|Gravity.TOP;
mPct.setPadding(Math.round(20 * density), Math.round(10 * density), Math.round(18 * density), Math.round(12 * density));
mPct.setLayoutParams(lp);
} else {
ViewGroup parent = (ViewGroup)mPct.getParent();
if (parent != null) parent.removeView(mPct);
}
container.addView(mPct);
mPct.setTag(source);
int panelResId = res.getIdentifier("panel_round_corner_bg", "drawable", "com.android.systemui");
mPct.setBackground(res.getDrawable(panelResId, context.getTheme()));
int colorResId = res.getIdentifier("qs_tile_icon_disabled_color", "color", "com.android.systemui");
mPct.setTextColor(res.getColor(colorResId, container.getContext().getTheme()));
mPct.setAlpha(0.0f);
mPct.setVisibility(View.GONE);
}
public static void BrightnessPctHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BrightnessMirrorController", lpparam.classLoader, "showMirror", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
ViewGroup mStatusBarWindow = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mStatusBarWindow");
if (mStatusBarWindow == null) {
Helpers.log("BrightnessPctHook", "mStatusBarWindow is null");
return;
}
initPct(mStatusBarWindow, 1);
mPct.setVisibility(View.VISIBLE);
mPct.animate().alpha(1.0f).setDuration(300).start();
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BrightnessMirrorController", lpparam.classLoader, "hideMirror", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if (mPct != null) mPct.setVisibility(View.GONE);
}
});
if (Helpers.is12()) {
Helpers.findAndHookMethod("com.android.systemui.miui.controlcenter.policy.QCBrightnessMirrorController", lpparam.classLoader, "showMirror", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
ViewGroup mControlPanelContentView = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mControlPanelContentView");
if (mControlPanelContentView == null) {
Helpers.log("BrightnessPctHook", "mControlPanelContentView is null");
return;
}
initPct((ViewGroup)mControlPanelContentView.getParent(), 1);
mPct.setVisibility(View.VISIBLE);
mPct.animate().alpha(1.0f).setDuration(300).start();
}
});
Helpers.findAndHookMethod("com.android.systemui.miui.controlcenter.policy.QCBrightnessMirrorController", lpparam.classLoader, "hideMirror", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if (mPct != null) mPct.setVisibility(View.GONE);
}
});
}
Helpers.hookAllMethods("com.android.systemui.settings.BrightnessController", lpparam.classLoader, "onChanged", new MethodHook() {
@Override
@SuppressLint("SetTextI18n")
protected void after(final MethodHookParam param) throws Throwable {
if (mPct == null || (int)mPct.getTag() != 1) return;
int currentLevel = (int)(param.args[2] instanceof Integer ? param.args[2] : param.args[3]);
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
int maxLevel = mContext.getResources().getInteger(mContext.getResources().getIdentifier("config_screenBrightnessSettingMaximum", "integer", "android"));
mPct.setText(((currentLevel * 100) / maxLevel) + "%");
}
});
}
public static void HideProximityWarningHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.policy.MiuiScreenOnProximityLock", lpparam.classLoader, "showHint", XC_MethodReplacement.DO_NOTHING);
}
public static void HideIconsVoLTERes() {
MainModule.resHooks.setObjectReplacement("com.android.systemui", "bool", "status_bar_hide_volte", true);
}
public static void HideIconsVoLTEHook(LoadPackageParam lpparam) {
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.systemui.MCCUtils", lpparam.classLoader, "isHideVolte", Context.class, String.class, XC_MethodReplacement.returnConstant(true));
}
public static void HideLockScreenClockHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "setKeyguardStatusViewVisibility", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
View mKeyguardClockView = (View)XposedHelpers.getObjectField(param.thisObject, "mKeyguardClockView");
if (mKeyguardClockView == null) {
Helpers.log("HideLockScreenClockHook", "mKeyguardClockView is null");
return;
}
((ViewGroup)mKeyguardClockView).getChildAt(0).setVisibility(View.INVISIBLE);
mKeyguardClockView.animate().cancel();
XposedHelpers.setBooleanField(param.thisObject, "mKeyguardStatusViewAnimating", false);
mKeyguardClockView.setAlpha(0.0f);
mKeyguardClockView.setVisibility(View.INVISIBLE);
}
});
}
public static void NoSilentVibrateHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.miui.volume.MiuiVolumeDialogImpl", lpparam.classLoader, "vibrateH", XC_MethodReplacement.DO_NOTHING);
}
public static void FirstVolumePressHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.audio.AudioService$VolumeController", lpparam.classLoader, "suppressAdjustment", int.class, int.class, boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int streamType = (int)param.args[0];
if (streamType != AudioManager.STREAM_MUSIC) return;
boolean isMuteAdjust = (boolean)param.args[2];
if (isMuteAdjust) return;
Object mController = XposedHelpers.getObjectField(param.thisObject, "mController");
if (mController == null) return;
param.setResult(false);
}
});
}
public static void HideThemeBackgroundBrightnessHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BrightnessMirrorController", lpparam.classLoader, "showMirror", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Object mNotificationPanel = XposedHelpers.getObjectField(param.thisObject, "mNotificationPanel");
if (mNotificationPanel == null) return;
View mThemeBackgroundView = (View)XposedHelpers.getObjectField(mNotificationPanel, "mThemeBackgroundView");
if (mThemeBackgroundView != null) mThemeBackgroundView.setVisibility(View.GONE);
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BrightnessMirrorController", lpparam.classLoader, "hideMirror", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object mNotificationPanel = XposedHelpers.getObjectField(param.thisObject, "mNotificationPanel");
if (mNotificationPanel == null) return;
View mThemeBackgroundView = (View)XposedHelpers.getObjectField(mNotificationPanel, "mThemeBackgroundView");
if (mThemeBackgroundView != null) mThemeBackgroundView.setVisibility(View.VISIBLE);
}
});
}
public static void NoSignatureVerifyHook() {
if (Helpers.isNougat()) return;
Helpers.hookAllMethods("android.content.pm.PackageParser.SigningDetails", null, "checkCapability", XC_MethodReplacement.returnConstant(true));
Helpers.hookAllMethods("android.content.pm.PackageParser.SigningDetails", null, "checkCapabilityRecover", XC_MethodReplacement.returnConstant(true));
}
public static void NoSignatureVerifyServiceHook(LoadPackageParam lpparam) {
if (!Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerServiceUtils", lpparam.classLoader, "compareSignatures", XC_MethodReplacement.returnConstant(0))) {
Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "compareSignatures", XC_MethodReplacement.returnConstant(0));
Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "compareSignaturesCompat", XC_MethodReplacement.returnConstant(0));
Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "compareSignaturesRecover", XC_MethodReplacement.returnConstant(0));
}
Helpers.hookAllMethods("com.android.server.pm.PackageManagerServiceInjector", lpparam.classLoader, "isAllowedInstall", XC_MethodReplacement.returnConstant(true));
Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "canSkipFullPackageVerification", XC_MethodReplacement.returnConstant(true));
Helpers.hookAllMethodsSilently("com.android.server.pm.PackageManagerService", lpparam.classLoader, "canSkipFullApkVerification", XC_MethodReplacement.returnConstant(true));
}
@SuppressWarnings("ResultOfMethodCallIgnored")
public static void NoSignatureVerifyMiuiHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethodSilently("com.android.packageinstaller.InstallAppProgress.a", lpparam.classLoader, "a", Boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
Helpers.findAndHookMethodSilently("com.android.packageinstaller.InstallAppProgress.a", lpparam.classLoader, "onPostExecute", Boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
Helpers.findAndHookMethodSilently("com.android.packageinstaller.IncrementInstallProgress.a", lpparam.classLoader, "a", Boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
Helpers.findAndHookMethodSilently("com.android.packageinstaller.IncrementInstallProgress.a", lpparam.classLoader, "onPostExecute", Boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
}
public static void ScreenDimTimeHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.power.PowerManagerService", lpparam.classLoader, "readConfigurationLocked", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
float opt = MainModule.mPrefs.getInt("system_dimtime", 0) / 100f;
XposedHelpers.setIntField(param.thisObject, "mMaximumScreenDimDurationConfig", 600000);
XposedHelpers.setFloatField(param.thisObject, "mMaximumScreenDimRatioConfig", opt);
// Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
// int minScreenOffTimeout = mContext.getResources().getInteger(mContext.getResources().getIdentifier("config_minimumScreenOffTimeout", "integer", "android"));
}
});
// Helpers.hookAllMethods("com.android.server.power.PowerManagerService", lpparam.classLoader, "getScreenOffTimeoutLocked", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// //XposedBridge.log("getScreenOffTimeoutLocked (mSleepTimeoutSetting): " + param.args[0]);
// //XposedBridge.log("mMaximumScreenOffTimeoutFromDeviceAdmin: " + XposedHelpers.getLongField(param.thisObject, "mMaximumScreenOffTimeoutFromDeviceAdmin"));
// XposedBridge.log("mUserActivityTimeoutOverrideFromWindowManager: " + XposedHelpers.getLongField(param.thisObject, "mUserActivityTimeoutOverrideFromWindowManager"));
// }
// });
//
// Helpers.hookAllMethods("com.android.server.power.PowerManagerService", lpparam.classLoader, "updateUserActivitySummaryLocked", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// if ((int)param.args[1] == 1) return;
// XposedBridge.log("updateUserActivitySummaryLocked: " + param.args[0] + ", " + param.args[1]);
// }
// });
}
public static void NoOverscrollHook() {
if (Helpers.isQPlus())
Helpers.findAndHookMethod("android.widget.AbsListView", null, "initAbsListView", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
((AbsListView)param.thisObject).setOverScrollMode(View.OVER_SCROLL_NEVER);
}
});
else
Helpers.findAndHookMethod("android.widget.AbsListView", null, "setOverScrollMode", int.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = View.OVER_SCROLL_NEVER;
}
});
}
public static void NoOverscrollAppHook(LoadPackageParam lpparam) {
MethodHook hookParam = new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = false;
}
};
Class<?> sblCls = findClassIfExists("miuix.springback.view.SpringBackLayout", lpparam.classLoader);
if (sblCls != null) {
Helpers.hookAllConstructors(sblCls, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
try {
XposedHelpers.callMethod(param.thisObject, "setSpringBackEnable", false);
} catch (Throwable t) {
try { XposedHelpers.setBooleanField(param.thisObject, "mSpringBackEnable", false); } catch (Throwable ignore) {}
}
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(sblCls, "setSpringBackEnable", boolean.class, hookParam);
}
Class<?> rrvCls = findClassIfExists("androidx.recyclerview.widget.RemixRecyclerView", lpparam.classLoader);
if (rrvCls != null) {
Helpers.hookAllConstructors(rrvCls, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
((View)param.thisObject).setOverScrollMode(View.OVER_SCROLL_NEVER);
try {
XposedHelpers.callMethod(param.thisObject, "setSpringEnabled", false);
} catch (Throwable t) {
try { XposedHelpers.setBooleanField(param.thisObject, "mSpringEnabled", false); } catch (Throwable ignore) {}
}
}
});
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(rrvCls, "setSpringEnabled", boolean.class, hookParam);
}
}
private static Dialog mDialog = null;
private static float blurCollapsed = 0.0f;
private static float blurExpanded = 0.0f;
@SuppressWarnings("deprecation")
private static void updateBlurRatio(Object thisObject) {
if (mDialog == null || mDialog.getWindow() == null) return;
View rootView = mDialog.getWindow().getDecorView();
if (rootView.isAttachedToWindow() && rootView.getLayoutParams() instanceof WindowManager.LayoutParams) {
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams)rootView.getLayoutParams();
layoutParams.flags |= WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
boolean isExpanded = (boolean)XposedHelpers.callMethod(thisObject, "isExpanded");
XposedHelpers.setFloatField(layoutParams, "blurRatio", isExpanded ? blurExpanded : blurCollapsed);
mDialog.getWindow().getWindowManager().updateViewLayout(rootView, layoutParams);
}
}
public static void BlurVolumeDialogBackgroundHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.miui.volume.MiuiVolumeDialogView", lpparam.classLoader, "onAttachedToWindow", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
updateBlurRatio(param.thisObject);
}
});
Helpers.hookAllMethods("com.android.systemui.miui.volume.MiuiVolumeDialogView", lpparam.classLoader, "onExpandStateUpdated", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
updateBlurRatio(param.thisObject);
}
});
Helpers.hookAllMethods("com.android.systemui.miui.volume.MiuiVolumeDialogImpl", lpparam.classLoader, "initDialog", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = new Handler(mContext.getMainLooper());
mDialog = (Dialog)XposedHelpers.getObjectField(param.thisObject, "mDialog");
blurCollapsed = MainModule.mPrefs.getInt("system_volumeblur_collapsed", 0) / 100f;
blurExpanded = MainModule.mPrefs.getInt("system_volumeblur_expanded", 0) / 100f;
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if (key.equals("pref_key_system_volumeblur_collapsed")) blurCollapsed = Helpers.getSharedIntPref(mContext, key, 0) / 100f;
if (key.equals("pref_key_system_volumeblur_expanded")) blurExpanded = Helpers.getSharedIntPref(mContext, key, 0) / 100f;
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
}
public static void BlurVolumeDialogBackgroundRes() {
MainModule.resHooks.setObjectReplacement("com.android.systemui", "fraction", "miui_volume_dim_behind_collapsed", 0.0f);
MainModule.resHooks.setObjectReplacement("com.android.systemui", "fraction", "miui_volume_dim_behind_expanded", 0.0f);
}
public static void RemoveSecureHook() {
Helpers.findAndHookMethod(Window.class, "setFlags", int.class, int.class, new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
int flags = (int)param.args[0];
int mask = (int)param.args[1];
flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
mask &= ~WindowManager.LayoutParams.FLAG_SECURE;
param.args[0] = flags;
param.args[1] = mask;
}
});
MethodHook paramFlagsHook = new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
if (!(param.args[1] instanceof WindowManager.LayoutParams)) return;
WindowManager.LayoutParams params = (WindowManager.LayoutParams)param.args[1];
params.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
}
};
Helpers.hookAllMethods("android.view.WindowManagerGlobal", null, "addView", paramFlagsHook);
Helpers.hookAllMethods("android.view.WindowManagerGlobal", null, "updateViewLayout", paramFlagsHook);
Helpers.findAndHookMethod(SurfaceView.class, "setSecure", boolean.class, new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = false;
}
});
}
public static void AllowAllKeyguardHook(LoadPackageParam lpparam) {
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.notification.MiuiNotificationCompat", lpparam.classLoader, "isEnableKeyguard", Notification.class, XC_MethodReplacement.returnConstant(true));
}
public static void AllowAllKeyguardSysHook() {
Helpers.findAndHookMethod(MiuiNotification.class, "setEnableKeyguard", boolean.class, new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
Helpers.findAndHookMethod(MiuiNotification.class, "isEnableKeyguard", XC_MethodReplacement.returnConstant(true));
}
public static void AllowAllFloatHook(LoadPackageParam lpparam) {
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.systemui.statusbar.notification.MiuiNotificationCompat", lpparam.classLoader, "isEnableFloat", Notification.class, XC_MethodReplacement.returnConstant(true));
}
public static void AllowAllFloatSysHook() {
Helpers.findAndHookMethod(MiuiNotification.class, "setEnableFloat", boolean.class, new MethodHook() {
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
Helpers.findAndHookMethod(MiuiNotification.class, "isEnableFloat", XC_MethodReplacement.returnConstant(true));
}
public static void AllowDirectReplyHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setLockScreenAllowRemoteInput", boolean.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
param.args[0] = true;
}
});
}
public static void HideQSHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setBarState", int.class, new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Object mNotificationPanel = XposedHelpers.getObjectField(param.thisObject, "mNotificationPanel");
final View mQsFrame = (View)XposedHelpers.getObjectField(mNotificationPanel, "mQsFrame");
if ((int)param.args[0] == 2) {
ViewGroup.LayoutParams lp = mQsFrame.getLayoutParams();
lp.height = 1;
mQsFrame.setLayoutParams(lp);
} else {
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
ViewGroup.LayoutParams lp = mQsFrame.getLayoutParams();
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
mQsFrame.setLayoutParams(lp);
}
}, 300);
}
}
});
}
public static void RemoveDrawerBackgroundHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "drawChild", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mStatusBarStateOrig", XposedHelpers.getIntField(param.thisObject, "mStatusBarState"));
XposedHelpers.setIntField(param.thisObject, "mStatusBarState", 0);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mKeyguardShowingOrig", XposedHelpers.getBooleanField(param.thisObject, "mKeyguardShowing"));
XposedHelpers.setBooleanField(param.thisObject, "mKeyguardShowing", false);
}
@Override
protected void after(MethodHookParam param) throws Throwable {
XposedHelpers.setIntField(param.thisObject, "mStatusBarState", (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mStatusBarStateOrig"));
XposedHelpers.setBooleanField(param.thisObject, "mKeyguardShowing", (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mKeyguardShowingOrig"));
}
});
}
public static void LockScreenTimeoutHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBarWindowManager", lpparam.classLoader, "applyUserActivityTimeout", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object mLpChanged = XposedHelpers.getObjectField(param.thisObject, "mLpChanged");
if (mLpChanged == null) return;
long userActivityTimeout = XposedHelpers.getLongField(mLpChanged, "userActivityTimeout");
if (userActivityTimeout > 0)
XposedHelpers.setLongField(mLpChanged, "userActivityTimeout", MainModule.mPrefs.getInt("system_lstimeout", 9) * 1000L);
}
});
}
private static final SimpleDateFormat formatter = new SimpleDateFormat("H:m", Locale.ENGLISH);
public static void MuffledVibrationHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.VibratorService", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = new Handler(mContext.getMainLooper());
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if (key.contains("pref_key_system_vibration_amp_")) MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 100));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.hookAllMethods("com.android.server.VibratorService", lpparam.classLoader, "doVibratorOn", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
float ratio_ringer = MainModule.mPrefs.getInt("system_vibration_amp_ringer", 100) / 100f;
float ratio_notif = MainModule.mPrefs.getInt("system_vibration_amp_notif", 100) / 100f;
float ratio_other = MainModule.mPrefs.getInt("system_vibration_amp_other", 100) / 100f;
boolean isRingtone = false;
boolean isNotification = false;
Object mCurrentVibration = XposedHelpers.getObjectField(param.thisObject, "mCurrentVibration");
if (mCurrentVibration != null) try {
isRingtone = (boolean)XposedHelpers.callMethod(mCurrentVibration, "isRingtone");
isNotification = (boolean)XposedHelpers.callMethod(mCurrentVibration, "isNotification");
} catch (Throwable t) {
int mUsageHint = XposedHelpers.getIntField(mCurrentVibration, "mUsageHint");
isRingtone = mUsageHint == 6;
isNotification = mUsageHint == 5 || mUsageHint == 7 || mUsageHint == 8 || mUsageHint == 9;
}
float ratio;
if (isRingtone) ratio = ratio_ringer;
else if (isNotification) ratio = ratio_notif;
else ratio = ratio_other;
if (ratio == 1.0f) return;
String key = "system_vibration_amp_period";
int start_hour = MainModule.mPrefs.getInt(key + "_start_hour", 0);
int start_minute = MainModule.mPrefs.getInt(key + "_start_minute", 0);
int end_hour = MainModule.mPrefs.getInt(key + "_end_hour", 0);
int end_minute = MainModule.mPrefs.getInt(key + "_end_minute", 0);
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()));
boolean insidePeriod = start.before(end) ? now.after(start) && now.before(end) : now.before(end) || now.after(start);
if (!insidePeriod) return;
boolean mSupportsAmplitudeControl = false;
try {
mSupportsAmplitudeControl = XposedHelpers.getBooleanField(param.thisObject, "mSupportsAmplitudeControl");
} catch (Throwable ignored) {}
if (mSupportsAmplitudeControl)
param.args[1] = Math.round(((int)param.args[1] == -1 ? XposedHelpers.getIntField(param.thisObject, "mDefaultVibrationAmplitude") : (int)param.args[1]) * ratio);
else
param.args[0] = Math.max(3, (long)Math.round((long)param.args[0] * ratio));
}
});
// if (Helpers.isNougat())
// Helpers.hookAllMethods("com.android.server.VibratorService", lpparam.classLoader, "vibratePattern", new MethodHook() {
// @Override
// protected void before(final MethodHookParam param) throws Throwable {
//
// }
// });
}
public static void ResizableWidgetsHook() {
Helpers.findAndHookMethod("android.appwidget.AppWidgetHostView", null, "getAppWidgetInfo", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
AppWidgetProviderInfo widgetInfo = (AppWidgetProviderInfo)param.getResult();
if (widgetInfo == null) return;
widgetInfo.resizeMode = AppWidgetProviderInfo.RESIZE_BOTH;
widgetInfo.minHeight = 0;
widgetInfo.minWidth = 0;
widgetInfo.minResizeHeight = 0;
widgetInfo.minResizeWidth = 0;
param.setResult(widgetInfo);
}
});
Helpers.findAndHookMethod("android.appwidget.AppWidgetManager", null, "getAppWidgetInfo", int.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
AppWidgetProviderInfo widgetInfo = (AppWidgetProviderInfo)param.getResult();
if (widgetInfo == null) return;
widgetInfo.resizeMode = AppWidgetProviderInfo.RESIZE_BOTH;
widgetInfo.minHeight = 0;
widgetInfo.minWidth = 0;
widgetInfo.minResizeHeight = 0;
widgetInfo.minResizeWidth = 0;
param.setResult(widgetInfo);
}
});
}
@SuppressWarnings("ConstantConditions")
private static void hookUpdateTime(Object thisObject) {
try {
TextView mCurrentDate = null;
TextView mCurrentDateLarge = null;
try { mCurrentDate = (TextView)XposedHelpers.getObjectField(thisObject, "mCurrentDate"); } catch (Throwable ignore) {}
try { mCurrentDateLarge = (TextView)XposedHelpers.getObjectField(thisObject, "mCurrentDateLarge"); } catch (Throwable ignore) {}
if (mCurrentDate == null && mCurrentDateLarge == null) return;
Context mContext = mCurrentDate != null ? mCurrentDate.getContext() : mCurrentDateLarge.getContext();
long timestamp = Helpers.getNextMIUIAlarmTime(mContext);
if (timestamp == 0 && MainModule.mPrefs.getBoolean("system_lsalarm_all"))
timestamp = Helpers.getNextStockAlarmTime(mContext);
if (timestamp == 0) return;
StringBuilder alarmStr = new StringBuilder();
alarmStr.append("\n").append(Helpers.getModuleRes(mContext).getString(R.string.system_statusbaricons_alarm_title)).append(" ");
int format = MainModule.mPrefs.getStringAsInt("system_lsalarm_format", 1);
if (format == 1 || format == 3) {
SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormat.getBestDateTimePattern(Locale.getDefault(), DateFormat.is24HourFormat(mContext) ? "EHmm" : "EHmma"), Locale.getDefault());
dateFormat.setTimeZone(TimeZone.getDefault());
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calendar.setTimeInMillis(timestamp);
alarmStr.append(dateFormat.format(calendar.getTime()));
}
if (format == 2 || format == 3) {
StringBuilder timeStr = new StringBuilder(DateUtils.getRelativeTimeSpanString(timestamp, currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
timeStr.setCharAt(0, Character.toLowerCase(timeStr.charAt(0)));
alarmStr.append(format == 3 ? " (" + timeStr + ")" : timeStr);
}
int pos = Settings.System.getInt(mContext.getContentResolver(), "selected_keyguard_clock_position", 0);
if (mCurrentDate != null) {
mCurrentDate.setTextAlignment(View.TEXT_ALIGNMENT_INHERIT);
mCurrentDate.setLineSpacing(0, 1.5f);
mCurrentDate.append(alarmStr);
if (pos != 2 && pos != 4) mCurrentDate.setTextAlignment(View.TEXT_ALIGNMENT_CENTER);
}
if (mCurrentDateLarge != null) {
int resId = mCurrentDateLarge.getResources().getIdentifier("miui_clock_date_text_size", "dimen", "com.android.systemui");
int fontSize = resId == 0 ? Math.round(mCurrentDateLarge.getResources().getDisplayMetrics().density * 14.0f) : mCurrentDateLarge.getResources().getDimensionPixelSize(resId);
alarmStr.insert(1, "\n\n ");
SpannableString span = new SpannableString(alarmStr);
span.setSpan(new AbsoluteSizeSpan(fontSize, false), 0, alarmStr.length(), 0);
span.setSpan(new TypefaceSpan("sans-serif"), 0, alarmStr.length(), 0);
mCurrentDateLarge.append(span);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void LockScreenAlaramHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.keyguard.KeyguardUpdateMonitor", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
new Helpers.SharedPrefObserver(mContext, new Handler(mContext.getMainLooper())) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if ("pref_key_system_lsalarm_all".equals(key)) MainModule.mPrefs.put(key, Helpers.getSharedBoolPref(mContext, key, false));
if ("pref_key_system_lsalarm_format".equals(key)) MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, "1"));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
if (Helpers.is12())
Helpers.findAndHookMethod("com.android.keyguard.clock.MiuiKeyguardSingleClock", lpparam.classLoader, "updateTime", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object mMiuiBaseClock = XposedHelpers.getObjectField(param.thisObject, "mMiuiBaseClock");
if (mMiuiBaseClock != null) hookUpdateTime(mMiuiBaseClock);
}
});
else if (!Helpers.findAndHookMethodSilently("com.android.keyguard.MiuiKeyguardBaseClock", lpparam.classLoader, "updateTime", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
hookUpdateTime(param.thisObject);
}
})) Helpers.findAndHookMethod("com.android.keyguard.MiuiKeyguardClock", lpparam.classLoader, "updateTime", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
hookUpdateTime(param.thisObject);
}
});
}
private static boolean isSlidingStart = false;
private static boolean isSliding = false;
private static float tapStartX = 0;
private static float tapStartY = 0;
private static float tapStartPointers = 0;
private static float tapStartBrightness = 0;
private static float currentTouchX = 0;
private static long currentTouchTime = 0;
public static void StatusBarGesturesHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "makeStatusBarView", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
new Helpers.SharedPrefObserver(mContext, new Handler(mContext.getMainLooper())) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if ("pref_key_system_statusbarcontrols_single".equals(key) || "pref_key_system_statusbarcontrols_dual".equals(key))
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, "1"));
else if ("pref_key_system_statusbarcontrols_sens_bright".equals(key) || "pref_key_system_statusbarcontrols_sens_vol".equals(key))
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, "2"));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.PanelView", lpparam.classLoader, "setExpandedHeightInternal", new MethodHook() {
@Override
protected void before(final MethodHookParam param) throws Throwable {
float mExpandedFraction = XposedHelpers.getFloatField(param.thisObject, "mExpandedFraction");
if (mExpandedFraction > 0.33f) {
currentTouchTime = 0;
currentTouchX = 0;
}
}
});
final Class<?> buCls = XposedHelpers.findClassIfExists("com.android.settingslib.display.BrightnessUtils", lpparam.classLoader);
MethodHook hook = new MethodHook() {
@Override
@SuppressLint("SetTextI18n")
protected void before(final MethodHookParam param) throws Throwable {
boolean isInControlCenter = Helpers.is12() && "ControlPanelWindowView".equals(param.thisObject.getClass().getSimpleName());
Context mContext = isInControlCenter ? ((View)param.thisObject).getContext() : (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Resources res = mContext.getResources();
int sbHeight = res.getDimensionPixelSize(res.getIdentifier("status_bar_height", "dimen", "android"));
MotionEvent event = (MotionEvent)param.args[0];
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
tapStartX = event.getX();
tapStartY = event.getY();
isSlidingStart = isInControlCenter ? tapStartY <= sbHeight : !XposedHelpers.getBooleanField(param.thisObject, "mPanelExpanded");
tapStartPointers = 1;
tapStartBrightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);
if (MainModule.mPrefs.getBoolean("system_showpct")) {
ViewGroup mStatusBarWindow = isInControlCenter ? (ViewGroup)param.thisObject : (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mStatusBarWindow");
if (mStatusBarWindow == null)
Helpers.log("StatusBarGesturesHook", "mStatusBarWindow is null");
else
initPct(mStatusBarWindow, 2);
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
tapStartPointers = event.getPointerCount();
break;
case MotionEvent.ACTION_UP:
long lastTouchTime = currentTouchTime;
float lastTouchX = currentTouchX;
currentTouchTime = currentTimeMillis();
currentTouchX = event.getX();
if (currentTouchTime - lastTouchTime < 250L && Math.abs(currentTouchX - lastTouchX) < 100F) {
GlobalActions.handleAction(mContext, "pref_key_system_statusbarcontrols_dt");
currentTouchTime = 0L;
currentTouchX = 0F;
}
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_CANCEL:
isSlidingStart = false;
isSliding = false;
if (mPct != null) mPct.setVisibility(View.GONE);
break;
case MotionEvent.ACTION_MOVE:
if (!isSlidingStart) return;
DisplayMetrics metrics = res.getDisplayMetrics();
if (event.getY() - tapStartY > sbHeight) return;
float delta = event.getX() - tapStartX;
if (delta == 0) return;
if (!isSliding && Math.abs(delta) > metrics.widthPixels / 10f) isSliding = true;
if (!isSliding) return;
int opt = MainModule.mPrefs.getStringAsInt(tapStartPointers == 2 ? "system_statusbarcontrols_dual" : "system_statusbarcontrols_single", 1);
if (opt == 2) {
ContentResolver resolver = mContext.getContentResolver();
int sens = MainModule.mPrefs.getStringAsInt("system_statusbarcontrols_sens_bright", 2);
int minLevel = res.getInteger(res.getIdentifier("config_screenBrightnessSettingMinimum", "integer", "android"));
int maxLevel = res.getInteger(res.getIdentifier("config_screenBrightnessSettingMaximum", "integer", "android"));
boolean isHLG = maxLevel != 255;
float ratio = delta / metrics.widthPixels;
if (isHLG) ratio = (ratio >= 0 ? 1 : -1) * (sens == 1 ? 0.66f : (sens == 3 ? 1.66f : 1.0f)) * (float)Math.pow(ratio, 2);
int nextLevel = Math.min(maxLevel, Math.max(minLevel, Math.round(tapStartBrightness + (maxLevel - minLevel) * ratio)));
if (!Helpers.isPiePlus()) try {
int brightnessMode = Settings.System.getInt(resolver, Settings.System.SCREEN_BRIGHTNESS_MODE, 0);
if (brightnessMode == android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC) {
float adj = nextLevel * 2.0f / (maxLevel - minLevel) - 1.0f;
XposedHelpers.callStaticMethod(findClass("com.android.systemui.SystemUICompat", lpparam.classLoader), "setTemporaryScreenAutoBrightness", adj);
Settings.System.putFloat(resolver, "screen_auto_brightness_adj", adj);
} else {
XposedHelpers.callStaticMethod(findClass("com.android.systemui.SystemUICompat", lpparam.classLoader), "setTemporaryScreenBrightness", nextLevel);
}
} catch (Throwable ignore) {}
Settings.System.putInt(resolver, Settings.System.SCREEN_BRIGHTNESS, nextLevel);
if (MainModule.mPrefs.getBoolean("system_showpct") && mPct != null) {
if (mPct.getVisibility() == View.GONE) {
mPct.setVisibility(View.VISIBLE);
mPct.animate().alpha(1.0f).setDuration(300).start();
}
int nextLevelGamma = nextLevel;
if (isHLG && buCls != null)
nextLevelGamma = (int)XposedHelpers.callStaticMethod(buCls, "convertLinearToGamma", nextLevel, minLevel, maxLevel);
if ((int)mPct.getTag() == 2) mPct.setText(((nextLevelGamma * 100) / maxLevel) + "%");
}
} else if (opt == 3) {
int sens = MainModule.mPrefs.getStringAsInt("system_statusbarcontrols_sens_vol", 2);
if (Math.abs(delta) < metrics.widthPixels / ((sens == 1 ? 0.66f : (sens == 3 ? 1.66f : 1.0f)) * 20 * metrics.density)) return;
tapStartX = event.getX();
AudioManager audioManager = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
audioManager.adjustVolume(delta > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER, 1 << 12 /* FLAG_FROM_KEY */ | AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_ALLOW_RINGER_MODES | AudioManager.FLAG_VIBRATE);
}
break;
}
}
};
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "interceptTouchEvent", MotionEvent.class, hook);
if (Helpers.is12())
Helpers.findAndHookMethod("com.android.systemui.miui.statusbar.phone.ControlPanelWindowView", lpparam.classLoader, "onTouchEvent", MotionEvent.class, hook);
}
public static void ScreenshotConfigHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.screenshot.SaveImageInBackgroundTask", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
try {
OutputStream mOutputStream = (OutputStream)XposedHelpers.getObjectField(param.thisObject, "mOutputStream");
if (mOutputStream != null) mOutputStream.close();
String filePath = (String)XposedHelpers.getObjectField(param.thisObject, "mImageFilePath");
new File(filePath).delete();
} catch (Throwable ignore) {}
Context context = (Context)param.args[0];
int folder = Integer.parseInt(Helpers.getSharedStringPref(context, "pref_key_system_screenshot_path", "1"));
String dir = Helpers.getSharedStringPref(context, "pref_key_system_screenshot_mypath", "");
File mScreenshotDir;
if (folder > 1) {
if (folder == 4 && !TextUtils.isEmpty(dir))
mScreenshotDir = new File(dir);
else
mScreenshotDir = new File(Environment.getExternalStoragePublicDirectory(folder == 2 ? Environment.DIRECTORY_PICTURES : Environment.DIRECTORY_DCIM), "Screenshots");
if (!mScreenshotDir.exists()) mScreenshotDir.mkdirs();
} else {
mScreenshotDir = (File)XposedHelpers.getObjectField(param.thisObject, "mScreenshotDir");
}
boolean hasTemp = false;
String mTempImageFilePath = null;
try {
mTempImageFilePath = (String)XposedHelpers.getObjectField(param.thisObject, "mTempImageFilePath");
hasTemp = true;
} catch (Throwable ignore) {}
String mImageFileName = (String)XposedHelpers.getObjectField(param.thisObject, "mImageFileName");
String mImageFilePath = String.format("%s/%s", mScreenshotDir, mImageFileName);
if (hasTemp) mTempImageFilePath = String.format("%s/%s", mScreenshotDir, "." + mImageFileName);
int quality = Helpers.getSharedIntPref(context, "pref_key_system_screenshot_quality", 100);
int format = Integer.parseInt(Helpers.getSharedStringPref(context, "pref_key_system_screenshot_format", "2"));
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mScreenshotQuality", quality);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mScreenshotFormat", format);
String ext = format <= 2 ? ".jpg" : (format == 3 ? ".png" : ".webp");
mImageFileName = mImageFileName.replace(".png", "").replace(".jpg", "").replace(".webp", "") + ext;
mImageFilePath = mImageFilePath.replace(".png", "").replace(".jpg", "").replace(".webp", "") + ext;
XposedHelpers.setObjectField(param.thisObject, "mImageFileName", mImageFileName);
XposedHelpers.setObjectField(param.thisObject, "mImageFilePath", mImageFilePath);
Object mNotifyMediaStoreData = XposedHelpers.getObjectField(param.thisObject, "mNotifyMediaStoreData");
XposedHelpers.setObjectField(mNotifyMediaStoreData, "imageFileName", mImageFileName);
XposedHelpers.setObjectField(mNotifyMediaStoreData, "imageFilePath", mImageFilePath);
if (hasTemp) {
XposedHelpers.setObjectField(param.thisObject, "mTempImageFilePath", mTempImageFilePath);
XposedHelpers.setObjectField(mNotifyMediaStoreData, "tempImageFilePath", mTempImageFilePath);
}
}
});
Helpers.hookAllMethods("com.android.systemui.screenshot.SaveImageInBackgroundTask", lpparam.classLoader, "doInBackground", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Object[] data = (Object[])param.args[0];
if (data == null || data.length != 1) return;
Bitmap image = (Bitmap)XposedHelpers.getObjectField(data[0], "image");
if (image == null) return;
int format = 2;
int quality = 100;
try {
format = (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mScreenshotFormat");
quality = (int)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mScreenshotQuality");
} catch (Throwable t) {
XposedBridge.log(t);
}
FileOutputStream mCustomOutputStream;
try {
String mTempImageFilePath = (String)XposedHelpers.getObjectField(param.thisObject, "mTempImageFilePath");
File shot = new File(mTempImageFilePath);
if (shot.exists()) shot.delete();
mCustomOutputStream = new FileOutputStream(mTempImageFilePath);
} catch (Throwable t) {
String mImageFilePath = (String)XposedHelpers.getObjectField(param.thisObject, "mImageFilePath");
File shot = new File(mImageFilePath);
if (shot.exists()) shot.delete();
mCustomOutputStream = new FileOutputStream(mImageFilePath);
}
Bitmap.CompressFormat compress = format <= 2 ? Bitmap.CompressFormat.JPEG : (format == 3 ? Bitmap.CompressFormat.PNG : Bitmap.CompressFormat.WEBP);
image.compress(compress, quality, mCustomOutputStream);
mCustomOutputStream.flush();
mCustomOutputStream.close();
try {
XposedHelpers.setObjectField(param.thisObject, "mOutputStream", new ByteArrayOutputStream());
} catch (Throwable ignore) {}
}
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// Object data = param.getResult();
// if (data != null) XposedHelpers.setIntField(data, "result", 0);
// }
});
}
public static void NoNetworkSpeedSeparatorHook(LoadPackageParam lpparam) {
// Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBarFactory", lpparam.classLoader, "getCollapsedStatusBarFragmentController", new MethodHook() {
// @Override
// protected void before(MethodHookParam param) throws Throwable {
// Class cls = XposedHelpers.findClass("com.android.systemui.statusbar.phone.StatusBarTypeController$CutoutType", lpparam.classLoader);
// XposedBridge.log("new: " + cls.getEnumConstants()[3]);
// param.args[0] = cls.getEnumConstants()[3];
// }
// });
Helpers.hookAllConstructors("com.android.systemui.statusbar.NetworkSpeedSplitter", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
((TextView)param.thisObject).setText("");
}
});
Helpers.findAndHookMethod("com.android.systemui.statusbar.NetworkSpeedSplitter", lpparam.classLoader, "init", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
((TextView)param.thisObject).setText("");
}
});
}
public static void ToastTimeHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.server.notification.NotificationManagerService", lpparam.classLoader, "showNextToastLocked", new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.callMethod(param.thisObject, "getContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
ArrayList<Object> mToastQueue = (ArrayList<Object>)XposedHelpers.getObjectField(param.thisObject, "mToastQueue");
if (mContext == null || mHandler == null || mToastQueue == null || mToastQueue.size() == 0) return;
int mod = (Helpers.getSharedIntPref(mContext, "pref_key_system_toasttime", 0) - 4) * 1000;
for (Object record: mToastQueue)
if (record != null && mHandler.hasMessages(2, record)) {
mHandler.removeCallbacksAndMessages(record);
int duration = XposedHelpers.getIntField(record, "duration");
int delay = Math.max(1000, (duration == 1 ? 3500 : 2000) + mod);
mHandler.sendMessageDelayed(Message.obtain(mHandler, 2, record), delay);
}
}
});
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "systemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler, "pref_key_system_toasttime", 0) {
@Override
public void onChange(String name, int defValue) {
MainModule.mPrefs.put(name, Helpers.getSharedIntPref(mContext, name, defValue));
}
};
}
});
String windowClass = Helpers.isQPlus() ? "com.android.server.wm.DisplayPolicy" : "com.android.server.policy.PhoneWindowManager";
Helpers.hookAllMethods(windowClass, lpparam.classLoader, "adjustWindowParamsLw", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
Object lp = param.args.length == 1 ? param.args[0] : param.args[1];
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mPrevHideTimeout", XposedHelpers.getLongField(lp, "hideTimeoutMilliseconds"));
}
@Override
protected void after(MethodHookParam param) throws Throwable {
Object lp = param.args.length == 1 ? param.args[0] : param.args[1];
long mPrevHideTimeout = (long)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mPrevHideTimeout");
long mHideTimeout = XposedHelpers.getLongField(lp, "hideTimeoutMilliseconds");
if (mPrevHideTimeout == -1 || mHideTimeout == -1) return;
long dur = 0;
if (mPrevHideTimeout == 1000 || mPrevHideTimeout == 4000 || mPrevHideTimeout == 5000 || mPrevHideTimeout == 7000 || mPrevHideTimeout != mHideTimeout)
dur = Math.max(1000, 3500 + (MainModule.mPrefs.getInt("system_toasttime", 0) - 4) * 1000);
if (dur != 0) XposedHelpers.setLongField(lp, "hideTimeoutMilliseconds", dur);
}
});
}
public static void ClearAllTasksHook(LoadPackageParam lpparam) {
String wpuClass = Helpers.isQPlus() ? "com.android.server.wm.WindowProcessUtils" : "com.android.server.am.ProcessUtils";
Helpers.hookAllMethods(wpuClass, lpparam.classLoader, "getPerceptibleRecentAppList", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
param.setResult(null);
}
});
}
private static int hours3ResId;
private static int hours4ResId;
private static int hours5ResId;
private static int hours6ResId;
private static int hours8ResId;
private static int hours10ResId;
private static int hours12ResId;
private static int foreverResId;
public static void MoreSnoozeOptionsRes() {
hours3ResId = MainModule.resHooks.addResource("time_3h", R.string.time_3h);
hours4ResId = MainModule.resHooks.addResource("time_4h", R.string.time_4h);
hours5ResId = MainModule.resHooks.addResource("time_5h", R.string.time_5h);
hours6ResId = MainModule.resHooks.addResource("time_6h", R.string.time_6h);
hours8ResId = MainModule.resHooks.addResource("time_8h", R.string.time_8h);
hours10ResId = MainModule.resHooks.addResource("time_10h", R.string.time_10h);
hours12ResId = MainModule.resHooks.addResource("time_12h", R.string.time_12h);
foreverResId = MainModule.resHooks.addResource("time_forever", R.string.time_forever);
}
public static void MoreSnoozeOptionsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationSnooze", lpparam.classLoader, "getDefaultSnoozeOptions", new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(MethodHookParam param) throws Throwable {
ArrayList<Object> options = (ArrayList<Object>)param.getResult();
if (options == null) return;
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours3ResId, 180));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours4ResId, 240));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours5ResId, 300));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours6ResId, 360));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours8ResId, 480));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours10ResId, 600));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", hours12ResId, 720));
options.add(XposedHelpers.callMethod(param.thisObject, "createOption", foreverResId, 1024));
}
});
if (Helpers.is12())
Helpers.findAndHookMethod("com.android.systemui.statusbar.NotificationSnooze", lpparam.classLoader, "createOptionViews", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
LinearLayout mSnoozeOptionContainer = (LinearLayout)XposedHelpers.getObjectField(param.thisObject, "mSnoozeOptionContainer");
ViewGroup parent = ((ViewGroup)mSnoozeOptionContainer.getParent());
if (parent.getClass() == ScrollView.class) return;
parent.removeView(mSnoozeOptionContainer);
HorizontalScrollView scrollView = new HorizontalScrollView(mSnoozeOptionContainer.getContext());
scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
scrollView.setVerticalScrollBarEnabled(false);
scrollView.setHorizontalScrollBarEnabled(false);
scrollView.addView(mSnoozeOptionContainer);
parent.addView(scrollView);
ViewGroup.LayoutParams lp1 = scrollView.getLayoutParams();
lp1.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp1.height = ViewGroup.LayoutParams.WRAP_CONTENT;
scrollView.setLayoutParams(lp1);
ViewGroup.MarginLayoutParams lp2 = (ViewGroup.MarginLayoutParams)mSnoozeOptionContainer.getLayoutParams();
lp2.setMarginStart(0);
lp2.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp2.height = ViewGroup.LayoutParams.WRAP_CONTENT;
mSnoozeOptionContainer.setLayoutParams(lp2);
}
});
}
public static void MoreSnoozeOptionsServiceHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.notification.SnoozeHelper", lpparam.classLoader, "scheduleRepost", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if ((long)param.args[3] == 1024 * 60000) param.setResult(null);
}
@Override
@SuppressWarnings("unchecked")
protected void after(MethodHookParam param) throws Throwable {
if ((long)param.args[3] == 1024 * 60000) return;
ArrayMap<String, Long> mSnoozedNotificationDelays = (ArrayMap<String, Long>)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSnoozedNotificationDelays");
if (mSnoozedNotificationDelays == null) mSnoozedNotificationDelays = new ArrayMap<String, Long>();
mSnoozedNotificationDelays.put((String)param.args[1], currentTimeMillis() + (long)param.args[3]);
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mSnoozedNotificationDelays", mSnoozedNotificationDelays);
}
});
Helpers.findAndHookMethod("com.android.server.notification.SnoozeHelper", lpparam.classLoader, "repost", String.class, int.class, new MethodHook() {
@Override
@SuppressWarnings({"unchecked", "SuspiciousMethodCalls"})
protected void after(MethodHookParam param) throws Throwable {
ArrayMap<String, Long> mSnoozedNotificationDelays = (ArrayMap<String, Long>)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSnoozedNotificationDelays");
if (mSnoozedNotificationDelays != null) mSnoozedNotificationDelays.remove(param.args[0]);
}
});
Helpers.hookAllConstructors("com.android.server.notification.SnoozeHelper", lpparam.classLoader, new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(MethodHookParam param) throws Throwable {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_PREFIX + "GetSnoozedNotifications");
filter.addAction(ACTION_PREFIX + "UnsnoozeNotification");
filter.addAction(ACTION_PREFIX + "CancelNotification");
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
ArrayMap<Integer, ArrayMap<String, ArrayMap<String, Object>>> mSnoozedNotifications = (ArrayMap<Integer, ArrayMap<String, ArrayMap<String, Object>>>)XposedHelpers.getObjectField(param.thisObject, "mSnoozedNotifications");
ArrayMap<String, Long> mSnoozedNotificationDelays = (ArrayMap<String, Long>)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSnoozedNotificationDelays");
if (action.equals(ACTION_PREFIX + "CancelNotification")) try {
ArrayMap<String, ArrayMap<String, Object>> packages = mSnoozedNotifications.get(intent.getIntExtra("user", 0));
if (packages == null) return;
ArrayMap<String, Object> notificatios = packages.get(intent.getStringExtra("package"));
if (notificatios == null) return;
if (notificatios.containsKey(intent.getStringExtra("key")))
XposedHelpers.setBooleanField(notificatios.get(intent.getStringExtra("key")), "isCanceled", intent.getBooleanExtra("canceled", false));
return;
} catch (Throwable t) {
XposedBridge.log(t);
}
if (action.equals(ACTION_PREFIX + "UnsnoozeNotification")) try {
XposedHelpers.callMethod(param.thisObject, "repost", intent.getStringExtra("key"), intent.getIntExtra("user", 0));
} catch (Throwable t) {
XposedBridge.log(t);
}
try {
Bundle notifications = new Bundle();
int user;
String pkg;
for (int i = 0; i < mSnoozedNotifications.size(); i++ ) {
user = mSnoozedNotifications.keyAt(i);
ArrayMap<String, ArrayMap<String, Object>> mSnoozedNotification = mSnoozedNotifications.get(mSnoozedNotifications.keyAt(i));
for (int j = 0; j < mSnoozedNotification.size(); j++ ) {
pkg = mSnoozedNotification.keyAt(j);
ArrayMap<String, Object> mSnoozed = mSnoozedNotification.get(mSnoozedNotification.keyAt(j));
for (int k = 0; k < mSnoozed.size(); k++) {
String key = mSnoozed.keyAt(k);
Bundle notif = new Bundle();
notif.putInt("user", user);
notif.putString("package", pkg);
notif.putString("key", key);
Object record = mSnoozed.get(key);
notif.putBoolean("canceled", XposedHelpers.getBooleanField(record, "isCanceled"));
notif.putLong("created", XposedHelpers.getLongField(record, "mCreationTimeMs"));
notif.putLong("updated", XposedHelpers.getLongField(record, "mUpdateTimeMs"));
if (mSnoozedNotificationDelays != null && mSnoozedNotificationDelays.get(key) != null)
notif.putLong("reposted", mSnoozedNotificationDelays.get(key));
Object sbn = XposedHelpers.getObjectField(record, "sbn");
Notification notification = (Notification)XposedHelpers.getObjectField(sbn, "notification");
if (notification != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
notif.putString("channel", notification.getChannelId());
notif.putInt("color", notification.color);
if (notification.getLargeIcon() != null)
notif.putParcelable("icon", notification.getLargeIcon());
if (notification.extras != null) {
notif.putString("title", notification.extras.getCharSequence(Notification.EXTRA_TITLE).toString());
CharSequence text = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT, null);
if (text == null || "" == text) text = notification.extras.getCharSequence(Notification.EXTRA_TEXT, null);
if (text != null && "" != text) {
String[] lines = text.toString().split("\\n");
notif.putString("text", lines[0] + (lines.length == 1 ? "" : "..."));
}
Parcelable[] messages = notification.extras.getParcelableArray(Notification.EXTRA_MESSAGES);
if (messages != null) notif.putInt("messages", messages.length);
}
}
notifications.putBundle(mSnoozed.keyAt(k), notif);
}
}
}
Intent snoozedIntent = new Intent(GlobalActions.EVENT_PREFIX + "UpdateSnoozedNotifications");
snoozedIntent.setPackage(Helpers.modulePkg);
snoozedIntent.putExtras(notifications);
mContext.sendBroadcast(snoozedIntent);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, filter);
}
});
}
public static void InactiveBrightnessSliderHook(LoadPackageParam lpparam) {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = MainModule.mPrefs.getStringAsInt("system_inactivebrightness", 1);
if (opt == 2) {
SeekBar mSlider = (SeekBar)XposedHelpers.getObjectField(param.thisObject, "mSlider");
if (mSlider != null)
mSlider.setOnTouchListener(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
} else if (opt == 3) try {
View sliderView = (View)param.thisObject;
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)sliderView.getLayoutParams();
lp.height = 0;
lp.topMargin = Math.round(2 * sliderView.getResources().getDisplayMetrics().density);
lp.bottomMargin = 0;
sliderView.setLayoutParams(lp);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
Helpers.findAndHookMethod("com.android.systemui.settings.ToggleSliderView", lpparam.classLoader, "onAttachedToWindow", hook);
if (Helpers.is12())
Helpers.findAndHookMethod("com.android.systemui.miui.controlcenter.QCToggleSliderView", lpparam.classLoader, "onAttachedToWindow", hook);
}
private static final float[] startPos = new float[2];
private static void processLSEvent(MethodHookParam param) {
MotionEvent event = (MotionEvent)param.args[0];
if (event.getPointerCount() > 1) return;
int action = event.getActionMasked();
if (action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_UP) return;
ViewGroup mKeyguardBottomArea = (ViewGroup)XposedHelpers.getObjectField(param.thisObject, "mKeyguardBottomArea");
if (mKeyguardBottomArea == null) return;
ViewGroup mIndicationArea = (ViewGroup)XposedHelpers.getObjectField(mKeyguardBottomArea, "mIndicationArea");
if (!Helpers.isReallyVisible(mIndicationArea)) return;
int[] coord = new int[2];
mIndicationArea.getLocationOnScreen(coord);
Rect rect = new Rect(coord[0], coord[1], coord[0] + mIndicationArea.getWidth(), coord[1] + mIndicationArea.getHeight());
if (!rect.contains((int)event.getX(), (int)event.getY())) return;
if (action == MotionEvent.ACTION_DOWN) {
startPos[0] = event.getX();
startPos[1] = event.getY();
} else if (action == MotionEvent.ACTION_UP) try {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
if (Math.abs(event.getX() - startPos[0]) > slop || Math.abs(event.getY() - startPos[1]) > slop) return;
Object mStatusBar = XposedHelpers.getObjectField(param.thisObject, "mStatusBar");
XposedHelpers.callMethod(mStatusBar, "showBouncer");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void TapToUnlockHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "onTouchEvent", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
processLSEvent(param);
}
});
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "onInterceptTouchEvent", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
processLSEvent(param);
}
});
}
public static void NoSafeVolumeWarningRes() {
MainModule.resHooks.setObjectReplacement("android", "bool", "config_safe_media_volume_enabled", false);
MainModule.resHooks.setObjectReplacement("android", "bool", "config_safe_media_disable_on_volume_up", false);
}
public static void NoLowBatteryWarningHook() {
Helpers.hookAllMethods(Settings.System.class, "getIntForUser", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
String key = (String)param.args[1];
if ("low_battery_dialog_disabled".equals(key)) param.setResult(1);
}
});
}
public static void TempHideOverlayHook() {
Helpers.hookAllMethods("android.view.WindowManagerGlobal", null, "addView", new MethodHook() {
@Override
@SuppressWarnings("ConstantConditions")
protected void after(final MethodHookParam param) throws Throwable {
if (param.args[0] == null || !(param.args[1] instanceof WindowManager.LayoutParams) || param.getThrowable() != null) return;
WindowManager.LayoutParams params = (WindowManager.LayoutParams)param.args[1];
final View view = (View)param.args[0];
if (params.type != WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY && params.type != WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY) return;
XposedHelpers.setAdditionalInstanceField(view, "mSavedVisibility", view.getVisibility());
view.getContext().registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (view == null) return;
boolean state = intent.getBooleanExtra("IsFinished", true);
if (state) {
view.setVisibility((int)XposedHelpers.getAdditionalInstanceField(view, "mSavedVisibility"));
} else if (view.getVisibility() != View.GONE) {
XposedHelpers.setAdditionalInstanceField(view, "mSavedVisibility", view.getVisibility());
view.setVisibility(View.GONE);
}
}
}, new IntentFilter("miui.intent.TAKE_SCREENSHOT"));
}
});
}
public static void ScreenshotFloatTimeHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.screenshot.GlobalScreenshot", lpparam.classLoader, "startGotoThumbnailAnimation", Runnable.class, new MethodHook() {
@Override
@SuppressWarnings("ConstantConditions")
protected void after(MethodHookParam param) throws Throwable {
boolean mIsShowLongScreenShotGuide = false;
try {
mIsShowLongScreenShotGuide = XposedHelpers.getBooleanField(param.thisObject, "mIsShowLongScreenShotGuide");
} catch (Throwable ignore) {}
if (mIsShowLongScreenShotGuide) return;
int opt = MainModule.mPrefs.getInt("system_screenshot_floattime", 0);
if (opt <= 0) return;
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
Runnable mQuitThumbnailRunnable = (Runnable)XposedHelpers.getObjectField(param.thisObject, "mQuitThumbnailRunnable");
mHandler.removeCallbacks(mQuitThumbnailRunnable);
mHandler.postDelayed(mQuitThumbnailRunnable, opt * 1000L);
}
});
}
public static void ScrambleAppLockPINHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.miui.applicationlock.widget.MiuiNumericInputView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
LinearLayout keys = (LinearLayout)param.thisObject;
ArrayList<View> mRandomViews = new ArrayList<View>();
View bottom0 = null; View bottom2 = null;
for (int row = 0; row <= 3; row++) {
ViewGroup cols = (ViewGroup)keys.getChildAt(row);
for (int col = 0; col <= 2; col++) {
if (row == 3)
if (col == 0) {
bottom0 = cols.getChildAt(col);
continue;
} else if (col == 2) {
bottom2 = cols.getChildAt(col);
continue;
}
mRandomViews.add(cols.getChildAt(col));
}
cols.removeAllViews();
}
Collections.shuffle(mRandomViews);
int cnt = 0;
for (int row = 0; row <= 3; row++)
for (int col = 0; col <= 2; col++) {
ViewGroup cols = (ViewGroup)keys.getChildAt(row);
if (row == 3)
if (col == 0) {
cols.addView(bottom0);
continue;
} else if (col == 2) {
cols.addView(bottom2);
continue;
}
cols.addView(mRandomViews.get(cnt));
cnt++;
}
}
});
}
public static void ChargingInfoServiceHook(LoadPackageParam lpparam) {
if (!Helpers.hookAllMethodsSilently("com.android.server.BatteryService$BatteryPropertiesRegistrar", lpparam.classLoader, "getProperty", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int req = (int)param.args[0];
if (req < 1000) return;
long value = Long.MIN_VALUE;
if (req == 1001)
value = XposedHelpers.getIntField(XposedHelpers.getSurroundingThis(param.thisObject), "mLastBatteryVoltage");
else if (req == 1002)
value = XposedHelpers.getIntField(XposedHelpers.getSurroundingThis(param.thisObject), "mLastBatteryTemperature");
else if (req == 1003)
value = XposedHelpers.getIntField(XposedHelpers.getSurroundingThis(param.thisObject), "mLastBatteryHealth");
XposedHelpers.callMethod(param.args[1], "setLong", value);
param.setResult(0);
}
})) Helpers.findAndHookMethod("com.android.server.BatteryService", lpparam.classLoader, "processValuesLocked", boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
try {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
ContentResolver provider = mContext.getContentResolver();
Settings.Global.putInt(provider, Helpers.modulePkg + ".battery.voltage", XposedHelpers.getIntField(param.thisObject, "mLastBatteryVoltage"));
Settings.Global.putInt(provider, Helpers.modulePkg + ".battery.temperature", XposedHelpers.getIntField(param.thisObject, "mLastBatteryTemperature"));
Settings.Global.putInt(provider, Helpers.modulePkg + ".battery.health", XposedHelpers.getIntField(param.thisObject, "mLastBatteryHealth"));
} catch (Throwable ignore) {}
}
});
}
public static void ChargingInfoHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.keyguard.KeyguardUpdateMonitor", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)param.args[0];
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String type = uri.getPathSegments().get(1);
String key = uri.getPathSegments().get(2);
if (!key.contains("pref_key_system_charginginfo_")) return;
switch (type) {
case "string":
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, ""));
break;
case "integer":
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 1));
break;
case "boolean":
MainModule.mPrefs.put(key, Helpers.getSharedBoolPref(mContext, key, false));
break;
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.hookAllMethods("com.android.keyguard.charge.ChargeUtils", lpparam.classLoader, "getChargingHintText", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context context = (Context)param.args[0];
int charge = (int)param.args[2];
String hint = (String)param.getResult();
String PROVIDER_POWER_CENTER = (String)XposedHelpers.getStaticObjectField(findClass("com.android.keyguard.charge.ChargeUtils", lpparam.classLoader), "PROVIDER_POWER_CENTER");
Bundle bundle = null;
try {
bundle = context.getContentResolver().call(Uri.parse(PROVIDER_POWER_CENTER), "getBatteryCurrent", null, null);
} catch (Exception ignore) {}
if (bundle != null && charge < 100) {
boolean showCurr = MainModule.mPrefs.getBoolean("system_charginginfo_current");
boolean showVolt = MainModule.mPrefs.getBoolean("system_charginginfo_voltage");
boolean showWatt = MainModule.mPrefs.getBoolean("system_charginginfo_wattage");
boolean showTemp = MainModule.mPrefs.getBoolean("system_charginginfo_temp");
ArrayList<String> values = new ArrayList<>();
BatteryManager btrMgr = (BatteryManager)context.getSystemService(Context.BATTERY_SERVICE);
int currVal = Math.abs(bundle.getInt("current_now"));
long voltVal = btrMgr.getLongProperty(1001);
if (voltVal == Long.MIN_VALUE) voltVal = Settings.Global.getInt(context.getContentResolver(), Helpers.modulePkg + ".battery.voltage", 0);
if (voltVal == Long.MIN_VALUE) voltVal = 0;
long tempVal = btrMgr.getLongProperty(1002);
if (tempVal == Long.MIN_VALUE) tempVal = Settings.Global.getInt(context.getContentResolver(), Helpers.modulePkg + ".battery.temperature", 0);
if (tempVal == Long.MIN_VALUE) tempVal = 0;
if (showCurr) values.add(currVal + " mA");
if (showVolt) values.add(String.format(Locale.getDefault(), "%.1f", voltVal / 1000f) + " V");
if (showWatt) values.add(String.format(Locale.getDefault(), "%.1f", voltVal / 1000f * currVal / 1000f) + " W");
if (showTemp) values.add(Math.round(tempVal / 10f) + " °C");
if (values.size() == 0) return;
String info = TextUtils.join(" · ", values);
int opt = MainModule.mPrefs.getStringAsInt("system_charginginfo_view", 1);
if (opt == 1)
param.setResult(hint + "\n" + info);
else if (opt == 2)
param.setResult(hint + " · " + info);
else if (opt == 3)
param.setResult(info + " · " + hint);
}
}
});
Helpers.hookAllConstructors("com.android.systemui.statusbar.phone.KeyguardIndicationTextView", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
int opt = MainModule.mPrefs.getStringAsInt("system_charginginfo_view", 1);
if (opt != 1) return;
TextView indicator = (TextView)param.thisObject;
if (indicator != null) indicator.setSingleLine(false);
}
});
}
public static void UseNativeRecentsHook(LoadPackageParam lpparam) {
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("com.android.systemui.recents.misc.SystemServicesProxy", lpparam.classLoader, "isRecentsWithinLauncher", Context.class, XC_MethodReplacement.returnConstant(false));
}
public static void UseNativeRecentsFixHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.wm.TaskRecord", lpparam.classLoader, "isVisible", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if ((boolean)param.getResult()) return;
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
for (StackTraceElement el: stackTrace)
if (el != null) if ("getPerceptibleRecentAppList".equals(el.getMethodName())) {
param.setResult(true);
return;
}
}
});
}
public static void NoUnlockAnimationHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.miui.ActivityObserverImpl", lpparam.classLoader, "isTopActivityLauncher", XC_MethodReplacement.returnConstant(false));
}
public static void NoSOSHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.keyguard.EmergencyButton", lpparam.classLoader, "updateEmergencyCallButton", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Button mSOS = (Button)param.thisObject;
if (mSOS.getVisibility() == View.VISIBLE) mSOS.setEnabled(false);
}
});
}
public static void NoDarkForceHook(LoadPackageParam lpparam) {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ContentResolver contentResolver = ((Context)XposedHelpers.callMethod(param.thisObject, "getContext")).getContentResolver();
XposedHelpers.callStaticMethod(Settings.System.class, "putIntForUser", contentResolver, "smart_dark_enable", 0, XposedHelpers.callStaticMethod(UserHandle.class, "getCallingUserId"));
XposedHelpers.callStaticMethod(XposedHelpers.findClassIfExists("android.os.SystemProperties", lpparam.classLoader), "set", "debug.hwui.force_dark", "false");
}
};
Helpers.findAndHookMethod("com.android.server.UiModeManagerService", lpparam.classLoader, "setForceDark", Context.class, hook);
Helpers.findAndHookMethod("com.android.server.UiModeManagerService", lpparam.classLoader, "setDarkProp", int.class, int.class, hook);
}
public static void MaxNotificationIconsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationIconContainer", lpparam.classLoader, "getMaxIconCount", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
int opt = MainModule.mPrefs.getStringAsInt("system_maxsbicons", 0);
param.setResult(opt == -1 ? 9999 : opt);
}
});
// Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.NotificationIconContainer", lpparam.classLoader, "calculateIconTranslations", new MethodHook() {
// @Override
// @SuppressWarnings("unchecked")
// protected void after(MethodHookParam param) throws Throwable {
// HashMap mIconStates = (HashMap)XposedHelpers.getObjectField(param.thisObject, "mIconStates");
// if (mIconStates.size() == 0) return;
// int opt = MainModule.mPrefs.getStringAsInt("system_maxsbicons", 0);
// ViewGroup container = (ViewGroup)param.thisObject;
// for (int i = 0; i < container.getChildCount(); i++)
// if (opt == -1 || i < opt) {
// Object mIconState = mIconStates.get(container.getChildAt(i));
// if (mIconState == null) continue;
// XposedHelpers.setIntField(mIconState, "visibleState", 0);
// XposedHelpers.setFloatField(mIconState, "iconAppearAmount", 1.0f);
// XposedHelpers.setFloatField(mIconState, "xTranslation", (float)XposedHelpers.callMethod(param.thisObject, "getActualPaddingStart"));
// }
// }
// });
// for (Member method: Math.class.getMethods())
// if (method.getName().equals("min")) Helpers.log("min method found! " + method);
// Set unhooks = XposedBridge.hookAllMethods(Math.class, "min", new MethodHook() {
// @Override
// protected void before(MethodHookParam param) throws Throwable {
// Helpers.log("Math.min: " + param.args[1].getClass().getSimpleName() + ", " + param.args[1]);
// }
// });
// Helpers.log("unhooks: " + unhooks.size());
}
public static void MoreNotificationsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.NotificationData", lpparam.classLoader, "shouldRemove", new MethodHook() {
@Override
@SuppressWarnings({"unchecked", "SynchronizationOnLocalVariableOrMethodParameter"})
protected void before(MethodHookParam param) throws Throwable {
if (param.args[1] == null) return;
ArrayMap<String, ?> mEntries = (ArrayMap<String, ?>)XposedHelpers.getObjectField(param.thisObject, "mEntries");
if (mEntries == null) return;
Object notification;
String pkgName;
String srcPkgName = (String)XposedHelpers.callMethod(XposedHelpers.getObjectField(param.args[1], "notification"), "getPackageName");
int cnt = 0;
synchronized (mEntries) {
for (int i = 0; i < mEntries.size(); i++) {
notification = XposedHelpers.getObjectField(mEntries.valueAt(i), "notification");
if (notification == null) continue;
pkgName = (String)XposedHelpers.callMethod(notification, "getPackageName");
if (pkgName.equals(srcPkgName)) cnt++;
}
}
if (cnt < 24) param.setResult(null);
}
});
}
public static void VolumeDialogDNDSwitchHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.miui.volume.MiuiRingerModeLayout.RingerButtonHelper", lpparam.classLoader, "updateState", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
boolean mExpanded = XposedHelpers.getBooleanField(param.thisObject, "mExpanded");
if (mExpanded) return;
View mStandardView = (View)XposedHelpers.getObjectField(param.thisObject, "mStandardView");
View mDndView = (View)XposedHelpers.getObjectField(param.thisObject, "mDndView");
if (mStandardView != null) mStandardView.setVisibility(View.GONE);
if (mDndView != null) mDndView.setVisibility(View.VISIBLE);
}
});
}
public static void NoMediaMuteInDNDHook() {
Helpers.hookAllMethods("android.media.AudioServiceInjector", null, "handleZenModeChangedForMusic", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if ((int)param.args[2] == 1 || (int)param.args[3] == 1) param.setResult(null);
}
});
}
public static void VolumeDialogAutohideDelayHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.miui.volume.MiuiVolumeDialogImpl", lpparam.classLoader, "computeTimeoutH", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
boolean mHovering = XposedHelpers.getBooleanField(param.thisObject, "mHovering");
if (mHovering) {
param.setResult(16000);
return;
}
Object mSafetyWarning = XposedHelpers.getObjectField(param.thisObject, "mSafetyWarning");
if (mSafetyWarning != null) {
int opt = MainModule.mPrefs.getInt("system_volumedialogdelay_expanded", 0);
param.setResult(opt > 0 ? opt : 5000);
return;
}
boolean mExpanded = XposedHelpers.getBooleanField(param.thisObject, "mExpanded");
int opt = MainModule.mPrefs.getInt(mExpanded ? "system_volumedialogdelay_expanded" : "system_volumedialogdelay_collapsed", 0);
if (opt > 0) param.setResult(opt);
}
});
}
public static ArrayList<SoundData> mLastPlayedSounds = new ArrayList<SoundData>();
public static void AudioSilencerServiceHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "init", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_PREFIX + "SavePlayedSound");
filter.addAction(ACTION_PREFIX + "FetchPlayedSounds");
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
mContext.registerReceiver(new BroadcastReceiver() {
public void onReceive(final Context context, Intent intent) {
String action = intent.getAction();
if (action != null) try {
if (action.equals(ACTION_PREFIX + "SavePlayedSound")) {
SoundData data = intent.getParcelableExtra("data");
mLastPlayedSounds.add(0, data);
if (mLastPlayedSounds.size() > 10)
mLastPlayedSounds = new ArrayList<SoundData>(mLastPlayedSounds.subList(0, 10));
} else if (action.equals(ACTION_PREFIX + "FetchPlayedSounds")) {
Intent soundsIntent = new Intent(GlobalActions.EVENT_PREFIX + "FetchPlayedSoundsData");
soundsIntent.putParcelableArrayListExtra("sounds", mLastPlayedSounds);
soundsIntent.setPackage(Helpers.modulePkg);
mContext.sendBroadcast(soundsIntent);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, filter);
}
});
}
public static void SavePlayedSound(Context context, SoundData data) {
Intent saveSoundIntent = new Intent(ACTION_PREFIX + "SavePlayedSound");
saveSoundIntent.putExtra("data", data);
saveSoundIntent.setPackage("android");
context.sendBroadcast(saveSoundIntent);
}
@SuppressWarnings({"unchecked"})
public static void AudioSilencerHook() {
Helpers.hookAllConstructors(SoundPool.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSourceSoundData") == null) {
SparseArray<SoundData> mSourceSoundData = new SparseArray<SoundData>();
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mSourceSoundData", mSourceSoundData);
}
}
});
Helpers.hookAllMethods(SoundPool.class, "load", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
SparseArray<SoundData> mSourceSoundData = (SparseArray<SoundData>)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSourceSoundData");
Context callerContext = Helpers.findContext();
if (callerContext == null) return;
String caller = callerContext.getPackageName();
if (param.args[0] instanceof Context) {
Context mContext = (Context)param.args[0];
mSourceSoundData.put((int)param.getResult(), new SoundData(caller, "resource", mContext.getResources().getResourceName((int)param.args[1])));
} else if (param.args[0] instanceof String) {
mSourceSoundData.put((int)param.getResult(), new SoundData(caller, "file", (String)param.args[0]));
}
}
});
Helpers.hookAllMethods(SoundPool.class, "play", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
SparseArray<SoundData> mSourceSoundData = (SparseArray<SoundData>)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSourceSoundData");
if (mSourceSoundData != null) {
Context mContext = Helpers.findContext();
if (mContext == null) return;
SoundData data = mSourceSoundData.get((Integer)param.args[0]);
SavePlayedSound(mContext, data);
Set<String> silencedSounds = Helpers.getSharedStringSetPref(mContext, "pref_key_system_audiosilencer_sounds");
if (silencedSounds.contains(data.toPref())) param.setResult(null);
}
}
});
Helpers.hookAllMethods(MediaPlayer.class, "setDataSource", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
if (Modifier.isPrivate(param.method.getModifiers())) return;
Context callerContext = Helpers.findContext();
if (callerContext == null) return;
String caller = callerContext.getPackageName();
SoundData soundData = null;
if (param.args.length > 1 && param.args[0] instanceof Context && param.args[1] instanceof Uri)
soundData = new SoundData(caller, "uri", ((Uri)param.args[1]).getPath());
else if (param.args[0] instanceof String)
soundData = new SoundData(caller, "file", (String)param.args[0]);
if (soundData != null)
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mSourceSoundData", soundData);
}
});
Helpers.hookAllMethods(MediaPlayer.class, "start", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
SoundData mSourceSoundData = (SoundData)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mSourceSoundData");
if (mSourceSoundData != null) {
Context mContext = Helpers.findContext();
if (mContext == null) return;
SavePlayedSound(mContext, mSourceSoundData);
Set<String> silencedSounds = Helpers.getSharedStringSetPref(mContext, "pref_key_system_audiosilencer_sounds");
if (silencedSounds.contains(mSourceSoundData.toPref())) param.setResult(null);
}
}
});
}
public static void BetterPopupsAllowFloatHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.miui.statusbar.policy.AppMiniWindowManager", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String key = uri.getPathSegments().get(2);
if (key.contains("pref_key_system_betterpopups_allowfloat_apps"))
MainModule.mPrefs.put(key, Helpers.getSharedStringSetPref(mContext, key));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.findAndHookMethod("com.android.systemui.miui.statusbar.policy.AppMiniWindowManager", lpparam.classLoader, "canNotificationSlide", Context.class, "com.android.systemui.miui.statusbar.ExpandedNotification", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object notification = XposedHelpers.callMethod(param.args[1], "getNotification");
PendingIntent intent = (PendingIntent)XposedHelpers.callMethod(param.thisObject, "getIntent", notification);
if (intent == null) return;
Set<String> selectedApps = MainModule.mPrefs.getStringSet("system_betterpopups_allowfloat_apps");
Set<String> selectedAppsBlack = MainModule.mPrefs.getStringSet("system_betterpopups_allowfloat_apps_black");
if (selectedApps.contains(intent.getCreatorPackage())) param.setResult(true);
else if (selectedAppsBlack.contains(intent.getCreatorPackage())) param.setResult(false);
}
});
}
public static void NoFloatingWindowBlacklistHook() {
MethodHook clearHook = new MethodHook() {
@Override
@SuppressWarnings("unchecked")
protected void after(MethodHookParam param) throws Throwable {
List<String> blackList = (List<String>)param.getResult();
if (blackList != null) blackList.clear();
param.setResult(blackList);
}
};
Helpers.findAndHookMethod("android.util.MiuiMultiWindowAdapter", null, "getFreeformBlackList", clearHook);
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently("android.util.MiuiMultiWindowAdapter", null, "getFreeformBlackListFromCloud", Context.class, clearHook);
// Unlock on all devices
Helpers.findAndHookMethod("android.util.MiuiMultiWindowUtils", null, "supportFreeform", XC_MethodReplacement.returnConstant(true));
}
public static ConcurrentHashMap<String, Pair<Float, Rect>> fwApps = new ConcurrentHashMap<String, Pair<Float, Rect>>();
public static String getTaskPackageName(Object thisObject, int taskId) {
return getTaskPackageName(thisObject, taskId, false, null);
}
public static String getTaskPackageName(Object thisObject, int taskId, ActivityOptions options) {
return getTaskPackageName(thisObject, taskId, true, options);
}
public static String getTaskPackageName(Object thisObject, int taskId, boolean withOptions, ActivityOptions options) {
Object mRootActivityContainer = XposedHelpers.getObjectField(thisObject, "mRootActivityContainer");
if (mRootActivityContainer == null) return null;
Object task = withOptions ?
XposedHelpers.callMethod(mRootActivityContainer, "anyTaskForId", taskId, 2, options, true) :
XposedHelpers.callMethod(mRootActivityContainer, "anyTaskForId", taskId, 0);
if (task == null) return null;
Intent intent = (Intent)XposedHelpers.getObjectField(task, "intent");
return intent == null ? null : intent.getComponent().getPackageName();
}
public static String serializeFwApps() {
StringBuilder data = new StringBuilder();
for (Map.Entry<String, Pair<Float, Rect>> entry: fwApps.entrySet()) {
Pair<Float, Rect> val = entry.getValue();
data.append(entry.getKey());
data.append(":");
data.append(val.first);
data.append(":");
data.append(val.second == null ? "-" : val.second.flattenToString());
data.append("|");
}
return data.toString().replaceFirst("\\|$", "");
}
public static void unserializeFwApps(String data) {
fwApps.clear();
if (data == null || "".equals(data)) return;
String[] dataArr = data.split("\\|");
for (String appData: dataArr) {
if ("".equals(appData)) continue;
String[] appDataArr = appData.split(":");
fwApps.put(appDataArr[0], new Pair<Float, Rect>(Float.parseFloat(appDataArr[1]), "-".equals(appDataArr[2]) ? null : Rect.unflattenFromString(appDataArr[2])));
}
}
public static void storeFwAppsInSetting(Context context) {
Settings.Global.putString(context.getContentResolver(), Helpers.modulePkg + ".fw.apps", serializeFwApps());
}
public static void restoreFwAppsInSetting(Context context) {
unserializeFwApps(Settings.Global.getString(context.getContentResolver(), Helpers.modulePkg + ".fw.apps"));
}
public static void StickyFloatingWindowsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.wm.ActivityStarterInjector", lpparam.classLoader, "modifyLaunchActivityOptionIfNeed", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if (param.args.length != 8) return;
Intent intent = (Intent)param.args[5];
if (intent == null || intent.getComponent() == null) return;
ActivityOptions options = (ActivityOptions)param.getResult();
int windowingMode = options == null ? -1 : (int)XposedHelpers.callMethod(options, "getLaunchWindowingMode");
String pkgName = intent.getComponent().getPackageName();
if (windowingMode != 5 && fwApps.containsKey(pkgName)) try {
Class<?> mmwuCls = findClassIfExists("android.util.MiuiMultiWindowUtils", null);
if (mmwuCls == null) {
Helpers.log("StickyFloatingWindowsHook", "Cannot find MiuiMultiWindowUtils class");
return;
}
Context mContext = (Context)XposedHelpers.getObjectField(param.args[0], "mContext");
//options = (ActivityOptions)XposedHelpers.callStaticMethod(mmwuCls, "getActivityOptions", mContext, pkgName, true, false);
if (options == null) options = ActivityOptions.makeBasic();
XposedHelpers.callMethod(options, "setLaunchWindowingMode", 5);
XposedHelpers.callMethod(options, "setMiuiConfigFlag", 2);
Float scale;
Rect rect;
Pair<Float, Rect> values = fwApps.get(pkgName);
if (values == null || values.first == 0f || values.second == null) {
scale = XposedHelpers.getStaticFloatField(mmwuCls, "sScale");
rect = (Rect)XposedHelpers.callStaticMethod(mmwuCls, "getFreeformRect", mContext);
} else {
scale = values.first;
rect = values.second;
}
options.setLaunchBounds(rect);
try {
Object injector = XposedHelpers.callMethod(options, "getActivityOptionsInjector");
XposedHelpers.callMethod(injector, "setFreeformScale", scale);
} catch (Throwable ignore) {}
param.setResult(options);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
Helpers.hookAllMethods("com.android.server.wm.ActivityStackSupervisor", lpparam.classLoader, "startActivityFromRecents", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object safeOptions = param.args[3];
ActivityOptions options = (ActivityOptions)XposedHelpers.callMethod(safeOptions, "getOptions", param.thisObject);
int windowingMode = options == null ? -1 : (int)XposedHelpers.callMethod(options, "getLaunchWindowingMode");
if (windowingMode != 5) return;
String pkgName = getTaskPackageName(param.thisObject, (int)param.args[2], options);
if (pkgName != null) {
fwApps.put(pkgName, new Pair<Float, Rect>(0f, null));
storeFwAppsInSetting((Context)XposedHelpers.getObjectField(XposedHelpers.getObjectField(param.thisObject, "mService"), "mContext"));
}
}
});
Helpers.hookAllMethods("com.android.server.wm.MiuiFreeFormGestureController", lpparam.classLoader, "notifyFullScreenWidnowModeStart", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
String pkgName = (String)XposedHelpers.getObjectField(param.thisObject, "mFreeFormPackageName");
if (fwApps.remove(pkgName) != null)
storeFwAppsInSetting((Context)XposedHelpers.getObjectField(XposedHelpers.getObjectField(param.thisObject, "mService"), "mContext"));
}
});
// Helpers.hookAllMethods("com.android.server.wm.MiuiFreeFormGesturePointerEventListener", lpparam.classLoader, "startShowFullScreenWindow", new MethodHook() {
// @Override
// protected void before(MethodHookParam param) throws Throwable {
// Object mGestureController = XposedHelpers.getObjectField(param.thisObject, "mGestureController");
// XposedBridge.log("FULLSCREEN: " + XposedHelpers.getObjectField(mGestureController, "mFreeFormPackageName"));
// }
// });
Helpers.findAndHookMethod("com.android.server.wm.ActivityTaskManagerService", lpparam.classLoader, "onSystemReady", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
String pkgName = intent.getStringExtra("package");
if (pkgName != null) {
fwApps.put(pkgName, new Pair<Float, Rect>(0f, null));
storeFwAppsInSetting(mContext);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}, new IntentFilter(ACTION_PREFIX + "RememberFloatingWindow"));
restoreFwAppsInSetting(mContext);
}
});
Helpers.hookAllMethods("com.android.server.wm.ActivityTaskManagerService", lpparam.classLoader, "resizeTask", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
float sScale = XposedHelpers.getStaticFloatField(findClass("android.util.MiuiMultiWindowUtils", null), "sScale");
String pkgName = getTaskPackageName(param.thisObject, (int)param.args[0]);
if (pkgName != null && fwApps.containsKey(pkgName)) {
fwApps.put(pkgName, new Pair<Float, Rect>(sScale, new Rect((Rect)param.args[1])));
storeFwAppsInSetting((Context)XposedHelpers.getObjectField(param.thisObject, "mContext"));
}
}
});
}
public static void StickyFloatingWindowsLauncherHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.miui.home.smallwindow.BaseDelegateAdapter", lpparam.classLoader, "startFreeformActivity",new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
String pkgName = (String)param.args[1];
if (pkgName == null) return;
Intent intent = new Intent(ACTION_PREFIX + "RememberFloatingWindow");
intent.putExtra("package", pkgName);
((Context)param.args[0]).sendBroadcast(intent);
}
});
}
public static void MessagingStyleLinesSysHook() {
Helpers.findAndHookMethod("android.app.Notification.MessagingStyle", null, "makeMessagingView", boolean.class, boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
if ((boolean)param.args[0] && (boolean)param.args[1]) return;
RemoteViews remote = (RemoteViews)param.getResult();
Context mContext = (Context)XposedHelpers.getObjectField(XposedHelpers.getObjectField(param.thisObject, "mBuilder"), "mContext");
remote.setInt(mContext.getResources().getIdentifier("notification_messaging", "id", "android"), "setMaxDisplayedLines", MainModule.mPrefs.getInt("system_messagingstylelines", Integer.MAX_VALUE));
}
});
}
public static void MessagingStyleLinesHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.android.systemui.statusbar.notification.NotificationMessagingTemplateViewWrapper", lpparam.classLoader, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object mMessagingLinearLayout = XposedHelpers.getObjectField(param.thisObject, "mMessagingLinearLayout");
int mMaxDisplayedLines = XposedHelpers.getIntField(mMessagingLinearLayout, "mMaxDisplayedLines");
if (mMaxDisplayedLines == Integer.MAX_VALUE) XposedHelpers.callMethod(mMessagingLinearLayout, "setMaxDisplayedLines", MainModule.mPrefs.getInt("system_messagingstylelines", Integer.MAX_VALUE));
}
});
}
public static void MultiWindowPlusNativeHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.recents.views.RecentMenuView", lpparam.classLoader, "onBusEvent", "com.android.systemui.recents.events.activity.ShowTaskMenuEvent", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
ImageView mMenuItemMultiWindow = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mMenuItemMultiWindow");
ImageView mMenuItemSmallWindow = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mMenuItemSmallWindow");
mMenuItemMultiWindow.setEnabled(true);
mMenuItemMultiWindow.setImageAlpha(255);
mMenuItemSmallWindow.setEnabled(true);
mMenuItemSmallWindow.setImageAlpha(255);
}
});
// Helpers.findAndHookMethod("com.android.systemui.recents.RecentsActivity", lpparam.classLoader, "updateDockBtnVisible", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// View mDockBtn = (View)XposedHelpers.getObjectField(param.thisObject, "mDockBtn");
// mDockBtn.setVisibility(View.VISIBLE);
// }
// });
}
public static void MultiWindowPlusHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.miui.home.recents.views.RecentMenuView", lpparam.classLoader, "onMessageEvent", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
ImageView mMenuItemMultiWindow = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mMenuItemMultiWindow");
ImageView mMenuItemSmallWindow = (ImageView)XposedHelpers.getObjectField(param.thisObject, "mMenuItemSmallWindow");
mMenuItemMultiWindow.setEnabled(true);
mMenuItemMultiWindow.setImageAlpha(255);
mMenuItemSmallWindow.setEnabled(true);
mMenuItemSmallWindow.setImageAlpha(255);
}
}, 200);
}
});
}
public static void SecureControlCenterHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateKeyguardState", boolean.class, boolean.class, new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object mStatusBarWindow = XposedHelpers.callMethod(param.thisObject, "getStatusBarWindow");
if (mStatusBarWindow == null) return;
Object mControllerPanel = XposedHelpers.getObjectField(mStatusBarWindow, "mControllerPanel");
if (mControllerPanel == null) return;
Object mControlCenter = XposedHelpers.getObjectField(mControllerPanel, "mControlCenter");
if (mControlCenter == null) return;
KeyguardManager kgMgr = (KeyguardManager)XposedHelpers.getObjectField(param.thisObject, "mKeyguardManager");
XposedHelpers.setAdditionalInstanceField(mControlCenter, "isOnSecureKeyguard", kgMgr.isKeyguardLocked() && kgMgr.isKeyguardSecure());
}
});
Helpers.hookAllMethods("com.android.systemui.miui.statusbar.ControlCenter", lpparam.classLoader, "panelEnabled", new MethodHook() {
@Override
protected void before(MethodHookParam param) throws Throwable {
boolean isOnSecureKeyguard = false;
try { isOnSecureKeyguard = (boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "isOnSecureKeyguard"); } catch (Throwable ignore) {}
if (isOnSecureKeyguard) param.setResult(false);
}
});
}
public static void MinimalNotificationViewHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "updateNotification", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if (param.args.length != 3) return;
Object expandableRow = XposedHelpers.getObjectField(param.args[0], "row");
Object mNotificationData = XposedHelpers.getObjectField(param.thisObject, "mNotificationData");
boolean newLowPriority = (boolean)XposedHelpers.callMethod(mNotificationData, "isAmbient", XposedHelpers.callMethod(param.args[1], "getKey")) && !(boolean)XposedHelpers.callMethod(XposedHelpers.callMethod(param.args[1], "getNotification"), "isGroupSummary");
boolean hasEntry = XposedHelpers.callMethod(mNotificationData, "get", XposedHelpers.getObjectField(param.args[0], "key")) != null;
boolean isLowPriority = (boolean)XposedHelpers.callMethod(expandableRow, "isLowPriority");
XposedHelpers.callMethod(expandableRow, "setIsLowPriority", newLowPriority);
boolean hasLowPriorityChanged = hasEntry && isLowPriority != newLowPriority;
XposedHelpers.callMethod(expandableRow, "setLowPriorityStateUpdated", hasLowPriorityChanged);
XposedHelpers.callMethod(expandableRow, "updateNotification", param.args[0]);
}
});
}
public static void NotificationChannelSettingsHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "onClickMenuSettings", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if ((boolean)param.args[2]) return;
Object entry = XposedHelpers.callMethod(param.args[0], "getEntry");
String id = (String)XposedHelpers.callMethod(XposedHelpers.getObjectField(entry, "channel"), "getId");
if ("miscellaneous".equals(id)) return;
Object notification = XposedHelpers.getObjectField(entry, "notification");
Class<?> nuCls = findClassIfExists("com.android.systemui.miui.statusbar.notification.NotificationUtil", lpparam.classLoader);
if (nuCls != null) {
boolean isHybrid = (boolean)XposedHelpers.callStaticMethod(nuCls, "isHybrid", notification);
if (isHybrid) return;
}
String pkgName;
int user;
if ((boolean)XposedHelpers.callMethod(notification, "isSubstituteNotification")) {
pkgName = (String)XposedHelpers.callMethod(notification, "getBasePkg");
user = -1;
} else {
pkgName = (String)XposedHelpers.callMethod(notification, "getPackageName");
user = (int)XposedHelpers.callMethod(notification, "getAppUid");
}
Intent intent = new Intent("android.intent.action.MAIN");
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClassName("com.android.settings", "com.android.settings.Settings$ChannelNotificationSettingsActivity");
intent.putExtra("package", pkgName);
intent.putExtra("android.provider.extra.CHANNEL_ID", id);
intent.putExtra("uid", user);
try {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
XposedHelpers.callMethod(mContext, "startActivityAsUser", intent, android.os.Process.myUserHandle());
} catch (Throwable ignore) {}
}
});
}
public static void SkipAppLockHook(LoadPackageParam lpparam) {
Helpers.hookAllConstructors("com.miui.server.AccessController", lpparam.classLoader, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mWorkHandler");
new Helpers.SharedPrefObserver(mContext, mHandler) {
@Override
public void onChange(Uri uri) {
try {
String type = uri.getPathSegments().get(1);
String key = uri.getPathSegments().get(2);
if (key.contains("pref_key_system_applock_skip_activities") && "string".equals(type))
MainModule.mPrefs.put(key, Helpers.getSharedStringPref(mContext, key, ""));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
}
});
Helpers.hookAllMethods("com.miui.server.AccessController", lpparam.classLoader, "skipActivity", new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Intent intent = (Intent)param.args[0];
if (intent == null || intent.getComponent() == null) return;
String pkgName = intent.getComponent().getPackageName();
String actName = intent.getComponent().getClassName();
Helpers.log("SkipAppLock", actName);
String key = "system_applock_skip_activities";
String itemStr = MainModule.mPrefs.getString(key, "");
if (itemStr == null || itemStr.isEmpty()) return;
String[] itemArr = itemStr.trim().split("\\|");
for (String uuid: itemArr) {
String pkgAct = MainModule.mPrefs.getString(key + "_" + uuid + "_activity", "");
if (pkgAct.equals(pkgName + "|" + actName)) param.setResult(true);
}
}
});
}
private static final List<String> securedTiles = new ArrayList<String>();
public static void SecureQSTilesHook(LoadPackageParam lpparam) {
Class<?> tileHostCls = XposedHelpers.findClassIfExists("com.android.systemui.qs.QSTileHost", lpparam.classLoader);
Method initMethod = XposedHelpers.findMethodExactIfExists(tileHostCls, "init");
MethodHook hook = new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
BroadcastReceiver mAfterUnlockReceiver = new BroadcastReceiver() {
@Override
@SuppressWarnings("unchecked")
public void onReceive(Context context, Intent intent) {
try {
String tileName = intent.getStringExtra("tileName");
boolean expandAfter = intent.getBooleanExtra("expandAfter", false);
boolean usingCenter = intent.getBooleanExtra("usingCenter", false);
if ("edit".equals(tileName) || expandAfter) {
Intent expandIntent = new Intent(ACTION_PREFIX + "ExpandSettings");
expandIntent.putExtra("forceExpand", true);
context.sendBroadcast(expandIntent);
}
LinkedHashMap<String, ?> mTiles = (LinkedHashMap<String, ?>)XposedHelpers.getObjectField(param.thisObject, "mTiles");
//for (Map.Entry mTile: mTiles.entrySet())
//XposedBridge.log(mTile.getKey() + " = " + mTile.getValue());
Object tile = mTiles.get(tileName);
if (tile == null)
if (usingCenter) {
Object mController = XposedHelpers.callStaticMethod(findClass("com.android.systemui.Dependency", lpparam.classLoader), "get", findClassIfExists("com.android.systemui.miui.statusbar.policy.ControlPanelController", lpparam.classLoader));
Object mControlCenter = XposedHelpers.getObjectField(mController, "mControlCenter");
Object mControlPanelContentView = XposedHelpers.getObjectField(mControlCenter, "mControlPanelContentView");
Object mControlCenterPanel = XposedHelpers.callMethod(mControlPanelContentView, "getControlCenterPanel");
Object mBigTile = null;
if ("bt".equals(tileName)) mBigTile = XposedHelpers.getObjectField(mControlCenterPanel, "mBigTile1");
else if ("cell".equals(tileName)) mBigTile = XposedHelpers.getObjectField(mControlCenterPanel, "mBigTile2");
else if ("wifi".equals(tileName)) mBigTile = XposedHelpers.getObjectField(mControlCenterPanel, "mBigTile3");
if (mBigTile != null) tile = XposedHelpers.getObjectField(mBigTile, "mQSTile");
if (tile == null) return;
} else return;
XposedHelpers.setAdditionalInstanceField(tile, "mCalledAfterUnlock", true);
XposedHelpers.callMethod(tile, "handleClick");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mAfterUnlockReceiver", mAfterUnlockReceiver);
mContext.registerReceiver(mAfterUnlockReceiver, new IntentFilter(ACTION_PREFIX + "HandleQSTileClick"));
}
};
if (initMethod != null) {
Helpers.findAndHookMethod(tileHostCls, "init", hook);
Helpers.findAndHookMethod(tileHostCls, "destroy", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
BroadcastReceiver mAfterUnlockReceiver = (BroadcastReceiver)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mAfterUnlockReceiver");
if (mAfterUnlockReceiver != null) mContext.unregisterReceiver(mAfterUnlockReceiver);
}
});
} else Helpers.hookAllConstructors(tileHostCls, hook);
Helpers.findAndHookMethod("com.android.systemui.qs.tileimpl.QSFactoryImpl", lpparam.classLoader, "createTileInternal", String.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Object tile = param.getResult();
if (tile == null) return;
String tileClass = tile.getClass().getCanonicalName();
final String tileName = (String)param.args[0];
String name = (String)param.args[0];
if (name.startsWith("intent(")) name = "intent";
else if (name.startsWith("custom(")) name = "custom";
final HashSet<String> secureTitles = new HashSet<String>();
if (MainModule.mPrefs.getBoolean("system_secureqs_wifi")) secureTitles.add("wifi");
if (MainModule.mPrefs.getBoolean("system_secureqs_bt")) secureTitles.add("bt");
if (MainModule.mPrefs.getBoolean("system_secureqs_mobiledata")) secureTitles.add("cell");
if (MainModule.mPrefs.getBoolean("system_secureqs_airplane")) secureTitles.add("airplane");
if (MainModule.mPrefs.getBoolean("system_secureqs_location")) secureTitles.add("gps");
if (MainModule.mPrefs.getBoolean("system_secureqs_hotspot")) secureTitles.add("hotspot");
if (MainModule.mPrefs.getBoolean("system_secureqs_nfc")) secureTitles.add("nfc");
if (MainModule.mPrefs.getBoolean("system_secureqs_sync")) secureTitles.add("sync");
if (MainModule.mPrefs.getBoolean("system_secureqs_edit")) secureTitles.add("edit");
if (MainModule.mPrefs.getBoolean("system_secureqs_custom")) {
secureTitles.add("intent");
secureTitles.add("custom");
}
if (secureTitles.contains(name) && !securedTiles.contains(tileClass)) {
MethodHook hook = new MethodHook(10) {
@Override
protected void before(final MethodHookParam param) throws Throwable {
Boolean mCalledAfterUnlock = (Boolean)XposedHelpers.getAdditionalInstanceField(param.thisObject, "mCalledAfterUnlock");
if (mCalledAfterUnlock != null && mCalledAfterUnlock) {
XposedHelpers.setAdditionalInstanceField(param.thisObject, "mCalledAfterUnlock", false);
return;
}
Boolean isScreenLockDisabled = (Boolean)XposedHelpers.getAdditionalStaticField(findClass("com.android.systemui.keyguard.KeyguardViewMediator", lpparam.classLoader), "isScreenLockDisabled");
isScreenLockDisabled = isScreenLockDisabled != null && isScreenLockDisabled;
if (isScreenLockDisabled) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
KeyguardManager kgMgr = (KeyguardManager)mContext.getSystemService(Context.KEYGUARD_SERVICE);
if (!kgMgr.isKeyguardLocked() || !kgMgr.isKeyguardSecure()) return;
Handler mHandler = new Handler(mContext.getMainLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
try {
Object mApplication = XposedHelpers.callMethod(mContext.getApplicationContext(), "getSystemUIApplication");
Object mStatusBar = XposedHelpers.callMethod(mApplication, "getComponent", findClassIfExists("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader));
boolean usingControlCenter = false;
if (Helpers.is12()) {
Object mController = XposedHelpers.callStaticMethod(findClass("com.android.systemui.Dependency", lpparam.classLoader), "get", findClassIfExists("com.android.systemui.miui.statusbar.policy.ControlPanelController", lpparam.classLoader));
usingControlCenter = (boolean)XposedHelpers.callMethod(mController, "isUseControlCenter");
if (usingControlCenter) XposedHelpers.callMethod(mController, "collapsePanel", true);
}
boolean keepOpened = MainModule.mPrefs.getBoolean("system_secureqs_keepopened");
final boolean usingCenter = usingControlCenter;
final boolean expandAfter = usingControlCenter && keepOpened;
if (!usingControlCenter && keepOpened)
XposedHelpers.setBooleanField(mStatusBar, "mLeaveOpenOnKeyguardHide", true);
XposedHelpers.callMethod(mStatusBar, "postQSRunnableDismissingKeyguard", new Runnable() {
public void run() {
Intent intent = new Intent(ACTION_PREFIX + "HandleQSTileClick");
intent.putExtra("tileName", tileName);
intent.putExtra("expandAfter", expandAfter);
intent.putExtra("usingCenter", usingCenter);
mContext.sendBroadcast(intent);
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
param.setResult(null);
}
};
Helpers.findAndHookMethod(tileClass, lpparam.classLoader, "handleClick", hook);
//noinspection ResultOfMethodCallIgnored
Helpers.findAndHookMethodSilently(tileClass, lpparam.classLoader, "handleSecondaryClick", hook);
securedTiles.add(tileClass);
}
}
});
}
public static void HideLockScreenHintHook(LoadPackageParam lpparam) {
MethodHook hook = new MethodHook() {
@Override
protected void after(MethodHookParam param) throws Throwable {
Object controller = XposedHelpers.getSurroundingThis(param.thisObject);
XposedHelpers.setObjectField(controller, "mUpArrowIndication", null);
XposedHelpers.callMethod(controller, "updateIndication");
}
};
Helpers.hookAllMethods("com.android.systemui.statusbar.KeyguardIndicationController$BaseKeyguardCallback", lpparam.classLoader, "onRefreshBatteryInfo", hook);
if (!Helpers.hookAllMethodsSilently("com.android.systemui.statusbar.KeyguardIndicationController$BaseKeyguardCallback", lpparam.classLoader, "onStartedWakingUp", hook))
Helpers.hookAllMethodsSilently("com.android.systemui.statusbar.KeyguardIndicationController$BaseKeyguardCallback", lpparam.classLoader, "onScreenTurnedOn", hook);
}
public static void HideLockScreenStatusBarHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "makeStatusBarView", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
View mKeyguardStatusBar = (View)XposedHelpers.getObjectField(param.thisObject, "mKeyguardStatusBar");
if (mKeyguardStatusBar != null) mKeyguardStatusBar.setTranslationY(-999f);
}
});
}
public static void MuteVisibleNotificationsHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.media.NotificationPlayer$CreationAndCompletionThread", lpparam.classLoader, "run", new MethodHook() {
@Override
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
protected void before(final MethodHookParam param) throws Throwable {
Object mCmd = XposedHelpers.getObjectField(param.thisObject, "mCmd");
if (mCmd == null) return;
int code = XposedHelpers.getIntField(mCmd, "code");
if (code != 1) return;
AudioAttributes attributes = (AudioAttributes)XposedHelpers.getObjectField(mCmd, "attributes");
if (attributes.getUsage() == AudioAttributes.USAGE_NOTIFICATION || attributes.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE || attributes.getUsage() == AudioAttributes.USAGE_UNKNOWN)
if (attributes.getContentType() == AudioAttributes.CONTENT_TYPE_SONIFICATION || attributes.getContentType() == AudioAttributes.CONTENT_TYPE_UNKNOWN) {
Context context = (Context)XposedHelpers.getObjectField(mCmd, "context");
PowerManager powerMgr = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
if (powerMgr.isInteractive()) {
Thread thread = (Thread)param.thisObject;
synchronized (thread) { thread.notify(); }
param.setResult(null);
}
}
}
});
}
public static void NetworkIndicatorRes() {
int opt = MainModule.mPrefs.getStringAsInt("system_networkindicator", 1);
MainModule.resHooks.setObjectReplacement("com.android.systemui", "bool", "config_showActivity", opt == 2);
MainModule.resHooks.setObjectReplacement("com.android.systemui", "bool", "config_showWifiActivity", opt == 2);
}
public static void ClearBrightnessMirrorHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.BrightnessMirrorController", lpparam.classLoader, "showMirror", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
View mBrightnessMirror = (View)XposedHelpers.getObjectField(param.thisObject, "mBrightnessMirror");
mBrightnessMirror.setElevation(0);
mBrightnessMirror.setBackgroundColor(Color.TRANSPARENT);
}
});
}
public static void SetLockscreenWallpaperHook(LoadPackageParam lpparam) {
Helpers.hookAllMethods("com.android.server.wallpaper.WallpaperManagerService", lpparam.classLoader, "setWallpaper", new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
if (param.getThrowable() != null || param.getResult() == null || (int)param.args[5] == 1 || "com.android.thememanager".equals(param.args[1])) return;
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (mContext == null) return;
int handleIncomingUser = 0;
try {
handleIncomingUser = (int)XposedHelpers.callStaticMethod(ActivityManager.class, "handleIncomingUser", Binder.getCallingPid(), Binder.getCallingUid(), param.args[7], false, true, "changing wallpaper", null);
} catch (Throwable ignore) {}
Object wallpaperData = XposedHelpers.callMethod(param.thisObject, "getWallpaperSafeLocked", handleIncomingUser, param.args[5]);
File wallpaper = (File)XposedHelpers.getObjectField(wallpaperData, "wallpaperFile");
new Handler(mContext.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
if (!wallpaper.exists()) return;
if (Helpers.is10()) {
Intent copyIntent = new Intent(ACTION_PREFIX + "CopyToExternal");
copyIntent.putExtra("action", 1);
copyIntent.putExtra("from", wallpaper.getAbsolutePath());
mContext.sendBroadcast(copyIntent);
}
JSONObject data = new JSONObject();
JSONObject ex = new JSONObject();
try {
ex
.put("link_type", "0")
.put("title_size", "26")
.put("item_id", "wallpaper1")
.put("title_color", "#ffffffff")
.put("index_in_album", "1")
.put("tag_list", "CustoMIUIzer,mod")
.put("content_color", "#ffffffff")
.put("total_of_album", "1")
.put("img_level", "0")
.put("album_id", "1")
.put("title_customized", "0")
.put("lks_entry_text", "Some wallpaper");
data
.put("authority", "name.mikanoshi.customiuizer.mods.set_lockscreen_wallpaper")
.put("content", "Wallpaper set by some app")
.put("contentColorValue", 0)
.put("cp", "CustoMIUIzer")
.put("cpColorValue", 0)
.put("definition", -1)
.put("ex", ex.toString())
.put("fromColorValue", 0)
.put("hasAcc", false)
.put("indexInAlbum", -1)
.put("isAd", false)
.put("isCustom", false)
.put("isFd", false)
.put("isFrontCover", false)
.put("key", "wallpaper1")
.put("like", false)
.put("linkType", 0)
.put("noApply", false)
.put("noDislike", false)
.put("noSave", false)
.put("noShare", false)
.put("pos", 0)
.put("supportLike", true)
.put("title", "Some wallpaper")
.put("titleColorValue", 0)
.put("titleTextSize", -1)
.put("totalOfAlbum", -1)
.put("wallpaperUri", wallpaper.toURI());
} catch (Throwable t) {
XposedBridge.log(t);
}
Intent setIntent = new Intent("android.miui.UPDATE_LOCKSCREEN_WALLPAPER");
setIntent.putExtra("wallpaperInfo", data.toString());
setIntent.putExtra("apply", true);
mContext.sendBroadcast(setIntent);
}
}, 2000);
}
});
}
public static void BetterPopupsCenteredHook(LoadPackageParam lpparam) {
Helpers.findAndHookMethod("com.android.systemui.statusbar.policy.HeadsUpManager", lpparam.classLoader, "getHeadsUpTopMargin", Context.class, new MethodHook() {
@Override
protected void after(final MethodHookParam param) throws Throwable {
Context context = (Context)param.args[0];
Resources res = context.getResources();
int maxPopupHeight = res.getDimensionPixelSize(res.getIdentifier("notification_max_heads_up_height", "dimen", "com.android.systemui"));
if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) maxPopupHeight /= 3;
param.setResult(Math.round(context.getResources().getDisplayMetrics().heightPixels / 2.0f - maxPopupHeight / 2.0f));
}
});
}
// @SuppressWarnings("unchecked")
// public static void MultiWindowHook() {
// HashMap sAppList = (HashMap)XposedHelpers.getStaticObjectField(findClass("android.util.MiuiMultiWindowUtils", null), "sAppList");
// sAppList.put(Helpers.modulePkg, 4);
// XposedHelpers.setStaticObjectField(findClass("android.util.MiuiMultiWindowUtils", null), "sAppList", sAppList);
// }
//
// public static void MultiWindowServiceHook(LoadPackageParam lpparam) {
// Helpers.hookAllMethods("com.android.server.am.ActivityStarterInjector", lpparam.classLoader, "checkFreeformSupport", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// XposedHelpers.setObjectField(param.args[0], "mSupportsFreeformWindowManagement", true);
// }
// });
//
// Helpers.findAndHookMethod("com.android.server.am.ActivityStackSupervisorInjector", lpparam.classLoader, "supportsFreeform", XC_MethodReplacement.returnConstant(true));
//
// Helpers.hookAllMethods("com.android.server.am.ActivityDisplay", lpparam.classLoader, "resolveWindowingMode", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// Object mSupervisor = XposedHelpers.getObjectField(param.thisObject, "mSupervisor");
// Object mService = XposedHelpers.getObjectField(mSupervisor, "mService");
// Object mSupportsMultiWindow = XposedHelpers.getObjectField(mService, "mSupportsMultiWindow");
// Object mSupportsSplitScreenMultiWindow = XposedHelpers.getObjectField(mService, "mSupportsSplitScreenMultiWindow");
// Object mSupportsFreeformWindowManagement = XposedHelpers.getObjectField(mService, "mSupportsFreeformWindowManagement");
// Object mSupportsPictureInPicture = XposedHelpers.getObjectField(mService, "mSupportsPictureInPicture");
// XposedBridge.log("mSupportsMultiWindow: " + mSupportsMultiWindow);
// XposedBridge.log("mSupportsSplitScreenMultiWindow: " + mSupportsSplitScreenMultiWindow);
// XposedBridge.log("mSupportsFreeformWindowManagement: " + mSupportsFreeformWindowManagement);
// XposedBridge.log("mSupportsPictureInPicture: " + mSupportsPictureInPicture);
// XposedBridge.log("resolveWindowingMode: " + param.args[0] + ", " + param.args[1] + ", " + param.args[2] + ", " + param.args[3] + " = " + param.getResult());
// }
// });
//
// Helpers.hookAllMethods("com.android.server.pm.PackageManagerService", lpparam.classLoader, "hasSystemFeature", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// if ("android.software.freeform_window_management".equals(param.args[0])) param.setResult(true);
// }
// });
// }
//
// public static void QSFooterHook(LoadPackageParam lpparam) {
// Helpers.findAndHookMethod("com.android.systemui.qs.QSContainerImpl", lpparam.classLoader, "onFinishInflate", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// FrameLayout qs = (FrameLayout)param.thisObject;
// Context context = qs.getContext();
// Resources res = context.getResources();
// LinearLayout mQSFooterContainer = (LinearLayout)XposedHelpers.getObjectField(param.thisObject, "mQSFooterContainer");
// LayoutInflater inflater = (LayoutInflater)Helpers.getModuleContext(context).getSystemService(Context.LAYOUT_INFLATER_SERVICE);
//
// View dataView = inflater.inflate(R.layout.qs_footer, mQSFooterContainer, false);
// dataView.setTag("mydata");
// LinearLayout.LayoutParams lp0 = (LinearLayout.LayoutParams)dataView.getLayoutParams();
// int margin = res.getDimensionPixelSize(res.getIdentifier("qs_divider_margin_horizontal", "dimen", context.getPackageName()));
// int height = res.getDimensionPixelSize(res.getIdentifier("qs_footer_height", "dimen", context.getPackageName()));
// lp0.setMarginStart(margin);
// lp0.topMargin = - height / 6;
// lp0.bottomMargin = height / 4;
// dataView.setLayoutParams(lp0);
//
// ImageView icon = dataView.findViewById(R.id.qs_icon);
// icon.setImageDrawable(Helpers.getModuleRes(context).getDrawable(R.drawable.ic_gps_task, context.getTheme()));
// ViewGroup.LayoutParams lp1 = icon.getLayoutParams();
// int iconSize = res.getDimensionPixelSize(res.getIdentifier("qs_footer_data_usage_icon_size", "dimen", context.getPackageName()));
// lp1.width = iconSize;
// lp1.height = iconSize;
// icon.setLayoutParams(lp1);
//
// TextView data = dataView.findViewById(R.id.qs_data);
// LinearLayout.LayoutParams lp2 = (LinearLayout.LayoutParams)data.getLayoutParams();
// margin = res.getDimensionPixelSize(res.getIdentifier("qs_footer_line_margin_start", "dimen", context.getPackageName()));
// lp2.setMarginStart(margin);
// lp2.setMarginEnd(margin);
// data.setLayoutParams(lp2);
// data.setText("Some data...");
//
// int textColor = res.getColor(res.getIdentifier("qs_footer_data_usage_text_color", "color", context.getPackageName()), context.getTheme());
// int textSize = res.getDimensionPixelSize(res.getIdentifier("qs_tile_label_text_size", "dimen", context.getPackageName()));
// data.setTextColor(textColor);
// data.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
//
// mQSFooterContainer.addView(dataView);
// }
// });
//
// Helpers.findAndHookMethod("com.android.systemui.qs.QSContainerImpl", lpparam.classLoader, "updateQSDataUsage", boolean.class, new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// LinearLayout mQSFooterContainer = (LinearLayout)XposedHelpers.getObjectField(param.thisObject, "mQSFooterContainer");
// View dataView = mQSFooterContainer.findViewWithTag("mydata");
// mQSFooterContainer.removeView(dataView);
// mQSFooterContainer.addView(dataView);
// }
// });
// }
//
// public static void VolumeDialogTimeoutHook(LoadPackageParam lpparam) {
// Helpers.findAndHookMethod("com.android.systemui.miui.volume.MiuiVolumeDialogImpl", lpparam.classLoader, "computeTimeoutH", new MethodHook() {
// @Override
// protected void after(MethodHookParam param) throws Throwable {
// param.setResult(Math.max((int)param.getResult(), 10000));
// }
// });
// }
}