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.
1116 lines
54 KiB
Java
1116 lines
54 KiB
Java
package name.mikanoshi.customiuizer.mods;
|
|
|
|
import android.annotation.SuppressLint;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.ContentResolver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Color;
|
|
import android.graphics.drawable.Drawable;
|
|
import android.inputmethodservice.InputMethodService;
|
|
import android.media.AudioManager;
|
|
import android.net.Uri;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.PowerManager;
|
|
import android.os.PowerManager.WakeLock;
|
|
import android.os.SystemClock;
|
|
import android.provider.Settings;
|
|
import android.telecom.TelecomManager;
|
|
import android.telephony.TelephonyManager;
|
|
import android.view.KeyEvent;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewConfiguration;
|
|
import android.view.ViewGroup;
|
|
import android.view.WindowManager;
|
|
import android.widget.ImageView;
|
|
import android.widget.LinearLayout;
|
|
import android.widget.Toast;
|
|
|
|
import java.lang.reflect.Method;
|
|
|
|
import static java.lang.System.currentTimeMillis;
|
|
|
|
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
|
|
import de.robv.android.xposed.XC_MethodReplacement;
|
|
import de.robv.android.xposed.XposedBridge;
|
|
import de.robv.android.xposed.XposedHelpers;
|
|
|
|
import name.mikanoshi.customiuizer.MainModule;
|
|
import name.mikanoshi.customiuizer.R;
|
|
import name.mikanoshi.customiuizer.utils.Helpers;
|
|
import name.mikanoshi.customiuizer.utils.Helpers.MethodHook;
|
|
|
|
public class Controls {
|
|
|
|
private static boolean isPowerPressed = false;
|
|
private static boolean isPowerLongPressed = false;
|
|
private static boolean isVolumePressed = false;
|
|
private static boolean isVolumeLongPressed = false;
|
|
private static boolean isWaitingForPowerLongPressed = false;
|
|
private static boolean isWaitingForVolumeLongPressed = false;
|
|
private static boolean wasRaise2WakeEnabled = false;
|
|
private static Handler mHandler;
|
|
|
|
private static boolean isTorchEnabled(Context mContext) {
|
|
return Settings.Global.getInt(mContext.getContentResolver(), "torch_state", 0) != 0;
|
|
}
|
|
|
|
private static void setTorch(Context context, boolean state) {
|
|
if (state) {
|
|
int wakeup = Settings.System.getInt(context.getContentResolver(), "pick_up_gesture_wakeup_mode", 0);
|
|
wasRaise2WakeEnabled = wakeup == 1;
|
|
if (wasRaise2WakeEnabled) Settings.System.putInt(context.getContentResolver(), "pick_up_gesture_wakeup_mode", 0);
|
|
}
|
|
Intent intent = new Intent("miui.intent.action.TOGGLE_TORCH");
|
|
intent.putExtra("miui.intent.extra.IS_ENABLE", state);
|
|
context.sendBroadcast(intent);
|
|
}
|
|
|
|
private static final BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
|
|
public void onReceive(final Context context, Intent intent) {
|
|
if (isTorchEnabled(context)) setTorch(context, false);
|
|
if (Helpers.mWakeLock != null && Helpers.mWakeLock.isHeld()) Helpers.mWakeLock.release();
|
|
if (wasRaise2WakeEnabled) {
|
|
wasRaise2WakeEnabled = false;
|
|
Settings.System.putInt(context.getContentResolver(), "pick_up_gesture_wakeup_mode", 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
public static void PowerKeyRes() {
|
|
MainModule.resHooks.setObjectReplacement("android", "bool", "config_supportLongPressPowerWhenNonInteractive", true);
|
|
}
|
|
|
|
public static void PowerKeyHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "init", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
mContext.registerReceiver(mScreenOnReceiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
|
|
}
|
|
});
|
|
|
|
// Helpers.findAndHookMethod("com.android.server.input.InputManagerService", lpparam.classLoader, "interceptKeyBeforeQueueing", KeyEvent.class, int.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(final MethodHookParam param) throws Throwable {
|
|
// KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
// Helpers.log("PowerKeyHook", "InputManagerService interceptKeyBeforeQueueing: | KeyCode: " + keyEvent.getKeyCode() + " | Action: " + keyEvent.getAction() + " | RepeatCount: " + keyEvent.getRepeatCount()+ " | Flags: " + keyEvent.getFlags());
|
|
// }
|
|
// });
|
|
//
|
|
// Helpers.findAndHookMethod("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "interceptKeyBeforeQueueingInternal", KeyEvent.class, int.class, boolean.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(final MethodHookParam param) throws Throwable {
|
|
// KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
// Helpers.log("PowerKeyHook", "interceptKeyBeforeQueueingInternal: " + param.args[2] + " | KeyCode: " + keyEvent.getKeyCode() + " | Action: " + keyEvent.getAction() + " | RepeatCount: " + keyEvent.getRepeatCount()+ " | Flags: " + keyEvent.getFlags());
|
|
// }
|
|
// });
|
|
|
|
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "interceptKeyBeforeQueueing", KeyEvent.class, int.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
// Power and volkeys are pressed at the same time
|
|
if (isVolumePressed) return;
|
|
KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
|
|
int keycode = keyEvent.getKeyCode();
|
|
int action = keyEvent.getAction();
|
|
int flags = keyEvent.getFlags();
|
|
|
|
// Ignore repeated KeyEvents simulated on Power Key Up
|
|
if ((flags & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == KeyEvent.FLAG_VIRTUAL_HARD_KEY) return;
|
|
if ((flags & KeyEvent.FLAG_FROM_SYSTEM) != KeyEvent.FLAG_FROM_SYSTEM || keycode != KeyEvent.KEYCODE_POWER) return;
|
|
|
|
// Power long press
|
|
final Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
final PowerManager mPowerManager = (PowerManager)XposedHelpers.getObjectField(param.thisObject, "mPowerManager");
|
|
if (mPowerManager.isInteractive()) return;
|
|
//Helpers.log("PowerKeyHook", "interceptKeyBeforeQueueing: " + param.args[1] + ", isTracking: " + keyEvent.isTracking() + " | Source: " + keyEvent.getSource() + " | KeyCode: " + keyEvent.getKeyCode() + " | Action: " + keyEvent.getAction() + " | RepeatCount: " + keyEvent.getRepeatCount()+ " | Flags: " + keyEvent.getFlags());
|
|
if (action == KeyEvent.ACTION_DOWN) {
|
|
isPowerPressed = true;
|
|
isPowerLongPressed = false;
|
|
|
|
mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
|
|
|
|
int longPressDelay = (Helpers.getSharedBoolPref(mContext, "pref_key_controls_powerflash_delay", false) ? ViewConfiguration.getLongPressTimeout() * 3 : ViewConfiguration.getLongPressTimeout()) + 500;
|
|
// Post only one delayed runnable that waits for long press timeout
|
|
if (!isWaitingForPowerLongPressed)
|
|
mHandler.postDelayed(new Runnable() {
|
|
@Override
|
|
@SuppressLint("Wakelock")
|
|
public void run() {
|
|
if (isPowerPressed) {
|
|
isPowerLongPressed = true;
|
|
|
|
if (Helpers.mWakeLock == null)
|
|
Helpers.mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "miuizer:flashlight");
|
|
|
|
if (!isTorchEnabled(mContext) || !Helpers.mWakeLock.isHeld()) {
|
|
setTorch(mContext, true);
|
|
if (!Helpers.mWakeLock.isHeld()) Helpers.mWakeLock.acquire(600000);
|
|
} else {
|
|
setTorch(mContext, true);
|
|
if (Helpers.mWakeLock.isHeld()) Helpers.mWakeLock.release();
|
|
}
|
|
}
|
|
isPowerPressed = false;
|
|
isWaitingForPowerLongPressed = false;
|
|
}
|
|
}, longPressDelay);
|
|
|
|
isWaitingForPowerLongPressed = true;
|
|
param.setResult(0);
|
|
}
|
|
|
|
if (action == KeyEvent.ACTION_UP) {
|
|
if (isPowerPressed && !isPowerLongPressed) try {
|
|
if (isTorchEnabled(mContext)) setTorch(mContext, false);
|
|
if (Helpers.mWakeLock != null && Helpers.mWakeLock.isHeld()) Helpers.mWakeLock.release();
|
|
XposedHelpers.callMethod(mPowerManager, "wakeUp", SystemClock.uptimeMillis());
|
|
param.setResult(0);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
} else if (wasRaise2WakeEnabled && !isTorchEnabled(mContext)) {
|
|
wasRaise2WakeEnabled = false;
|
|
Settings.System.putInt(mContext.getContentResolver(), "pick_up_gesture_wakeup_mode", 1);
|
|
}
|
|
isPowerPressed = false;
|
|
isWaitingForPowerLongPressed = false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void VolumeMediaButtonsHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.server.policy.PhoneWindowManager", lpparam.classLoader, "interceptKeyBeforeQueueing", KeyEvent.class, int.class, new MethodHook() {
|
|
@Override
|
|
@SuppressLint("MissingPermission")
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
// Power and volkeys are pressed at the same time
|
|
if (isPowerPressed) return;
|
|
final KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
|
|
int keycode = keyEvent.getKeyCode();
|
|
int action = keyEvent.getAction();
|
|
int flags = keyEvent.getFlags();
|
|
|
|
// Ignore repeated KeyEvents simulated on volume Key Up
|
|
if ((flags & KeyEvent.FLAG_VIRTUAL_HARD_KEY) == KeyEvent.FLAG_VIRTUAL_HARD_KEY) return;
|
|
if ((flags & KeyEvent.FLAG_FROM_SYSTEM) != KeyEvent.FLAG_FROM_SYSTEM || (keycode != KeyEvent.KEYCODE_VOLUME_UP && keycode != KeyEvent.KEYCODE_VOLUME_DOWN)) return;
|
|
|
|
// Volume long press
|
|
final Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
final PowerManager mPowerManager = (PowerManager)XposedHelpers.getObjectField(param.thisObject, "mPowerManager");
|
|
if (mPowerManager.isInteractive()) return;
|
|
//Helpers.log("VolumeMediaButtonsHook", "interceptKeyBeforeQueueing: KeyCode: " + keyEvent.getKeyCode() + " | Action: " + keyEvent.getAction() + " | RepeatCount: " + keyEvent.getRepeatCount()+ " | Flags: " + keyEvent.getFlags() + " | " + mPowerManager.isInteractive());
|
|
if (action == KeyEvent.ACTION_DOWN) {
|
|
isVolumePressed = true;
|
|
isVolumeLongPressed = false;
|
|
|
|
mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
|
|
|
|
// Post only one delayed runnable that waits for long press timeout
|
|
if (mHandler != null && !isWaitingForVolumeLongPressed)
|
|
mHandler.postDelayed(new Runnable() {
|
|
public void run() {
|
|
if (isVolumePressed && GlobalActions.isMediaActionsAllowed(mContext)) {
|
|
isVolumeLongPressed = true;
|
|
switch (keyEvent.getKeyCode()) {
|
|
case KeyEvent.KEYCODE_VOLUME_UP:
|
|
int pref_mediaUp = Integer.parseInt(Helpers.getSharedStringPref(mContext, "pref_key_controls_volumemedia_up", "0"));
|
|
if (pref_mediaUp == 0) break;
|
|
GlobalActions.sendDownUpKeyEvent(mContext, pref_mediaUp, true);
|
|
break;
|
|
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
|
int pref_mediaDown = Integer.parseInt(Helpers.getSharedStringPref(mContext, "pref_key_controls_volumemedia_down", "0"));
|
|
if (pref_mediaDown == 0) break;
|
|
GlobalActions.sendDownUpKeyEvent(mContext, pref_mediaDown, true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
isVolumePressed = false;
|
|
isWaitingForVolumeLongPressed = false;
|
|
}
|
|
}, ViewConfiguration.getLongPressTimeout());
|
|
|
|
isWaitingForVolumeLongPressed = true;
|
|
param.setResult(0);
|
|
}
|
|
|
|
if (action == KeyEvent.ACTION_UP) {
|
|
isVolumePressed = false;
|
|
// Kill all callbacks (removing only posted Runnable is not working... no idea)
|
|
if (mHandler != null) mHandler.removeCallbacksAndMessages(null);
|
|
if (!isVolumeLongPressed) {
|
|
AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
|
|
TelecomManager tm = (TelecomManager)mContext.getSystemService(Context.TELECOM_SERVICE);
|
|
WakeLock mBroadcastWakeLock = (WakeLock)XposedHelpers.getObjectField(param.thisObject, "mBroadcastWakeLock");
|
|
int k = AudioManager.ADJUST_RAISE;
|
|
if (keycode != KeyEvent.KEYCODE_VOLUME_UP) k = AudioManager.ADJUST_LOWER;
|
|
mBroadcastWakeLock.acquire(5000);
|
|
// If music stream is playing, adjust its volume
|
|
if (am.isMusicActive()) am.adjustStreamVolume(AudioManager.STREAM_MUSIC, k, 0);
|
|
// If voice call is active while screen off by proximity sensor, adjust its volume
|
|
else if (tm.isInCall()) am.adjustStreamVolume(AudioManager.STREAM_VOICE_CALL, k, 0);
|
|
// If volume keys to wake option active, wake the device
|
|
else if (Settings.System.getInt(mContext.getContentResolver(), "volumekey_wake_screen", 0) == 1)
|
|
XposedHelpers.callMethod(mPowerManager, "wakeUp", SystemClock.uptimeMillis());
|
|
if (mBroadcastWakeLock.isHeld()) mBroadcastWakeLock.release();
|
|
}
|
|
param.setResult(0);
|
|
isWaitingForVolumeLongPressed = false;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void VolumeMediaPlayerHook() {
|
|
Helpers.findAndHookMethod("android.media.MediaPlayer", null, "pause", new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
Context mContext = Helpers.findContext();
|
|
int mStreamType = (int)XposedHelpers.findMethodExact(XposedHelpers.findClass("android.media.MediaPlayer", null), "getAudioStreamType").invoke(param.thisObject);
|
|
if (mContext != null && (mStreamType == AudioManager.STREAM_MUSIC || mStreamType == 0x80000000)) {
|
|
Intent intent = new Intent(GlobalActions.ACTION_PREFIX + "SaveLastMusicPausedTime");
|
|
intent.setPackage("android");
|
|
mContext.sendBroadcast(intent);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void VolumeCursorHook() {
|
|
Helpers.findAndHookMethod("android.inputmethodservice.InputMethodService", null, "onKeyDown", int.class, KeyEvent.class, new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
InputMethodService ims = (InputMethodService)param.thisObject;
|
|
int code = (int)param.args[0];
|
|
if ((code == KeyEvent.KEYCODE_VOLUME_UP || code == KeyEvent.KEYCODE_VOLUME_DOWN) && ims.isInputViewShown()) {
|
|
String pkgName = Settings.Global.getString(ims.getContentResolver(), Helpers.modulePkg + ".foreground.package");
|
|
if (MainModule.mPrefs.getStringSet("controls_volumecursor_apps").contains(pkgName)) return;
|
|
boolean swapDir = MainModule.mPrefs.getBoolean("controls_volumecursor_reverse");
|
|
ims.sendDownUpKeyEvents(code == (swapDir ? KeyEvent.KEYCODE_VOLUME_DOWN : KeyEvent.KEYCODE_VOLUME_UP) ? KeyEvent.KEYCODE_DPAD_LEFT : KeyEvent.KEYCODE_DPAD_RIGHT);
|
|
param.setResult(true);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("android.inputmethodservice.InputMethodService", null, "onKeyUp", int.class, KeyEvent.class, new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
InputMethodService ims = (InputMethodService)param.thisObject;
|
|
int code = (int)param.args[0];
|
|
if ((code == KeyEvent.KEYCODE_VOLUME_UP || code == KeyEvent.KEYCODE_VOLUME_DOWN) && ims.isInputViewShown()) {
|
|
String pkgName = Settings.Global.getString(ims.getContentResolver(), Helpers.modulePkg + ".foreground.package");
|
|
if (!MainModule.mPrefs.getStringSet("controls_volumecursor_apps").contains(pkgName)) param.setResult(true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private static boolean handleNavBarAction(Context context, String key) {
|
|
int action = Helpers.getSharedIntPref(context, key + "_action", 1);
|
|
if (action >= 85 && action <= 88) {
|
|
if (GlobalActions.isMediaActionsAllowed(context))
|
|
GlobalActions.sendDownUpKeyEvent(context, action, false);
|
|
return true;
|
|
} else if (action == 1) {
|
|
try {
|
|
Toast.makeText(Helpers.getModuleContext(context), R.string.controls_navbar_noaction, Toast.LENGTH_SHORT).show();
|
|
} catch (Throwable ignore) {}
|
|
return false;
|
|
} else {
|
|
return GlobalActions.handleAction(context, key);
|
|
}
|
|
}
|
|
|
|
private static void addCustomNavBarKeys(boolean isVertical, Context mContext, LinearLayout navButtons, Class<?> kbrCls) {
|
|
String pkgName = "com.android.systemui";
|
|
float density = mContext.getResources().getDisplayMetrics().density;
|
|
int two = Math.round(2 * density);
|
|
int margin = Math.round(MainModule.mPrefs.getInt("controls_navbarmargin", 0) * density);
|
|
|
|
Drawable dot1;
|
|
Drawable dot2;
|
|
try {
|
|
Context modCtx = Helpers.getModuleContext(mContext);
|
|
Resources modRes = Helpers.getModuleRes(mContext);
|
|
dot1 = modRes.getDrawable(R.drawable.ic_sysbar_dot_bottomleft, modCtx.getTheme());
|
|
dot2 = modRes.getDrawable(R.drawable.ic_sysbar_dot_topright, modCtx.getTheme());
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
return;
|
|
}
|
|
|
|
int diff1 = (dot1.getIntrinsicWidth() - dot1.getIntrinsicHeight()) / 2;
|
|
int diff2 = (dot2.getIntrinsicWidth() - dot2.getIntrinsicHeight()) / 2;
|
|
LinearLayout leftbtn = new LinearLayout(mContext);
|
|
ImageView left = new ImageView(mContext);
|
|
|
|
LinearLayout.LayoutParams lplc;
|
|
if (isVertical)
|
|
lplc = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
else
|
|
lplc = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
|
left.setLayoutParams(lplc);
|
|
|
|
LinearLayout.LayoutParams lpl = new LinearLayout.LayoutParams(lplc);
|
|
if (isVertical)
|
|
lpl.bottomMargin += margin;
|
|
else
|
|
lpl.leftMargin += margin;
|
|
leftbtn.setLayoutParams(lpl);
|
|
|
|
left.setScaleType(ImageView.ScaleType.CENTER);
|
|
left.setImageDrawable(dot1);
|
|
left.setScaleX(0.7f);
|
|
left.setScaleY(0.7f);
|
|
left.setAlpha(0.9f);
|
|
left.setPadding(isVertical ? 0 : two, isVertical ? two + diff1 : 0, isVertical ? 0 : two, isVertical ? two + diff1 : 0);
|
|
left.setTag("custom_left" + (isVertical ? "_vert" : "_horiz"));
|
|
if (kbrCls != null) try {
|
|
Drawable lripple = (Drawable)kbrCls.getConstructor(Context.class, View.class).newInstance(mContext, leftbtn);
|
|
leftbtn.setBackground(lripple);
|
|
} catch (Throwable ignore) {}
|
|
leftbtn.setClickable(true);
|
|
leftbtn.setHapticFeedbackEnabled(true);
|
|
leftbtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
handleNavBarAction(v.getContext(), "pref_key_controls_navbarleft");
|
|
}
|
|
});
|
|
leftbtn.setOnLongClickListener(new View.OnLongClickListener() {
|
|
@Override
|
|
public boolean onLongClick(View v) {
|
|
return handleNavBarAction(v.getContext(), "pref_key_controls_navbarleftlong");
|
|
}
|
|
});
|
|
leftbtn.addView(left);
|
|
|
|
LinearLayout rightbtn = new LinearLayout(mContext);
|
|
ImageView right = new ImageView(mContext);
|
|
LinearLayout.LayoutParams lprc;
|
|
if (isVertical)
|
|
lprc = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
else
|
|
lprc = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT);
|
|
right.setLayoutParams(lprc);
|
|
|
|
LinearLayout.LayoutParams lpr = new LinearLayout.LayoutParams(lprc);
|
|
if (isVertical)
|
|
lpr.topMargin += margin;
|
|
else
|
|
lpr.rightMargin += margin;
|
|
rightbtn.setLayoutParams(lpr);
|
|
|
|
right.setScaleType(ImageView.ScaleType.CENTER);
|
|
right.setImageDrawable(dot2);
|
|
right.setScaleX(0.7f);
|
|
right.setScaleY(0.7f);
|
|
right.setAlpha(0.9f);
|
|
right.setPadding(isVertical ? 0 : two, isVertical ? two + diff2 : 0, isVertical ? 0 : two, isVertical ? two + diff2 : 0);
|
|
right.setTag("custom_right" + (isVertical ? "_vert" : "_horiz"));
|
|
if (kbrCls != null) try {
|
|
Drawable rripple = (Drawable)kbrCls.getConstructor(Context.class, View.class).newInstance(mContext, rightbtn);
|
|
rightbtn.setBackground(rripple);
|
|
} catch (Throwable ignore) {}
|
|
rightbtn.setClickable(true);
|
|
rightbtn.setHapticFeedbackEnabled(true);
|
|
rightbtn.setOnClickListener(new View.OnClickListener() {
|
|
@Override
|
|
public void onClick(View v) {
|
|
handleNavBarAction(v.getContext(), "pref_key_controls_navbarright");
|
|
}
|
|
});
|
|
rightbtn.setOnLongClickListener(new View.OnLongClickListener() {
|
|
@Override
|
|
public boolean onLongClick(View v) {
|
|
return handleNavBarAction(v.getContext(), "pref_key_controls_navbarrightlong");
|
|
}
|
|
});
|
|
rightbtn.addView(right);
|
|
|
|
View startPadding = navButtons.findViewById(navButtons.getResources().getIdentifier("start_padding", "id", pkgName));
|
|
View sidePadding = navButtons.findViewById(navButtons.getResources().getIdentifier("side_padding", "id", pkgName));
|
|
|
|
LinearLayout.LayoutParams lp1 = (LinearLayout.LayoutParams)startPadding.getLayoutParams();
|
|
LinearLayout.LayoutParams lp2 = (LinearLayout.LayoutParams)sidePadding.getLayoutParams();
|
|
|
|
boolean hasLeftAction = MainModule.mPrefs.getInt("controls_navbarleft_action", 1) > 1 || MainModule.mPrefs.getInt("controls_navbarleftlong_action", 1) > 1;
|
|
boolean hasRightAction = MainModule.mPrefs.getInt("controls_navbarright_action", 1) > 1 || MainModule.mPrefs.getInt("controls_navbarrightlong_action", 1) > 1;
|
|
|
|
float part = Helpers.is11() ? 0.55f : 0.5f;
|
|
if (isVertical) {
|
|
if (hasRightAction) {
|
|
navButtons.addView(rightbtn, 0);
|
|
lp2.weight = Math.round(lp2.weight * part);
|
|
sidePadding.setLayoutParams(lp2);
|
|
sidePadding.setPadding(sidePadding.getPaddingLeft(), sidePadding.getPaddingTop() / 3, sidePadding.getPaddingRight(), sidePadding.getPaddingBottom());
|
|
}
|
|
if (hasLeftAction) {
|
|
navButtons.addView(leftbtn, navButtons.getChildCount());
|
|
lp1.weight = Math.round(lp1.weight * part);
|
|
startPadding.setLayoutParams(lp1);
|
|
}
|
|
} else {
|
|
if (hasLeftAction) {
|
|
navButtons.addView(leftbtn, 0);
|
|
lp1.weight = Math.round(lp1.weight * part);
|
|
startPadding.setLayoutParams(lp1);
|
|
}
|
|
if (hasRightAction) {
|
|
navButtons.addView(rightbtn, navButtons.getChildCount());
|
|
lp2.weight = Math.round(lp2.weight * part);
|
|
sidePadding.setLayoutParams(lp2);
|
|
sidePadding.setPadding(sidePadding.getPaddingLeft(), sidePadding.getPaddingTop(), sidePadding.getPaddingRight() / 3, sidePadding.getPaddingBottom());
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void NavBarButtonsHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "createNavigationBar", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Class<?> kbrCls = XposedHelpers.findClassIfExists("com.android.systemui.statusbar.policy.KeyButtonRipple", lpparam.classLoader);
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (mContext == null) {
|
|
Helpers.log("NavBarButtonsHook", "Cannot find context");
|
|
return;
|
|
}
|
|
LinearLayout mNavigationBarView = (LinearLayout)XposedHelpers.getObjectField(param.thisObject, "mNavigationBarView");
|
|
if (mNavigationBarView == null) {
|
|
Helpers.log("NavBarButtonsHook", "Cannot find navbar layout");
|
|
return;
|
|
}
|
|
ViewGroup rot0 = mNavigationBarView.findViewById(mNavigationBarView.getResources().getIdentifier("rot0", "id", lpparam.packageName));
|
|
ViewGroup rot90 = mNavigationBarView.findViewById(mNavigationBarView.getResources().getIdentifier("rot90", "id", lpparam.packageName));
|
|
LinearLayout navButtons0 = rot0.findViewById(mNavigationBarView.getResources().getIdentifier("nav_buttons", "id", lpparam.packageName));
|
|
LinearLayout navButtons90 = rot90.findViewById(mNavigationBarView.getResources().getIdentifier("nav_buttons", "id", lpparam.packageName));
|
|
|
|
addCustomNavBarKeys(false, mContext, navButtons0, kbrCls);
|
|
addCustomNavBarKeys(true, mContext, navButtons90, kbrCls);
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.NavigationBarView", lpparam.classLoader, "switchSuit", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
LinearLayout navbar = (LinearLayout)param.thisObject;
|
|
boolean isDark = (boolean)param.args[1];
|
|
ImageView hleft = navbar.findViewWithTag("custom_left_horiz");
|
|
ImageView vleft = navbar.findViewWithTag("custom_left_vert");
|
|
ImageView hright = navbar.findViewWithTag("custom_right_horiz");
|
|
ImageView vright = navbar.findViewWithTag("custom_right_vert");
|
|
|
|
Context modCtx = Helpers.getModuleContext(navbar.getContext());
|
|
Resources modRes = Helpers.getModuleRes(navbar.getContext());
|
|
if (isDark) {
|
|
Drawable darkImg1 = modRes.getDrawable(R.drawable.ic_sysbar_dot_bottomleft_dark, modCtx.getTheme());
|
|
Drawable darkImg2 = modRes.getDrawable(R.drawable.ic_sysbar_dot_topright_dark, modCtx.getTheme());
|
|
if (hleft != null) hleft.setImageDrawable(darkImg1);
|
|
if (vleft != null) vleft.setImageDrawable(darkImg1);
|
|
if (hright != null) hright.setImageDrawable(darkImg2);
|
|
if (vright != null) vright.setImageDrawable(darkImg2);
|
|
} else {
|
|
Drawable lightImg1 = modRes.getDrawable(R.drawable.ic_sysbar_dot_bottomleft, modCtx.getTheme());
|
|
Drawable lightImg2 = modRes.getDrawable(R.drawable.ic_sysbar_dot_topright, modCtx.getTheme());
|
|
if (hleft != null) hleft.setImageDrawable(lightImg1);
|
|
if (vleft != null) vleft.setImageDrawable(lightImg1);
|
|
if (hright != null) hright.setImageDrawable(lightImg2);
|
|
if (vright != null) vright.setImageDrawable(lightImg2);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
@SuppressLint("MissingPermission")
|
|
private static boolean handleCallAction(int action) {
|
|
TelecomManager tm = (TelecomManager)miuiPWMContext.getSystemService(Context.TELECOM_SERVICE);
|
|
if (tm == null) return false;
|
|
if (!tm.isInCall()) return false;
|
|
int callState = (int)XposedHelpers.callMethod(tm, "getCallState");
|
|
if (callState == TelephonyManager.CALL_STATE_RINGING) {
|
|
int accept = MainModule.mPrefs.getStringAsInt("controls_fingerprint_accept", 1);
|
|
int reject = MainModule.mPrefs.getStringAsInt("controls_fingerprint_reject", 1);
|
|
if (action == accept) {
|
|
XposedHelpers.callMethod(tm, "acceptRingingCall");
|
|
return true;
|
|
} else if (action == reject) {
|
|
XposedHelpers.callMethod(tm, "endCall");
|
|
return true;
|
|
}
|
|
} else if (callState == TelephonyManager.CALL_STATE_OFFHOOK) {
|
|
int hangup = MainModule.mPrefs.getStringAsInt("controls_fingerprint_hangup", 1);
|
|
if (action == hangup) {
|
|
XposedHelpers.callMethod(tm, "endCall");
|
|
return true;
|
|
}
|
|
}
|
|
return MainModule.mPrefs.getBoolean("controls_fingerprintskip2");
|
|
}
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
private static Context miuiPWMContext;
|
|
private static Handler miuiPWMHandler;
|
|
private static boolean hasDoubleTap = false;
|
|
private static boolean wasScreenOn = false;
|
|
private static boolean wasFingerprintUsed = false;
|
|
private static boolean isFingerprintPressed = false;
|
|
private static boolean isFingerprintLongPressed = false;
|
|
private static boolean isFingerprintLongPressHandled = false;
|
|
private static final Runnable singlePressFingerprint = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (miuiPWMContext == null || miuiPWMHandler == null) return;
|
|
miuiPWMHandler.removeCallbacks(longPressFingerprint);
|
|
if (!handleCallAction(2)) GlobalActions.handleAction(miuiPWMContext, "pref_key_controls_fingerprint1");
|
|
}
|
|
};
|
|
private static final Runnable longPressFingerprint = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
if (isFingerprintPressed) {
|
|
isFingerprintLongPressed = true;
|
|
isFingerprintLongPressHandled = handleCallAction(4);
|
|
Helpers.performStrongVibration(miuiPWMContext, true);
|
|
}
|
|
}
|
|
};
|
|
|
|
public static void FingerprintEventsHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "initInternal", 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_controls_fingerprint")) 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.findAndHookMethod("com.android.server.policy.MiuiPhoneWindowManager", lpparam.classLoader, "processFingerprintNavigationEvent", KeyEvent.class, boolean.class, new MethodHook() {
|
|
@Override
|
|
@SuppressLint("MissingPermission")
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
if (MainModule.mPrefs.getBoolean("controls_fingerprintskip")) {
|
|
Object mFocusedWindow = XposedHelpers.getObjectField(param.thisObject, "mFocusedWindow");
|
|
if ((boolean)param.args[1] && mFocusedWindow != null) {
|
|
String ownPkg = (String)XposedHelpers.callMethod(mFocusedWindow, "getOwningPackage");
|
|
if ("com.android.camera".equals(ownPkg)) return;
|
|
}
|
|
}
|
|
|
|
miuiPWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
miuiPWMHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
|
|
if (miuiPWMContext == null || miuiPWMHandler == null) return;
|
|
|
|
boolean isInCall = false;
|
|
if (miuiPWMContext != null) {
|
|
TelecomManager tm = (TelecomManager)miuiPWMContext.getSystemService(Context.TELECOM_SERVICE);
|
|
isInCall = tm != null && tm.isInCall();
|
|
}
|
|
|
|
KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
if (keyEvent.getKeyCode() != KeyEvent.KEYCODE_DPAD_CENTER || keyEvent.getAction() != KeyEvent.ACTION_DOWN) return;
|
|
|
|
isFingerprintPressed = true;
|
|
wasScreenOn = (boolean)XposedHelpers.callMethod(param.thisObject, "isScreenOn");
|
|
wasFingerprintUsed = Settings.System.getInt(miuiPWMContext.getContentResolver(), "is_fingerprint_active", 0) == 1;
|
|
|
|
hasDoubleTap = false;
|
|
if (wasScreenOn && !wasFingerprintUsed) {
|
|
int delay = MainModule.mPrefs.getInt("controls_fingerprintlong_delay", 0);
|
|
if (isInCall) {
|
|
int accept = MainModule.mPrefs.getStringAsInt("controls_fingerprint_accept", 1);
|
|
int reject = MainModule.mPrefs.getStringAsInt("controls_fingerprint_reject", 1);
|
|
int hangup = MainModule.mPrefs.getStringAsInt("controls_fingerprint_hangup", 1);
|
|
hasDoubleTap = accept == 3 || reject == 3 || hangup == 3;
|
|
if (accept == 4 || reject == 4 || hangup == 4)
|
|
miuiPWMHandler.postDelayed(longPressFingerprint, delay < 200 ? ViewConfiguration.getLongPressTimeout() : delay);
|
|
} else {
|
|
int dtaction = MainModule.mPrefs.getInt("controls_fingerprint2_action", 1);
|
|
hasDoubleTap = dtaction > 1;
|
|
if (MainModule.mPrefs.getInt("controls_fingerprintlong_action", 1) > 1)
|
|
miuiPWMHandler.postDelayed(longPressFingerprint, delay < 200 ? ViewConfiguration.getLongPressTimeout() : delay);
|
|
}
|
|
}
|
|
|
|
if (XposedHelpers.getAdditionalInstanceField(param.thisObject, "touchTime") == null)
|
|
XposedHelpers.setAdditionalInstanceField(param.thisObject, "touchTime", 0L);
|
|
}
|
|
|
|
@Override
|
|
@SuppressLint("MissingPermission")
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
if (MainModule.mPrefs.getBoolean("controls_fingerprintskip")) {
|
|
Object mFocusedWindow = XposedHelpers.getObjectField(param.thisObject, "mFocusedWindow");
|
|
if ((boolean)param.args[1] && mFocusedWindow != null) {
|
|
String ownPkg = (String)XposedHelpers.callMethod(mFocusedWindow, "getOwningPackage");
|
|
if ("com.android.camera".equals(ownPkg)) return;
|
|
}
|
|
}
|
|
|
|
KeyEvent keyEvent = (KeyEvent)param.args[0];
|
|
if (keyEvent.getKeyCode() != KeyEvent.KEYCODE_DPAD_CENTER || keyEvent.getAction() != KeyEvent.ACTION_UP) return;
|
|
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
Handler mHandler = (Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler");
|
|
|
|
long lastTouchTime = (long)XposedHelpers.getAdditionalInstanceField(param.thisObject, "touchTime");
|
|
long currentTouchTime = currentTimeMillis();
|
|
XposedHelpers.setAdditionalInstanceField(param.thisObject, "touchTime", currentTouchTime);
|
|
|
|
int delay = MainModule.mPrefs.getInt("controls_fingerprint2_delay", 50);
|
|
int dttimeout = delay < 200 ? ViewConfiguration.getDoubleTapTimeout() : delay;
|
|
if (wasScreenOn && !wasFingerprintUsed) {
|
|
if (hasDoubleTap && currentTouchTime - lastTouchTime < dttimeout) {
|
|
mHandler.removeCallbacks(singlePressFingerprint);
|
|
mHandler.removeCallbacks(longPressFingerprint);
|
|
if (!handleCallAction(3)) GlobalActions.handleAction(mContext, "pref_key_controls_fingerprint2");
|
|
wasScreenOn = false;
|
|
} else if (isFingerprintLongPressed) {
|
|
if (!isFingerprintLongPressHandled) GlobalActions.handleAction(mContext, "pref_key_controls_fingerprintlong");
|
|
isFingerprintLongPressHandled = false;
|
|
wasScreenOn = false;
|
|
} else {
|
|
mHandler.removeCallbacks(longPressFingerprint);
|
|
mHandler.removeCallbacks(singlePressFingerprint);
|
|
if (hasDoubleTap)
|
|
mHandler.postDelayed(singlePressFingerprint, dttimeout);
|
|
else
|
|
mHandler.post(singlePressFingerprint);
|
|
}
|
|
}
|
|
|
|
isFingerprintLongPressed = false;
|
|
isFingerprintPressed = false;
|
|
}
|
|
});
|
|
|
|
String fpService = Helpers.isQPlus() ? "com.android.server.biometrics.BiometricServiceBase" : "com.android.server.fingerprint.FingerprintService";
|
|
Helpers.hookAllMethods(fpService, lpparam.classLoader, "startClient", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
Settings.System.putInt(mContext.getContentResolver(), "is_fingerprint_active", 1);
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllMethods(fpService, lpparam.classLoader, "removeClient", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
Settings.System.putInt(mContext.getContentResolver(), "is_fingerprint_active", 0);
|
|
}
|
|
});
|
|
}
|
|
|
|
// public static void FingerprintHook(LoadPackageParam lpparam) {
|
|
// Helpers.findAndHookMethod("com.android.server.devicepolicy.DevicePolicyManagerService", lpparam.classLoader, "reportSuccessfulFingerprintAttempt", int.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(MethodHookParam param) throws Throwable {
|
|
// Helpers.log("reportSuccessfulFingerprintAttempt");
|
|
// Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
public static void FSGesturesSysHook() {
|
|
Helpers.findAndHookMethod("android.provider.MiuiSettings$Global", null, "getBoolean", ContentResolver.class, String.class, new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
if (!"force_fsg_nav_bar".equals(param.args[1])) return;
|
|
|
|
ContentResolver resolver = (ContentResolver)param.args[0];
|
|
Context mContext = (Context)XposedHelpers.getObjectField(resolver, "mContext");
|
|
|
|
if ("com.android.systemui".equals(mContext.getPackageName()))
|
|
for (StackTraceElement el: Thread.currentThread().getStackTrace())
|
|
if ("com.android.systemui.recents.BaseRecentsImpl".equals(el.getClassName())) {
|
|
param.setResult(true);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void FSGesturesHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.systemui.fsgesture.GestureStubView", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
MotionEvent event = (MotionEvent)param.args[0];
|
|
if (event.getAction() != MotionEvent.ACTION_DOWN) return;
|
|
View stub = (View)param.thisObject;
|
|
String pkgName = Settings.Global.getString(stub.getContext().getContentResolver(), Helpers.modulePkg + ".foreground.package");
|
|
if (MainModule.mPrefs.getStringSet("controls_fsg_horiz_apps").contains(pkgName)) param.setResult(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
@SuppressLint("StaticFieldLeak")
|
|
private static Context basePWMContext;
|
|
private static Object basePWMObject;
|
|
private static Method markShortcutTriggered;
|
|
|
|
private static final Runnable mBackLongPressAction = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (basePWMContext == null || basePWMObject == null) return;
|
|
if (GlobalActions.handleAction(basePWMContext, "pref_key_controls_backlong")) Helpers.performStrongVibration(basePWMContext);
|
|
if (Helpers.getSharedIntPref(basePWMContext, "pref_key_controls_backlong_action", 1) != 1) markShortcutTriggered.invoke(basePWMObject);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
};
|
|
private static final Runnable mHomeLongPressAction = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (basePWMContext == null || basePWMObject == null) return;
|
|
if (GlobalActions.handleAction(basePWMContext, "pref_key_controls_homelong")) Helpers.performStrongVibration(basePWMContext);
|
|
if (Helpers.getSharedIntPref(basePWMContext, "pref_key_controls_homelong_action", 1) != 1) markShortcutTriggered.invoke(basePWMObject);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
};
|
|
private static final Runnable mMenuLongPressAction = new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
if (basePWMContext == null || basePWMObject == null) return;
|
|
if (GlobalActions.handleAction(basePWMContext, "pref_key_controls_menulong")) Helpers.performStrongVibration(basePWMContext);
|
|
if (Helpers.getSharedIntPref(basePWMContext, "pref_key_controls_menulong_action", 1) != 1) markShortcutTriggered.invoke(basePWMObject);
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
};
|
|
|
|
public static void NavBarActionsHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "initInternal", 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);
|
|
if (!type.equals("integer")) return;
|
|
String key = uri.getPathSegments().get(2);
|
|
if (key.contains("pref_key_controls_backlong") || key.contains("pref_key_controls_homelong") || key.contains("pref_key_controls_menulong")) {
|
|
if (key.contains("_action"))
|
|
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 1));
|
|
else if (key.contains("_toggle"))
|
|
MainModule.mPrefs.put(key, Helpers.getSharedIntPref(mContext, key, 0));
|
|
}
|
|
} catch (Throwable t) {
|
|
XposedBridge.log(t);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllMethods("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "postKeyLongPress", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
if (basePWMObject == null) basePWMObject = param.thisObject;
|
|
if (basePWMContext == null) basePWMContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (markShortcutTriggered == null) markShortcutTriggered = XposedHelpers.findMethodExact("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "markShortcutTriggered");
|
|
|
|
int key = (int)param.args[0];
|
|
if (key == KeyEvent.KEYCODE_BACK && MainModule.mPrefs.getInt("controls_backlong_action", 1) > 1) {
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).postDelayed(mBackLongPressAction, ViewConfiguration.getLongPressTimeout());
|
|
param.setResult(null);
|
|
} else if (key == KeyEvent.KEYCODE_HOME && MainModule.mPrefs.getInt("controls_homelong_action", 1) > 1) {
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).postDelayed(mHomeLongPressAction, ViewConfiguration.getLongPressTimeout());
|
|
param.setResult(null);
|
|
} else if (key == KeyEvent.KEYCODE_APP_SWITCH && MainModule.mPrefs.getInt("controls_menulong_action", 1) > 1) {
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).postDelayed(mMenuLongPressAction, ViewConfiguration.getLongPressTimeout());
|
|
param.setResult(null);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllMethods("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "removeKeyLongPress", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
int key = (int)param.args[0];
|
|
if (key == KeyEvent.KEYCODE_BACK)
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).removeCallbacks(mBackLongPressAction);
|
|
else if (key == KeyEvent.KEYCODE_HOME)
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).removeCallbacks(mHomeLongPressAction);
|
|
else if (key == KeyEvent.KEYCODE_APP_SWITCH)
|
|
((Handler)XposedHelpers.getObjectField(param.thisObject, "mHandler")).removeCallbacks(mMenuLongPressAction);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void NavbarHeightRes() {
|
|
int opt = MainModule.mPrefs.getInt("controls_navbarheight", 19);
|
|
int heightDpi = opt == 19 ? 47 : opt;
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_height", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_height_landscape", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_frame_height", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_frame_height_landscape", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_gesture_height", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("*", "dimen", "navigation_bar_width", heightDpi);
|
|
MainModule.resHooks.setDensityReplacement("com.android.systemui", "dimen", "navigation_bar_size", heightDpi);
|
|
//MainModule.resHooks.setDensityReplacement("com.android.systemui", "dimen", "navigation_extra_key_width", heightDpi);
|
|
}
|
|
|
|
public static void FingerprintHapticSuccessHook(LoadPackageParam lpparam) {
|
|
String authClient = Helpers.isQPlus() ? "com.android.server.biometrics.AuthenticationClient" : "com.android.server.fingerprint.AuthenticationClient";
|
|
Helpers.hookAllMethods(authClient, lpparam.classLoader, "onAuthenticated", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
if (!((boolean)param.getResult())) return;
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
// boolean isScreenOn = (boolean)XposedHelpers.callMethod(param.thisObject, "isScreenOn");
|
|
// if (!isScreenOn) {
|
|
// WakeLock wl = ((PowerManager)mContext.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "miuizer:fingerprint_haptic_feedback");
|
|
// wl.acquire(2000);
|
|
// }
|
|
|
|
boolean ignoreSystem = MainModule.mPrefs.getBoolean("controls_fingerprintsuccess_ignore");
|
|
int opt = Integer.parseInt(MainModule.mPrefs.getString("controls_fingerprintsuccess", "1"));
|
|
if (opt == 2)
|
|
Helpers.performLightVibration(mContext, ignoreSystem);
|
|
else if (opt == 3)
|
|
Helpers.performStrongVibration(mContext, ignoreSystem);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void FingerprintHapticFailureHook(LoadPackageParam lpparam) {
|
|
if (Helpers.isNougat())
|
|
Helpers.findAndHookMethod("com.android.server.fingerprint.FingerprintUtils", lpparam.classLoader, "vibrateFingerprintError", Context.class, XC_MethodReplacement.returnConstant(null));
|
|
else {
|
|
String monitorClass = Helpers.isQPlus() ? "com.android.server.biometrics.ClientMonitor" : "com.android.server.fingerprint.ClientMonitor";
|
|
Helpers.hookAllMethods("com.android.server.VibratorService", lpparam.classLoader, "vibrate", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
|
for (StackTraceElement el : stackTrace)
|
|
if (monitorClass.equals(el.getClassName()) && "vibrateError".equals(el.getMethodName())) {
|
|
param.setResult(null);
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
public static void FingerprintScreenOnHook(LoadPackageParam lpparam) {
|
|
String authClient = Helpers.isQPlus() ? "com.android.server.biometrics.AuthenticationClient" : "com.android.server.fingerprint.AuthenticationClient";
|
|
Helpers.hookAllMethods(authClient, lpparam.classLoader, "onAuthenticated", new MethodHook() {
|
|
@Override
|
|
protected void after(MethodHookParam param) throws Throwable {
|
|
if ((boolean)param.getResult()) return;
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
PowerManager mPowerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
|
|
if (mPowerManager.isInteractive()) return;
|
|
if (!GlobalActions.wakeUp(mContext)) Helpers.log("FingerprintScreenOnHook", "Failed to wake up device");
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void BackGestureAreaHeightHook(LoadPackageParam lpparam, boolean isNative) {
|
|
if (!Helpers.findAndHookMethodSilently(isNative ? "com.android.systemui.fsgesture.GestureStubView" : "com.miui.home.recents.GestureStubView", lpparam.classLoader, "getGestureStubWindowParam", new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
WindowManager.LayoutParams lp = (WindowManager.LayoutParams)param.getResult();
|
|
int pct = MainModule.mPrefs.getInt("controls_fsg_coverage", 60);
|
|
lp.height = Math.round(lp.height / 60.0f * pct);
|
|
param.setResult(lp);
|
|
}
|
|
})) if (isNative) Helpers.log("BackGestureAreaHeightHook", "Cannot hook GestureStubView");
|
|
}
|
|
|
|
public static void BackGestureAreaWidthHook(LoadPackageParam lpparam, boolean isNative) {
|
|
if (!Helpers.findAndHookMethodSilently(isNative ? "com.android.systemui.fsgesture.GestureStubView" : "com.miui.home.recents.GestureStubView", lpparam.classLoader, "initScreenSizeAndDensity", int.class, new MethodHook() {
|
|
@Override
|
|
protected void after(final MethodHookParam param) throws Throwable {
|
|
int pct = MainModule.mPrefs.getInt("controls_fsg_width", 100);
|
|
if (pct == 100) return;
|
|
int mGestureStubDefaultSize = XposedHelpers.getIntField(param.thisObject, "mGestureStubDefaultSize");
|
|
int mGestureStubSize = XposedHelpers.getIntField(param.thisObject, "mGestureStubSize");
|
|
mGestureStubDefaultSize = Math.round(mGestureStubDefaultSize * pct / 100f);
|
|
mGestureStubSize = Math.round(mGestureStubSize * pct / 100f);
|
|
XposedHelpers.setIntField(param.thisObject, "mGestureStubDefaultSize", mGestureStubDefaultSize);
|
|
XposedHelpers.setIntField(param.thisObject, "mGestureStubSize", mGestureStubSize);
|
|
}
|
|
})) if (isNative) Helpers.log("BackGestureAreaWidthHook", "Cannot hook GestureStubView1");
|
|
|
|
if (!Helpers.findAndHookMethodSilently(isNative ? "com.android.systemui.fsgesture.GestureStubView" : "com.miui.home.recents.GestureStubView", lpparam.classLoader, "setSize", int.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
int pct = MainModule.mPrefs.getInt("controls_fsg_width", 100);
|
|
if (pct == 100) return;
|
|
int mGestureStubDefaultSize = XposedHelpers.getIntField(param.thisObject, "mGestureStubDefaultSize");
|
|
if ((int)param.args[0] == mGestureStubDefaultSize) return;
|
|
param.args[0] = Math.round((int)param.args[0] * pct / 100f);
|
|
}
|
|
})) if (isNative) Helpers.log("BackGestureAreaWidthHook", "Cannot hook GestureStubView2");
|
|
}
|
|
|
|
public static void HideNavBarHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "addNavigationBar", XC_MethodReplacement.DO_NOTHING);
|
|
Helpers.findAndHookMethod("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "changeNavBarViewState", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
XposedHelpers.callMethod(param.thisObject, "removeNavBarView");
|
|
XposedHelpers.callMethod(param.thisObject, "updateStatusBarPading");
|
|
param.setResult(null);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void ImeBackAltIconHook(LoadPackageParam lpparam) {
|
|
Helpers.hookAllMethods("com.android.systemui.statusbar.phone.StatusBar", lpparam.classLoader, "setImeWindowStatus", new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
Object mNavigationBarView = XposedHelpers.getObjectField(param.thisObject, "mNavigationBarView");
|
|
if (mNavigationBarView != null) XposedHelpers.callMethod(mNavigationBarView, "setNavigationIconHints", param.args[1], false);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void PowerDoubleTapActionHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "launchApp", Intent.class, new MethodHook() {
|
|
@Override
|
|
protected void before(MethodHookParam param) throws Throwable {
|
|
Intent intent = (Intent)param.args[0];
|
|
if (intent == null) return;
|
|
if (!"android.media.action.STILL_IMAGE_CAMERA".equals(intent.getAction())) return;
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (GlobalActions.handleAction(mContext, "pref_key_controls_powerdt", true)) param.setResult(true);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void NoScreenshotChordRes() {
|
|
MainModule.resHooks.setObjectReplacement("android", "bool", "config_enableScreenshotChord", false);
|
|
}
|
|
|
|
public static void NoFingerprintWakeHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.server.policy.MiuiPhoneWindowManager", lpparam.classLoader, "processBackFingerprintDpcenterEvent", KeyEvent.class, boolean.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
boolean isScreenOn = (boolean)param.args[1];
|
|
if (!isScreenOn) param.setResult(null);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void AssistGestureActionHook(LoadPackageParam lpparam) {
|
|
Helpers.findAndHookMethod("com.android.systemui.assist.AssistManager", lpparam.classLoader, "startAssist", Bundle.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
Bundle bundle = (Bundle)param.args[0];
|
|
if (bundle == null || bundle.getInt("triggered_by", 0) != 83 || bundle.getInt("invocation_type", 0) != 1) return;
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (GlobalActions.handleAction(mContext, "pref_key_controls_fsg_assist")) {
|
|
Helpers.performLightVibration(mContext);
|
|
param.setResult(null);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.findAndHookMethod("com.android.systemui.assist.AssistManager", lpparam.classLoader, "startAssist", Bundle.class, new MethodHook() {
|
|
@Override
|
|
protected void before(final MethodHookParam param) throws Throwable {
|
|
Bundle bundle = (Bundle)param.args[0];
|
|
if (bundle == null || bundle.getInt("triggered_by", 0) != 83 || bundle.getInt("invocation_type", 0) != 1) return;
|
|
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
if (GlobalActions.handleAction(mContext, "pref_key_controls_fsg_assist")) {
|
|
Helpers.performLightVibration(mContext);
|
|
param.setResult(null);
|
|
}
|
|
}
|
|
});
|
|
|
|
Helpers.hookAllConstructors("com.android.systemui.assist.ui.DefaultUiController", lpparam.classLoader, 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, "pref_key_controls_fsg_assist_action", 1) {
|
|
@Override
|
|
public void onChange(String name, int defValue) {
|
|
Object mInvocationLightsView = XposedHelpers.getObjectField(param.thisObject, "mInvocationLightsView");
|
|
if (mInvocationLightsView == null) return;
|
|
int opt = Helpers.getSharedIntPref(mContext, name, defValue);
|
|
if (opt > 1)
|
|
XposedHelpers.callMethod(mInvocationLightsView, "setColors", Color.parseColor("#424A60"), Color.parseColor("#EC7C6D"), Color.parseColor("#EC7C6D"), Color.parseColor("#424A60"));
|
|
else
|
|
XposedHelpers.callMethod(mInvocationLightsView, "setColors", -16776961, -65536, -256, -16711936);
|
|
}
|
|
}.onChange(false);
|
|
}
|
|
});
|
|
}
|
|
|
|
// public static void AIButtonHook(LoadPackageParam lpparam) {
|
|
// Helpers.findAndHookMethod("com.android.server.policy.BaseMiuiPhoneWindowManager", lpparam.classLoader, "startAiKeyService", String.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(MethodHookParam param) throws Throwable {
|
|
// Helpers.log("AIButtonHook", "startAiKeyService: " + param.args[0]);
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
// public static void SwapVolumeKeysHook(LoadPackageParam lpparam) {
|
|
// Helpers.findAndHookMethod("com.android.server.audio.AudioService", lpparam.classLoader, "adjustSuggestedStreamVolume", int.class, int.class, int.class, String.class, String.class, int.class, new MethodHook() {
|
|
// @Override
|
|
// protected void before(MethodHookParam param) throws Throwable {
|
|
// //Helpers.log("adjustStreamVolume: " + String.valueOf(param.args[0]) + ", " + String.valueOf(param.args[1]) + ", " + String.valueOf(param.args[2]) + ", " + String.valueOf(param.args[3]) + ", " + String.valueOf(param.args[4]) + ", " + String.valueOf(param.args[5]));
|
|
// if ((Integer)param.args[0] != 0) try {
|
|
// Context context = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
|
|
// int rotation = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
|
|
// if (rotation == Surface.ROTATION_90) param.args[0] = -1 * (Integer)param.args[0];
|
|
// } catch (Throwable t) {
|
|
// XposedBridge.log(t);
|
|
// }
|
|
// }
|
|
// });
|
|
// }
|
|
|
|
} |