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.

2161 lines
92 KiB
Java

package com.langerhans.one.mods;
import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.callStaticMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static de.robv.android.xposed.XposedHelpers.findClass;
import static de.robv.android.xposed.XposedHelpers.getObjectField;
import static de.robv.android.xposed.XposedHelpers.getStaticObjectField;
import static de.robv.android.xposed.XposedHelpers.setObjectField;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
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.ResolveInfo;
import android.content.res.Resources;
import android.content.res.XModuleResources;
import android.content.res.XResources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Debug.MemoryInfo;
import android.os.Environment;
import android.os.Handler;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.service.notification.StatusBarNotification;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.text.TextUtils.TruncateAt;
import android.text.method.SingleLineTransformationMethod;
import android.util.TypedValue;
import android.view.Display;
import android.view.GestureDetector;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.ImageView.ScaleType;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import com.htc.widget.HtcCheckBox;
import com.htc.widget.HtcCompoundButton;
import com.htc.widget.HtcPopupWindow;
import com.htc.widget.HtcCompoundButton.OnCheckedChangeListener;
import com.htc.widget.HtcSeekBar;
import com.langerhans.one.R;
import com.langerhans.one.utils.Helpers;
import com.langerhans.one.utils.PopupAdapter;
import com.langerhans.one.utils.Version;
import de.robv.android.xposed.XC_MethodHook;
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 de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;
import de.robv.android.xposed.callbacks.XC_LayoutInflated;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class SysUIMods {
private static int densify(Context ctx, int dimens) {
return Math.round(ctx.getResources().getDisplayMetrics().density * dimens);
}
public static void execHook_InvisiBar(final InitPackageResourcesParam resparam, final int transparency) {
resparam.res.setReplacement("com.android.systemui", "drawable", "status_bar_background", new XResources.DrawableLoader() {
@Override
public Drawable newDrawable(XResources res, int id) throws Throwable {
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, resparam.res);
if (modRes.getIdentifier("status_bar_background", "drawable", "com.langerhans.one") != 0) {
Drawable sb = modRes.getDrawable(R.drawable.status_bar_background);
sb.setAlpha(transparency);
return sb;
} else return null;
}
});
//For 4.4.2 builds try to replace second drawable. Silently fail on older version
try {
resparam.res.setReplacement("com.android.systemui", "drawable", "status_bar_background_launcher", new XResources.DrawableLoader() {
@Override
public Drawable newDrawable(XResources res, int id) throws Throwable {
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, resparam.res);
if (modRes.getIdentifier("status_bar_background", "drawable", "com.langerhans.one") != 0) {
Drawable sb = modRes.getDrawable(R.drawable.status_bar_background);
sb.setAlpha(transparency);
return sb;
} else return null;
}
});
} catch (Throwable ignore){}
}
public static void execHook_MinorEQS(final LoadPackageParam lpparam, final boolean removeText) {
//Enable mEQS
findAndHookMethod("com.android.systemui.statusbar.StatusBarFlag", lpparam.classLoader, "loadMinorQuickSetting", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(true);
}
});
//Recreate method to allow more tiles to be added to mEQS
findAndHookMethod("com.android.systemui.statusbar.phone.QuickSettings", lpparam.classLoader, "refreshQuickSettingConfig", int[].class, new XC_MethodReplacement() {
@Override
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
int[] QS_DEFAULT = (int[]) getStaticObjectField(param.thisObject.getClass(), "QS_DEFAULT");
String[] QS_MAPPING = (String[]) getStaticObjectField(param.thisObject.getClass(), "QS_MAPPING");
ArrayList<String> qsContent = new ArrayList<String>();
ArrayList<String> qsContent2 = new ArrayList<String>();
int[] paramArgs;
Class<?> CustomizationUtil = findClass("com.android.systemui.CustomizationUtil", lpparam.classLoader);
Object hcr = callStaticMethod(CustomizationUtil, "getReader");
if(param.args[0] == null)
{
if(hcr == null)
paramArgs = QS_DEFAULT;
else
{
paramArgs = (int[]) callMethod(hcr, "readIntArray", "quick_setting_items", QS_DEFAULT);
}
}else
{
paramArgs = (int[]) param.args[0];
}
if (paramArgs == null || paramArgs.length == 0)
paramArgs = QS_DEFAULT;
int i = QS_MAPPING.length;
int j = 0;
for (int k = paramArgs.length; j < k; j++)
{
int i1 = paramArgs[j];
if (i1 >= 0 && i1 < i)
qsContent.add(QS_MAPPING[i1]);
}
qsContent2 = new ArrayList<String>();
int l = 0;
do
{
if (l >= qsContent.size())
break;
if (!((String)qsContent.get(l)).equals("user_card"))
qsContent2.add(qsContent.get(l));
// if (qsContent2.size() == 5)
// break;
l++;
} while (true);
setObjectField(param.thisObject, "qsContent", qsContent);
setObjectField(param.thisObject, "qsContent2", qsContent2);
return null;
}
});
//Redraw the tile view because we have added or removed something... Sense 5.5 only.
if(XMain.senseVersion.compareTo(new Version("5.5")) >= 0)
{
findAndHookMethod("com.android.systemui.statusbar.phone.QuickSettings", lpparam.classLoader, "repositionQuickSettingTile", ViewGroup.class, ArrayList.class, boolean.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ViewGroup qsContainer = (ViewGroup) getObjectField(param.thisObject, "mContainerView2");
if(!param.args[0].equals(qsContainer))
return;
WindowManager wm = (WindowManager) qsContainer.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point displaySize = new Point();
display.getSize(displaySize);
int displayWidth = displaySize.x;
for(int k = 0; k < qsContainer.getChildCount(); k++)
{
LinearLayout tmp = (LinearLayout) qsContainer.getChildAt(k);
LinearLayout.LayoutParams tmpParams = (LinearLayout.LayoutParams) tmp.getLayoutParams();
tmpParams.width = (int) Math.floor(displayWidth / 5 - 3);
tmp.setLayoutParams(tmpParams);
if(removeText)
{
View quick_setting_text = tmp.findViewById(tmp.getResources().getIdentifier("quick_setting_text", "id", "com.android.systemui"));
if (quick_setting_text != null) quick_setting_text.setVisibility(View.GONE);
ImageView qsImg = (ImageView) tmp.findViewById(tmp.getResources().getIdentifier("quick_setting_image", "id", "com.android.systemui"));
if (qsImg != null) qsImg.setPadding(0, 0, 0, 20);
}
}
qsContainer.invalidate();
}
});
}
//Makes them scrolling. Showing 5 at once.
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
FrameLayout mStatusBarWindow = (FrameLayout) getObjectField(param.thisObject, "mStatusBarWindow");
if (mStatusBarWindow != null)
{
LinearLayout qsContainer = (LinearLayout) mStatusBarWindow.findViewById(mStatusBarWindow.getResources().getIdentifier("quick_settings_minor_container", "id", "com.android.systemui"));
LinearLayout notificationContainer = (LinearLayout) mStatusBarWindow.findViewById(mStatusBarWindow.getResources().getIdentifier("notification_container", "id", "com.android.systemui"));
if (qsContainer != null && notificationContainer != null)
{
HorizontalScrollView qsScroll = new HorizontalScrollView(mStatusBarWindow.getContext());
qsScroll.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
qsScroll.setFillViewport(true);
qsScroll.setHorizontalFadingEdgeEnabled(true);
qsScroll.setHorizontalScrollBarEnabled(false);
qsScroll.setOverScrollMode(View.OVER_SCROLL_NEVER);
if (XMain.pref.getBoolean("pref_key_sysui_theqs", false))
qsScroll.setBackgroundColor(Color.TRANSPARENT);
else
qsScroll.setBackgroundColor(Color.rgb(22, 22, 22));
WindowManager wm = (WindowManager) mStatusBarWindow.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point displaySize = new Point();
display.getSize(displaySize);
int displayWidth = displaySize.x;
for(int i = 0; i < qsContainer.getChildCount(); i++)
{
LinearLayout tmp = (LinearLayout) qsContainer.getChildAt(i);
if (tmp == null) continue;
LinearLayout.LayoutParams tmpParams = (LinearLayout.LayoutParams) tmp.getLayoutParams();
tmpParams.width = (int) Math.floor(displayWidth / 5 - 3);
tmp.setLayoutParams(tmpParams);
if(removeText)
{
View quick_setting_text = tmp.findViewById(tmp.getResources().getIdentifier("quick_setting_text", "id", "com.android.systemui"));
if (quick_setting_text != null) quick_setting_text.setVisibility(View.GONE);
ImageView qsImg = (ImageView) tmp.findViewById(tmp.getResources().getIdentifier("quick_setting_image", "id", "com.android.systemui"));
if (qsImg != null) qsImg.setPadding(0, 0, 0, 20);
}
}
notificationContainer.removeView(qsContainer);
qsScroll.addView(qsContainer);
notificationContainer.addView(qsScroll, 0);
}
}
}
});
}
public static void execHook_InvisiNotify(final InitPackageResourcesParam resparam, final int transparency) {
resparam.res.hookLayout("com.android.systemui", "layout", "super_status_bar", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
View bg = liparam.view.findViewById(resparam.res.getIdentifier("notification_panel", "id", "com.android.systemui"));
bg.getBackground().setAlpha(transparency);
}
});
resparam.res.hookLayout("com.android.systemui", "layout", "super_status_bar", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
}
});
}
public static void execHook_AospRecent(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.StatusBarFlag", lpparam.classLoader, "isHtcStyleRecentApp", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(false);
}
});
//Fix for FC on Sense 5.5
if (XMain.senseVersion.compareTo(new Version("5.5")) >= 0) {
findAndHookMethod("com.android.systemui.recent.RecentsActivity", lpparam.classLoader, "onCreate", Bundle.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
BroadcastReceiver mIntentReceiver = (BroadcastReceiver) getObjectField(param.thisObject, "mIntentReceiver");
IntentFilter mIntentFilter = (IntentFilter) getObjectField(param.thisObject, "mIntentFilter");
Activity thisActivity = (Activity) param.thisObject;
if (thisActivity != null && mIntentReceiver != null && mIntentFilter != null) {
try {
thisActivity.unregisterReceiver(mIntentReceiver);
} catch (Throwable t) {}
thisActivity.registerReceiver(mIntentReceiver, mIntentFilter);
}
}
});
}
}
public static void execHook_CenterClockLayout(final InitPackageResourcesParam resparam) {
resparam.res.hookLayout("com.android.systemui", "layout", "super_status_bar", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
FrameLayout statusBar = (FrameLayout) liparam.view.findViewById(resparam.res.getIdentifier("status_bar", "id", "com.android.systemui"));
TextView clock = (TextView) liparam.view.findViewById(resparam.res.getIdentifier("clock", "id", "com.android.systemui"));
LinearLayout systemIconArea = (LinearLayout) liparam.view.findViewById(resparam.res.getIdentifier("system_icon_area", "id", "com.android.systemui"));
LinearLayout statusBarContents = (LinearLayout) liparam.view.findViewById(resparam.res.getIdentifier("status_bar_contents", "id", "com.android.systemui"));
if(statusBar != null && clock != null && systemIconArea != null && statusBarContents != null)
{
clock.setGravity(Gravity.CENTER);
clock.setPadding(0, 0, 0, 0);
LinearLayout clockContainer = new LinearLayout(clock.getContext());
clockContainer.setOrientation(LinearLayout.HORIZONTAL);
clockContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
clockContainer.setGravity(Gravity.CENTER);
clockContainer.setTag("centerClock");
clockContainer.setPadding(0, 0, 0, 0);
systemIconArea.removeView(clock);
clockContainer.addView(clock);
statusBar.addView(clockContainer);
LinearLayout fillView = new LinearLayout(clock.getContext());
fillView.setOrientation(LinearLayout.HORIZONTAL);
fillView.setLayoutParams(new LayoutParams(500, LayoutParams.MATCH_PARENT));
fillView.setId(0x999999);
statusBarContents.addView(fillView, statusBarContents.indexOfChild(systemIconArea));
}else
{
XposedBridge.log("[S5T] Center Clock Error: One or more layouts or views not found");
}
}
});
}
/**
* Updates the fillView to make the notification icons move to the left
* @param viewToUpdate 0 = iconMerger; 1 = signalClusterView
* @param param params of the hooked method
*/
private static void updateFillView(int viewToUpdate, MethodHookParam param)
{
//iconMerger needs to be retrieved, where we can use the current object for signal cluster
LinearLayout startView = (LinearLayout) ((viewToUpdate == 0) ? getObjectField(param.thisObject, "mNotificationIcons") : param.thisObject);
if (startView != null)
{
//signal cluster is one step deeper in the view hierarchy...
FrameLayout statusBar = (viewToUpdate == 0) ? ((FrameLayout)startView.getParent().getParent().getParent()) : ((FrameLayout)startView.getParent().getParent().getParent().getParent());
if(statusBar != null)
{
LinearLayout systemIconArea = (LinearLayout) statusBar.findViewById(statusBar.getResources().getIdentifier("system_icon_area", "id", "com.android.systemui"));
if(systemIconArea != null)
{
LinearLayout fillView = (LinearLayout) statusBar.findViewById(0x999999);
if(fillView != null)
{
TextView clock = (TextView) statusBar.findViewById(statusBar.getResources().getIdentifier("clock", "id", "com.android.systemui"));
if(clock != null)
{
int systemIconAreaLeft = systemIconArea.getLeft();
int clockContainerLeft = clock.getLeft();
LayoutParams fillViewParams = fillView.getLayoutParams();
fillViewParams.width = systemIconAreaLeft - clockContainerLeft;
fillView.setLayoutParams(fillViewParams);
fillView.invalidate();
}else XposedBridge.log("clockContainer = null");
}else XposedBridge.log("fillView = null");
}else XposedBridge.log("systemIconArea = null");
}else XposedBridge.log("statusBar = null");
}else XposedBridge.log("startView = null");
}
public static void execHook_CenterClockAnimation(LoadPackageParam lpparam) {
//Listen for icon changes and update the width of the fill view
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "updateNotificationIcons", new XC_MethodHook(){
@Override
protected void beforeHookedMethod(MethodHookParam param)
{
updateFillView(0, param);
}
});
findAndHookMethod("com.android.systemui.statusbar.HtcGenericSignalClusterView", lpparam.classLoader, "apply", new XC_MethodHook(){
@Override
protected void beforeHookedMethod(MethodHookParam param)
{
updateFillView(1, param);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "updateResources", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
updateFillView(0, param);
}
});
try {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "refreshAllIconsForLayout", LinearLayout.class, new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
updateFillView(0, param);
}
});
} catch (Throwable t) {
}
//Helper class to hold needed variables for later methods (because nested methods and final and blah blah... Couldn't think of a better solution)
class Stuff{
Object statusbar;
Context ctx;
Resources res;
int animOut;
int animIn;
int animFade;
LinearLayout clock_container;
}
final Stuff stuff = new Stuff();
//Get what we need
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
stuff.statusbar = param.thisObject;
stuff.ctx = (Context)getObjectField(stuff.statusbar, "mContext");
stuff.res = stuff.ctx.getResources();
stuff.animFade = stuff.res.getIdentifier("fade_in", "anim", "android");
stuff.animIn = stuff.res.getIdentifier("push_down_in", "anim", "android");
stuff.animOut = stuff.res.getIdentifier("push_up_out", "anim", "android");
stuff.clock_container = (LinearLayout) ((FrameLayout) getObjectField(stuff.statusbar, "mStatusBarView")).findViewWithTag("centerClock");
}
});
//And now the 3 Ticker hooks
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar$MyTicker", lpparam.classLoader, "tickerStarting", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
stuff.clock_container.setVisibility(View.GONE);
Animation ani = (Animation) callMethod(stuff.statusbar, "loadAnim", stuff.animOut, null);
stuff.clock_container.startAnimation(ani);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar$MyTicker", lpparam.classLoader, "tickerDone", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
stuff.clock_container.setVisibility(View.VISIBLE);
Animation ani = (Animation) callMethod(stuff.statusbar, "loadAnim", stuff.animIn, null);
stuff.clock_container.startAnimation(ani);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar$MyTicker", lpparam.classLoader, "tickerHalting", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
stuff.clock_container.setVisibility(View.VISIBLE);
Animation ani = (Animation) callMethod(stuff.statusbar, "loadAnim", stuff.animFade, null);
stuff.clock_container.startAnimation(ani);
}
});
}
public static void execHook_removeAMPM(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.policy.Clock", lpparam.classLoader, "updateClock", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
String newTime = ((TextView)param.thisObject).getText().toString().replaceAll("(?i)am|pm", "").trim();
((TextView)param.thisObject).setText(newTime);
}
});
}
public static void execHook_ClockRemove(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "showClock", boolean.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
if ((Boolean)param.args[0]) param.setResult(null);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "updateClockTime", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
ArrayList<?> mClockSet = (ArrayList<?>)XposedHelpers.getObjectField(param.thisObject, "mClockSet");
if (mClockSet != null && mClockSet.size() > 0) ((TextView)mClockSet.get(0)).setVisibility(8);
}
});
}
public static void execHook_BrightnessSlider(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param)
{
final XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
FrameLayout mStatusBarWindow = (FrameLayout) getObjectField(param.thisObject, "mStatusBarWindow");
LinearLayout panel = (LinearLayout) mStatusBarWindow.findViewById(mStatusBarWindow.getResources().getIdentifier("panel", "id", "com.android.systemui"));
//Inflate the slider layout
LayoutInflater inflater = LayoutInflater.from(panel.getContext());
LinearLayout sliderConatiner = new LinearLayout(panel.getContext());
sliderConatiner = (LinearLayout) inflater.inflate(modRes.getLayout(R.layout.brightness_slider), panel, false);
sliderConatiner.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
v.performClick();
return true;
}
});
TextView autoText = (TextView) sliderConatiner.findViewById(R.id.autoText);
final HtcCheckBox cb = (HtcCheckBox) sliderConatiner.findViewById(R.id.autoCheckBox);
autoText.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
cb.toggle(); //Make it easier to toggle the checkbox. Way harder to hit it without that...
}
});
autoText.setText(Helpers.xl10n(modRes, R.string.systemui_brightslide_auto));
panel.addView(sliderConatiner, 1);
final HtcSeekBar seekBar = (HtcSeekBar) mStatusBarWindow.findViewWithTag("sliderSeekBar");
final HtcCheckBox checkBox = (HtcCheckBox) mStatusBarWindow.findViewById(R.id.autoCheckBox);
final ContentResolver cr = mStatusBarWindow.getContext().getContentResolver();
try {
seekBar.setProgress(android.provider.Settings.System.getInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS) - 30);
checkBox.setChecked(android.provider.Settings.System.getInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE) == 0 ? false : true);
seekBar.setEnabled(android.provider.Settings.System.getInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE) == 0 ? true : false);
seekBar.setDisplayMode(1); //Seekbar black BG
} catch (SettingNotFoundException e) {
//No brightness setting?
}
seekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
seekBar.setPressed(false);
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS, seekBar.getProgress() + 30);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
seekBar.setPressed(true);
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) try {
Object pwrmgr = seekBar.getContext().getSystemService(Context.POWER_SERVICE);
XposedHelpers.callMethod(pwrmgr, "setBacklightBrightness", progress + 30);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
checkBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(HtcCompoundButton arg0, boolean arg1) {
try{
if(arg1)
{
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE, 1);
seekBar.setProgress(android.provider.Settings.System.getInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS) - 30);
seekBar.setEnabled(false);
}else
{
android.provider.Settings.System.putInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE, 0);
seekBar.setProgress(android.provider.Settings.System.getInt(cr, android.provider.Settings.System.SCREEN_BRIGHTNESS) - 30);
seekBar.setEnabled(true);
}
} catch (SettingNotFoundException e) {
//No brightness setting?
}
}
});
SettingsObserver so = new SettingsObserver(new Handler());
so.setup(checkBox, seekBar, cr);
cr.registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, so);
}
});
}
private static ConnectivityManager connectivityManager = null;
private static TextView dataRateVal = null;
private static TextView dataRateUnits = null;
private static Handler mHandler = null;
private static Runnable mRunnable = null;
private static long bytesTotal = 0;
@SuppressLint("DefaultLocale")
private static ArrayList<String> humanReadableByteCount(long bytes) {
ArrayList<String> out = new ArrayList<String>();
if (bytes < 1024) {
out.add(String.valueOf(bytes));
out.add("B/s");
return out;
}
int exp = (int) (Math.log(bytes) / Math.log(1024));
char pre = "KMGTPE".charAt(exp-1);
out.add(String.format("%.1f", bytes / Math.pow(1024, exp)));
out.add(String.format("%sB/s", pre));
return out;
}
private static BroadcastReceiver connectChanged = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
try {
if (mRunnable == null || mHandler == null) return;
String action = intent.getAction();
if (action.equals("android.net.conn.CONNECTIVITY_CHANGE")) {
connectivityManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo ni = connectivityManager.getActiveNetworkInfo();
mHandler.removeCallbacks(mRunnable);
if (ni != null && ni.getState() == NetworkInfo.State.CONNECTED) {
mHandler.post(mRunnable);
} else if (dataRateVal != null && dataRateUnits != null) {
dataRateVal.setVisibility(8);
dataRateUnits.setVisibility(8);
}
}
} catch(Throwable t) {
XposedBridge.log(t);
}
}
};
public static void execHook_DataRateStatus(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook(){
@Override
protected void afterHookedMethod(MethodHookParam param) {
if (dataRateVal != null && dataRateUnits != null) return;
try {
Context mContext = (Context)getObjectField(param.thisObject, "mContext");
connectivityManager = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
FrameLayout mStatusBarView = (FrameLayout)getObjectField(param.thisObject, "mStatusBarView");
LinearLayout systemIconArea = (LinearLayout)mStatusBarView.findViewById(mStatusBarView.getResources().getIdentifier("system_icon_area", "id", "com.android.systemui"));
LinearLayout textFrame = new LinearLayout(mContext);
textFrame.setOrientation(LinearLayout.VERTICAL);
textFrame.setGravity(Gravity.CENTER_HORIZONTAL);
textFrame.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT));
dataRateVal = new TextView(mContext);
dataRateVal.setVisibility(8);
dataRateVal.setTransformationMethod(SingleLineTransformationMethod.getInstance());
dataRateVal.setEllipsize(null);
dataRateVal.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
dataRateVal.setTextColor(Color.WHITE);
dataRateVal.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
dataRateVal.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13.0f);
dataRateVal.setIncludeFontPadding(false);
dataRateVal.setPadding(0, 1, 5, 0);
dataRateVal.setLineSpacing(0, 0.9f);
//dataRateVal.setTypeface(null, Typeface.BOLD);
dataRateUnits = new TextView(mContext);
dataRateUnits.setVisibility(8);
dataRateUnits.setTransformationMethod(SingleLineTransformationMethod.getInstance());
dataRateUnits.setEllipsize(null);
dataRateUnits.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
dataRateUnits.setTextColor(Color.WHITE);
dataRateUnits.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
dataRateUnits.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 10.0f);
dataRateUnits.setIncludeFontPadding(false);
dataRateUnits.setPadding(0, 0, 5, 1);
dataRateUnits.setScaleY(0.9f);
textFrame.addView(dataRateVal, 0);
textFrame.addView(dataRateUnits, 1);
systemIconArea.addView(textFrame, 0);
mHandler = new Handler();
mRunnable = new Runnable() {
public void run() {
try {
boolean isConnected = false;
if (connectivityManager != null && dataRateVal != null && dataRateUnits != null) {
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
if (activeNetworkInfo != null)
if (activeNetworkInfo.isConnected()) isConnected = true;
if (isConnected) {
long rxBytes = TrafficStats.getTotalRxBytes();
long txBytes = TrafficStats.getTotalTxBytes();
long newBytes = 0;
if (rxBytes != -1L && txBytes != -1L) newBytes = rxBytes + txBytes;
long newBytesFixed = newBytes - bytesTotal;
if (newBytesFixed < 0 || bytesTotal == 0) newBytesFixed = 0;
long speed = Math.round(newBytesFixed/2);
bytesTotal = newBytes;
ArrayList<String> spd = humanReadableByteCount(speed);
dataRateVal.setText(spd.get(0));
dataRateUnits.setText(spd.get(1));
if (XMain.pref.getBoolean("pref_key_cb_texts", false)) {
int themeColor = StatusbarMods.getThemeColor();
dataRateVal.setTextColor(themeColor);
dataRateUnits.setTextColor(themeColor);
}
if (speed == 0) {
dataRateVal.setAlpha(0.3f);
dataRateUnits.setAlpha(0.3f);
} else {
dataRateVal.setAlpha(1.0f);
dataRateUnits.setAlpha(1.0f);
}
dataRateVal.setVisibility(0);
dataRateUnits.setVisibility(0);
} else {
dataRateVal.setVisibility(8);
dataRateUnits.setVisibility(8);
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
if (mHandler != null)
mHandler.postDelayed(mRunnable, 2000L);
}
};
IntentFilter intentfilter = new IntentFilter();
intentfilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
mContext.registerReceiver(connectChanged, intentfilter);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
}
//Need this to listen for settings changes
protected static class SettingsObserver extends ContentObserver {
private HtcCheckBox cb = null;
private HtcSeekBar sb = null;
private ContentResolver cr;
public SettingsObserver(Handler handler) {
super(handler);
}
public void setup(HtcCheckBox cb, HtcSeekBar sb, ContentResolver cr) {
this.cb = cb;
this.sb = sb;
this.cr = cr;
}
@Override
public void onChange(boolean selfChange) {
this.onChange(selfChange, null);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (!this.sb.isPressed()) try {
this.cb.setChecked(android.provider.Settings.System.getInt(this.cr, android.provider.Settings.System.SCREEN_BRIGHTNESS_MODE) == 0 ? false : true);
this.sb.setProgress(android.provider.Settings.System.getInt(this.cr, android.provider.Settings.System.SCREEN_BRIGHTNESS) - 30);
} catch (SettingNotFoundException e) {
//No brightness setting?
}
}
}
/*
public static void execHook_DisableEQS(final InitPackageResourcesParam resparam) {
resparam.res.setReplacement("com.android.systemui", "bool", "config_hasSettingsPanel", false);
resparam.res.setReplacement("com.android.systemui", "bool", "config_hasFlipSettingsPanel", false);
}
*/
public static void execHook_DisableEQS(final LoadPackageParam lpparam) {
XposedBridge.hookAllConstructors(findClass("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
View.OnClickListener newButtonOnClick = new View.OnClickListener() {
public void onClick(View view) {
XposedHelpers.callMethod(param.thisObject, "startActivityDismissingKeyguard", new Intent("android.settings.SETTINGS"), true);
return;
}
};
XposedHelpers.findField(param.thisObject.getClass(), "mSettingsButtonListener").set(param.thisObject, newButtonOnClick);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
ImageView mSettingsButton = (ImageView)XposedHelpers.findField(param.thisObject.getClass(), "mSettingsButton").get(param.thisObject);
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
mSettingsButton.setImageDrawable(modRes.getDrawable(R.drawable.ic_sysbar_quicksettings));
}
});
}
//hEQS LongClickListeners
public static void execHook_hEQSLongClick(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.QuickSettingsTileView", lpparam.classLoader, "onAttachedToWindow", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
final LinearLayout thisTile = (LinearLayout) param.thisObject;
thisTile.setLongClickable(true);
thisTile.setOnLongClickListener(new OnLongClickListener() {
@Override
@SuppressLint("DefaultLocale")
public boolean onLongClick(View v) {
String clickedTile = (String) getObjectField(thisTile, "tileLabel");
if (!clickedTile.equals("") && !(clickedTile == null))
{
String intentPkg = "";
String intentClass = "";
Intent settingIntent = null;
if (clickedTile.equals("apn")) {intentPkg = "com.android.settings"; intentClass = "com.android.settings.CdmaApnSettings";}
if (clickedTile.equals("auto_sync")) {intentClass = "android.settings.SYNC_SETTINGS";}
if (clickedTile.equals("bluetooth")) {intentClass = "android.settings.BLUETOOTH_SETTINGS";}
if (clickedTile.equals("brightness")) {settingIntent = new Intent("android.settings.DISPLAY_SETTINGS"); settingIntent.putExtra(":android:show_preference", "brightness");}
if (clickedTile.equals("do_not_disturb")) {intentClass = "com.htc.settings.DND_SETTINGS";}
if (clickedTile.equals("gps")) {intentClass = "android.settings.LOCATION_SOURCE_SETTINGS";}
if (clickedTile.equals("mobile_data")) {intentPkg = "com.android.phone"; intentClass = "com.android.phone.MobileNetworkSettings";}
if (clickedTile.equals("power_saver")) {intentPkg = "com.htc.htcpowermanager"; intentClass = "com.htc.htcpowermanager.powersaver.PowerSaverActivity";}
if (clickedTile.equals("screenshot")) {
int mBucketId = -1;
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Screenshots");
if (file != null)
{
mBucketId = file.getAbsolutePath().toLowerCase().hashCode();
}
settingIntent = new Intent("com.htc.album.action.VIEW_FOLDER_IN_THUMBNAIL");
settingIntent.putExtra("folder_type", (new StringBuilder()).append("collection_regular_bucket ").append(mBucketId).append(" Screenshots").toString());
settingIntent.putExtra("entry_from", "Screenshots");
settingIntent.setDataAndType(null, "image/*");
settingIntent.setFlags(0x14000000);
}
if (clickedTile.equals("wifi")) {intentClass = "android.settings.WIFI_SETTINGS";}
if (clickedTile.equals("wifi_hotspot")) {intentPkg = "com.htc.WifiRouter"; intentClass = "com.htc.WifiRouter.WifiRouter";}
Object viewTag = thisTile.getTag();
if (viewTag != null)
{
if (!intentPkg.equals(""))
callMethod(viewTag, "startSettingsActivity", intentPkg, intentClass);
else if (!(settingIntent == null))
callMethod(viewTag, "startSettingsActivity", settingIntent);
else
callMethod(viewTag, "startSettingsActivity", intentClass);
}
}
return true;
}
});
}
});
}
// Pinch to clear all recent apps
public static void execHook_RecentAppsInit(final LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.systemui.recent.RecentAppFxActivity", lpparam.classLoader, "onCreate", "android.os.Bundle", new XC_MethodHook(){
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
final GridView recentGridView = (GridView)XposedHelpers.findField(param.thisObject.getClass(), "mRecentGridView").get(param.thisObject);
killedEmAll = false;
gridViewObject = param.thisObject;
gridViewContext = recentGridView.getContext();
gridViewSelf = recentGridView;
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_RecentAppsClearTouch(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.recent.RecentsGridView", lpparam.classLoader, "onTouchEvent", MotionEvent.class, new TouchListenerOnTouch());
findAndHookMethod("com.android.systemui.recent.RecentsGridView", lpparam.classLoader, "onInterceptTouchEvent", MotionEvent.class, new TouchListenerOnTouchIntercept());
}
private static GridView gridViewSelf;
private static Object gridViewObject;
private static Context gridViewContext;
private static ActivityManager am;
private static ScaleGestureDetector mScaleDetector;
private static GestureDetector mDetector;
static boolean killedEmAll = false;
// Exterminate! - Daleks
private static void terminateAll(int animType) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException {
terminateAll(animType, null);
}
private static void terminateAll(int animType, final ViewGroup currApp) throws InvocationTargetException, IllegalArgumentException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException {
ArrayList<?> taskDescriptionsArray = (ArrayList<?>)XposedHelpers.getObjectField(gridViewObject, "mRecentTaskDescriptions");
if ((taskDescriptionsArray == null) || (taskDescriptionsArray.size() == 0)) {
// Recent array is empty, resuming last activity
closeRecents();
return;
}
int i = gridViewSelf.getChildCount();
int j = taskDescriptionsArray.size();
int cnt = 0;
// Go through all GridView items and get taskIds
while (cnt < i) {
View gridViewItem;
gridViewItem = gridViewSelf.getChildAt(cnt);
if (gridViewItem != null && !gridViewItem.equals(currApp)) {
Object gridViewItemTag = XposedHelpers.getObjectField(gridViewItem.getTag(), "td");
if (gridViewItemTag != null) {
// Recreate RecentAppFxActivity.handleSwipe() using hooked methods
int m = j - taskDescriptionsArray.indexOf(gridViewItemTag) - 1;
taskDescriptionsArray.remove(gridViewItemTag);
if (m != 0) try {
XposedHelpers.callMethod(gridViewSelf, "setDelPositionsList", Integer.valueOf(m));
} catch (Exception e) {}
if (am == null)
am = ((ActivityManager)gridViewContext.getSystemService("activity"));
if (am != null)
XposedHelpers.callMethod(am, "removeTask", XposedHelpers.getIntField(gridViewItemTag, "persistentTaskId"), Integer.valueOf(1));
gridViewItem.startAnimation(terminateAnimation(i, cnt, animType, currApp));
}
}
cnt++;
}
if (currApp != null) {
Handler handler = (Handler)XposedHelpers.getObjectField(gridViewObject, "handler");
Runnable runnable = new Runnable() {
public void run() {
XposedHelpers.callMethod(gridViewObject, "handleOnClick", currApp);
}
};
handler.postDelayed(runnable, 550l + (i - 1) * 50l);
}
}
// Shrink to center and fade out animations
private static Animation terminateAnimation(final int i, int cnt, int animType, final ViewGroup currApp) {
if (gridViewContext == null) return null;
Animation fadeOut = AnimationUtils.loadAnimation(gridViewContext, android.R.anim.fade_out);
AnimationSet localAnimationSet = new AnimationSet(true);
if (animType == 0)
{
fadeOut.setDuration(300l);
fadeOut.setStartOffset((i - cnt) * 70);
fadeOut.setInterpolator(AnimationUtils.loadInterpolator(gridViewContext, android.R.anim.linear_interpolator));
TranslateAnimation drop = new TranslateAnimation(0.0F, 0.0F, 0.0F, 300.0f);
drop.setDuration(500l);
drop.setStartOffset((i - cnt) * 70);
drop.setInterpolator(AnimationUtils.loadInterpolator(gridViewContext, android.R.anim.linear_interpolator));
localAnimationSet.addAnimation(drop);
} else {
fadeOut.setDuration(500l);
fadeOut.setStartOffset(cnt * 50);
fadeOut.setInterpolator(AnimationUtils.loadInterpolator(gridViewContext, android.R.anim.accelerate_interpolator));
ScaleAnimation shrink = new ScaleAnimation(1f, 0.2f, 1f, 0.2f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
shrink.setDuration(500l);
shrink.setStartOffset(cnt * 50);
shrink.setInterpolator(AnimationUtils.loadInterpolator(gridViewContext, android.R.anim.accelerate_decelerate_interpolator));
localAnimationSet.addAnimation(shrink);
}
localAnimationSet.addAnimation(fadeOut);
localAnimationSet.setFillAfter(true);
if (cnt == i - 1)
localAnimationSet.setAnimationListener(new Animation.AnimationListener() {
public void onAnimationEnd(Animation paramAnonymousAnimation) {
new Thread(new Runnable() {
@Override
public void run() {
try { if (i > 3) Thread.sleep((i + 1) * 15); } catch (Exception e) {}
if (currApp == null) closeRecents();
}
}).start();
}
public void onAnimationRepeat(Animation paramAnonymousAnimation) {}
public void onAnimationStart(Animation paramAnonymousAnimation) {}
});
return localAnimationSet;
}
// Listener for scale gestures
private static class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
killedEmAll = true;
try {
terminateAll(1);
} catch (Throwable t) {
XposedBridge.log(t);
}
return true;
}
}
// Listener for swipe gestures
private static class SwipeListener extends GestureDetector.SimpleOnGestureListener {
// For HTC One
private int SWIPE_MIN_DISTANCE = 120;
private int SWIPE_MAX_OFF_PATH = 250;
private int SWIPE_THRESHOLD_VELOCITY = 200;
final Context helperContext;
public SwipeListener(Context context) {
helperContext = context;
float density = helperContext.getResources().getDisplayMetrics().density;
SWIPE_MIN_DISTANCE = Math.round(40 * density);
SWIPE_MAX_OFF_PATH = Math.round(85 * density);
SWIPE_THRESHOLD_VELOCITY = Math.round(66 * density);
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH) return false;
if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE && Math.abs(velocityY) > SWIPE_THRESHOLD_VELOCITY) {
killedEmAll = true;
terminateAll(0);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
return false;
}
}
private static void initDetectors(MethodHookParam param) throws Throwable {
final GridView recentGridView = (GridView)param.thisObject;
if (mScaleDetector == null) mScaleDetector = new ScaleGestureDetector(recentGridView.getContext(), new ScaleListener());
if (mDetector == null) mDetector = new GestureDetector(recentGridView.getContext(), new SwipeListener((recentGridView.getContext())));
}
// Detect second finger and cancel action if some app thumbnail was pressed
private static class TouchListenerOnTouchIntercept extends XC_MethodHook {
MotionEvent ev = null;
@Override
protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
initDetectors(param);
ev = (MotionEvent)param.args[0];
if (ev == null) return;
mScaleDetector.onTouchEvent(ev);
mDetector.onTouchEvent(ev);
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: {
}
case MotionEvent.ACTION_POINTER_DOWN: {
if (ev.getPointerCount() == 2)
try {
param.setResult(Boolean.valueOf(true));
} catch (Throwable thw) {
param.setThrowable(thw);
}
}
}
}
}
// Detect scale/swipe gestures
private static class TouchListenerOnTouch extends XC_MethodHook {
MotionEvent ev = null;
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
}
@Override
protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
if (killedEmAll == true) return;
initDetectors(param);
ev = (MotionEvent)param.args[0];
if (ev == null) return;
mScaleDetector.onTouchEvent(ev);
mDetector.onTouchEvent(ev);
}
}
// Close activity
private static void closeRecents() {
try {
if (gridViewObject != null) {
if (XposedHelpers.getObjectField(gridViewObject, "mFinished") != null)
XposedHelpers.setBooleanField(gridViewObject, "mFinished", Boolean.valueOf(true));
((Activity)gridViewObject).finish();
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
private static int[] toIntArray(List<Integer> list) {
int[] ret = new int[list.size()];
int i = 0;
for (Integer e : list) ret[i++] = e.intValue();
return ret;
}
private static List<ActivityManager.RunningAppProcessInfo> procs = null;
private static String ramTAG = "RAMView";
private static class getRAMView extends AsyncTask<MethodHookParam, Void, Void> {
ViewGroup theView = null;
TextView ramView = null;
String ramText = null;
@Override
protected Void doInBackground(final MethodHookParam... params) {
try {
final MethodHookParam param = params[0];
theView = (ViewGroup)param.getResult();
if (theView != null) {
int pos = (Integer)param.args[0];
Object viewholder = theView.getTag();
ArrayList<?> mRecentTaskDescriptions = (ArrayList<?>)XposedHelpers.getObjectField(XposedHelpers.getSurroundingThis(param.thisObject), "mRecentTaskDescriptions");
if (mRecentTaskDescriptions == null) return null;
int taskPos = mRecentTaskDescriptions.size() - pos - 1;
if (taskPos < 0) return null;
Object taskdescription = mRecentTaskDescriptions.get(taskPos);
if (taskdescription == null) return null;
ResolveInfo resolveInfo = (ResolveInfo)XposedHelpers.getObjectField(taskdescription, "resolveInfo");
final ActivityManager am = (ActivityManager)theView.getContext().getSystemService(Context.ACTIVITY_SERVICE);
if (pos == 0 || procs == null) procs = am.getRunningAppProcesses();
final List<Integer> pids_mem = new ArrayList<Integer>();
for (ActivityManager.RunningAppProcessInfo process: procs)
if (process.processName.equals(resolveInfo.activityInfo.processName))
if (!pids_mem.contains(process.pid)) pids_mem.add(process.pid);
MemoryInfo[] mi = am.getProcessMemoryInfo(toIntArray(pids_mem));
int memTotal = 0;
for (MemoryInfo memInfo: mi)
memTotal += memInfo.getTotalPss();
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
ramText = String.format("%.1f", (float)(memTotal / 1024.0f)) + Helpers.xl10n(modRes, R.string.ram_mb);
if (theView.findViewWithTag(ramTAG) == null) {
ramView = new TextView(theView.getContext());
ramView.setTag(ramTAG);
ramView.setText(ramText);
final TextView text1 = (TextView)XposedHelpers.getObjectField(viewholder, "text1");
ramView.setTextSize(TypedValue.COMPLEX_UNIT_PX, text1.getTextSize());
ramView.setEllipsize(TruncateAt.END);
ramView.setSingleLine();
ramView.setTypeface(text1.getTypeface());
ramView.setTextColor(Color.argb(127, Color.red(text1.getCurrentTextColor()), Color.green(text1.getCurrentTextColor()), Color.blue(text1.getCurrentTextColor())));
if (XMain.senseVersion.compareTo(new Version("5.5")) == -1) {
RelativeLayout.LayoutParams p0 = (RelativeLayout.LayoutParams)text1.getLayoutParams();
ImageView img = (ImageView)XposedHelpers.getObjectField(viewholder, "img");
p0.setMargins(img.getPaddingLeft(), p0.topMargin, img.getPaddingRight(), 0);
ramView.setLayoutParams(p0);
ramView.setGravity(Gravity.CENTER);
ramView.setBackground(new ColorDrawable(Color.parseColor("#9F333333")));
ramView.setTranslationY(-32f * theView.getContext().getResources().getDisplayMetrics().density);
} else {
FrameLayout.LayoutParams p0 = (FrameLayout.LayoutParams)text1.getLayoutParams();
ramView.setLayoutParams(p0);
ramView.setGravity(Gravity.CENTER_VERTICAL);
ramView.setBackground(text1.getBackground());
ramView.setPadding(text1.getPaddingLeft(), text1.getPaddingTop(), text1.getPaddingRight(), text1.getPaddingBottom());
ramView.setTranslationY(-29.7f * theView.getContext().getResources().getDisplayMetrics().density);
}
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
return null;
}
@Override
protected void onPostExecute(Void result) {
if (theView != null)
if (theView.findViewWithTag(ramTAG) == null) {
if (ramView != null) theView.addView(ramView);
} else {
if (ramText != null)
((TextView)theView.findViewWithTag(ramTAG)).setText(ramText);
}
}
}
public static void execHook_RAMInRecents(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.recent.RecentAppFxActivity.RecentGridViewAdapter", lpparam.classLoader, "getView", int.class, View.class, ViewGroup.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
// Text before actual data is available
ViewGroup theView = (ViewGroup)param.getResult();
if (theView != null && theView.findViewWithTag(ramTAG) != null)
((TextView)theView.findViewWithTag(ramTAG)).setText("...");
// Get RAM usage for the task of this view
new getRAMView().execute(param);
}
});
}
static HtcPopupWindow popup = null;
public static void execHook_RecentsLongTap(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.recent.RecentAppFxActivity.RecentGridViewAdapter", lpparam.classLoader, "getView", int.class, View.class, ViewGroup.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
final ViewGroup theView = (ViewGroup)param.getResult();
if (theView != null) {
theView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
Activity FxRecent = (Activity)XposedHelpers.getSurroundingThis(param.thisObject);
popup = new HtcPopupWindow(FxRecent);
float density = theView.getContext().getResources().getDisplayMetrics().density;
int theWidth = Math.round(theView.getContext().getResources().getDisplayMetrics().widthPixels / 3 + 30 * density);
popup.setWidth(theWidth);
popup.setHeight(-2);
popup.setTouchable(true);
popup.setFocusable(true);
popup.setOutsideTouchable(true);
ListView options = new ListView(FxRecent);
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
ListAdapter listAdapter = new PopupAdapter(options.getContext(), Helpers.xl10n_array(modRes, R.array.recents_menu), true);
options.setAdapter(listAdapter);
options.setFocusableInTouchMode(true);
options.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
popup.dismiss();
Object viewholder = theView.getTag();
Object taskdescription = XposedHelpers.getObjectField(viewholder, "td");
String packageName = (String)XposedHelpers.getObjectField(taskdescription, "packageName");
if (position == 0) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", packageName, null));
intent.setComponent(intent.resolveActivity(view.getContext().getPackageManager()));
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
view.getContext().startActivity(intent);
} else if (position == 1) {
try {
theView.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + packageName)));
} catch (android.content.ActivityNotFoundException anfe) {
theView.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + packageName)));
}
} else if (position == 2) {
XposedHelpers.callMethod(XposedHelpers.getSurroundingThis(param.thisObject), "handleSwipe", theView);
} else {
try {
terminateAll(1, theView);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
});
popup.setContentView(options);
Object mRecentGridView = XposedHelpers.getObjectField(XposedHelpers.getSurroundingThis(param.thisObject), "mRecentGridView");
XposedHelpers.setBooleanField(mRecentGridView, "isDragging", true);
popup.showAtLocation(theView, Gravity.TOP|Gravity.START, Math.round(theView.getX() - theWidth/4), Math.round(theView.getY() - 20 * density));
return true;
} catch (Exception e) {
return false;
}
}
});
}
}
});
findAndHookMethod("com.android.systemui.recent.RecentAppFxActivity", lpparam.classLoader, "handleSwipe", View.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
Activity FxRecent = (Activity)param.thisObject;
if (FxRecent != null && !FxRecent.isFinishing() && popup != null && popup.isShowing()) try { popup.dismiss(); } catch (Throwable t) {}
}
});
}
private static Thread cpuThread = null;
private static boolean isThreadActive = false;
private static long workLast, totalLast, workC, totalC = 0;
private static int curFreq;
private static String curTemp;
private static void readCPU() {
BufferedReader readStream;
String[] a;
long work, total;
try {
readStream = new BufferedReader(new FileReader("/proc/stat"));
a = readStream.readLine().split("[ ]+", 9);
work = Long.parseLong(a[1]) + Long.parseLong(a[2]) + Long.parseLong(a[3]);
total = work + Long.parseLong(a[4]) + Long.parseLong(a[5]) + Long.parseLong(a[6]) + Long.parseLong(a[7]);
if (totalLast != 0) {
workC = work - workLast;
totalC = total - totalLast;
}
workLast = work;
totalLast = total;
readStream.close();
readStream = new BufferedReader(new FileReader("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"));
curFreq = Math.round((Integer.valueOf(readStream.readLine()) / 1000));
readStream.close();
readStream = new BufferedReader(new FileReader("/sys/class/thermal/thermal_zone0/temp"));
curTemp = readStream.readLine().trim();
int curTempInt = Integer.parseInt(curTemp);
if (curTempInt >= 1000) curTemp = String.valueOf(Math.round(curTempInt / 1000));
readStream.close();
} catch (Throwable t) {
t.printStackTrace();
}
}
public static void execHook_NotifDrawerHeaderSysInfo(final LoadPackageParam lpparam) {
XposedBridge.hookAllConstructors(findClass("com.android.systemui.statusbar.policy.DateView", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
final TextView date = (TextView)param.thisObject;
OnClickListener ocl = new OnClickListener() {
@Override
public void onClick(View v) {
if (cpuThread != null && cpuThread.isAlive()) {
Thread tmpThread = cpuThread;
cpuThread = null;
tmpThread.interrupt();
isThreadActive = false;
XposedHelpers.callMethod(param.thisObject, "updateClock");
} else {
cpuThread = new Thread(new Runnable() {
public void run() {
try {
while (Thread.currentThread() == cpuThread) {
readCPU();
date.getHandler().post(new Runnable() {
@Override
public void run() {
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
ActivityManager activityManager = (ActivityManager)date.getContext().getSystemService(Context.ACTIVITY_SERVICE);
activityManager.getMemoryInfo(mi);
long availableMegs = mi.availMem / 1048576L;
long totalMegs = mi.totalMem / 1048576L;
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
String MB = Helpers.xl10n(modRes, R.string.ram_mb);
String MHz = Helpers.xl10n(modRes, R.string.cpu_mhz);
date.setText("CPU " + String.valueOf(Math.round(workC * 100 / (float)totalC)) + "% " + String.valueOf(curFreq) + MHz + " " + curTemp + "\u00B0C" + "\n" + "RAM " + String.valueOf(availableMegs) + MB + " / " + String.valueOf(totalMegs) + MB);
}
});
Thread.sleep(1000);
}
} catch (Throwable t) {}
}
});
cpuThread.start();
isThreadActive = true;
}
}
};
date.setOnClickListener(ocl);
}
});
findAndHookMethod("com.android.systemui.statusbar.policy.DateView", lpparam.classLoader, "updateClock", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
if (isThreadActive) param.setResult(null);
}
});
}
public static void execHook_NotifDrawerHeaderClock(final InitPackageResourcesParam resparam, final int headerClock) {
resparam.res.hookLayout("com.android.systemui", "layout", "status_bar_expanded_header", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
View clock = liparam.view.findViewById(resparam.res.getIdentifier("clock", "id", "com.android.systemui"));
View date = liparam.view.findViewById(resparam.res.getIdentifier("date", "id", "com.android.systemui"));
final Intent clockIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
OnClickListener ocl = new OnClickListener() {
@Override
public void onClick(View v) {
try {
ComponentName cn = new ComponentName("com.htc.android.worldclock", "com.htc.android.worldclock.WorldClockTabControl");
clockIntent.setComponent(cn);
clockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
v.getContext().startActivity(clockIntent);
Object sbservice = v.getContext().getSystemService("statusbar");
Class<?> statusbarManager = Class.forName("android.app.StatusBarManager");
Method hidesb;
if (Build.VERSION.SDK_INT >= 17) {
hidesb = statusbarManager.getMethod("collapsePanels");
} else {
hidesb = statusbarManager.getMethod("collapse");
}
hidesb.setAccessible(true);
hidesb.invoke(sbservice);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
clock.setOnClickListener(ocl);
if (headerClock == 2) date.setOnClickListener(ocl);
}
});
}
// Listen for alarm changes and update label
static class SystemSettingsObserver extends ContentObserver {
Object thisObj = null;
public SystemSettingsObserver(Handler h, Object paramThisObject) {
super(h);
thisObj = paramThisObject;
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange);
try {
String uriPart = uri.getLastPathSegment();
if (uriPart != null && uriPart.equals(Settings.System.NEXT_ALARM_FORMATTED));
if (thisObj != null) XposedHelpers.callMethod(thisObj, "triggerUpdate");
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
private static void updateLabel(Object paramThisObject) {
try {
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
TextView mPlmnLabel = (TextView)XposedHelpers.getObjectField(paramThisObject, "mPlmnLabel");
TextView mSpnLabel = (TextView)XposedHelpers.getObjectField(paramThisObject, "mSpnLabel");
TextView mNetworkTextView = (TextView)XposedHelpers.getObjectField(paramThisObject, "mNetworkTextView");
if (mPlmnLabel != null) {
String txt = Helpers.getNextAlarm(mPlmnLabel.getContext());
if (XMain.pref_alarmnotify && txt != null && !txt.equals("")) mPlmnLabel.setText("");
}
if (mSpnLabel != null) {
String txt = Helpers.getNextAlarm(mSpnLabel.getContext());
if (XMain.pref_alarmnotify && txt != null && !txt.equals("")) mSpnLabel.setText(Helpers.xl10n(modRes, R.string.next_alarm) + ": " + txt);
else if (XMain.pref_signalnotify && !mSpnLabel.getText().toString().contains("dBm"))
mSpnLabel.setText(mSpnLabel.getText() + getCurrentSignalLevel(mSpnLabel.getContext()));
}
if (mNetworkTextView != null) {
String txt = Helpers.getNextAlarm(mNetworkTextView.getContext());
if (XMain.pref_alarmnotify && txt != null && !txt.equals("")) mNetworkTextView.setText(Helpers.xl10n(modRes, R.string.next_alarm) + ": " + txt);
else if (XMain.pref_signalnotify && !mNetworkTextView.getText().toString().contains("dBm"))
mNetworkTextView.setText(mNetworkTextView.getText() + getCurrentSignalLevel(mNetworkTextView.getContext()));
}
View vp = (View)((View)paramThisObject).getParent();
if (vp != null) vp.invalidate();
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_LabelsUpdate(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.CarrierLabel", lpparam.classLoader, "updateAirplaneMode", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
updateLabel(param.thisObject);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.CarrierLabel", lpparam.classLoader, "updateNetworkName", boolean.class, String.class, boolean.class, String.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
updateLabel(param.thisObject);
}
});
findAndHookMethod("com.android.systemui.statusbar.phone.CarrierLabel", lpparam.classLoader, "updateNetworkNameExt", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
updateLabel(param.thisObject);
}
});
}
public static void execHook_AlarmNotification(LoadPackageParam lpparam) {
XposedBridge.hookAllConstructors(findClass("com.android.systemui.statusbar.phone.CarrierLabel", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
try {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (mContext != null)
mContext.getContentResolver().registerContentObserver(android.provider.Settings.System.CONTENT_URI, true, new SystemSettingsObserver(new Handler(), param.thisObject));
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
}
public static class SignalListener extends PhoneStateListener {
Object thisObj = null;
public SignalListener(Object paramThisObject) {
super();
thisObj = paramThisObject;
}
public void onSignalStrengthsChanged (SignalStrength signalStrength) {
if (thisObj != null) {
lastSignalStrength = signalStrength;
XposedHelpers.callMethod(thisObj, "triggerUpdate");
}
}
}
private static SignalStrength lastSignalStrength = null;
private static String getCurrentSignalLevel(Context ctx) {
if (lastSignalStrength == null || Settings.Global.getInt(ctx.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0) {
lastSignalStrength = null;
return "";
}
TelephonyManager telMgr = (TelephonyManager)ctx.getSystemService(Context.TELEPHONY_SERVICE);
if (telMgr.getSimState() != TelephonyManager.SIM_STATE_READY) {
lastSignalStrength = null;
return "";
}
int asu = (Integer)XposedHelpers.callMethod(lastSignalStrength, "getAsuLevel");
int dBm = (Integer)XposedHelpers.callMethod(lastSignalStrength, "getDbm");
return " " + String.valueOf(dBm) + " dBm " + String.valueOf(asu) + " asu";
}
public static void execHook_SignalNotification(LoadPackageParam lpparam) {
XposedBridge.hookAllConstructors(findClass("com.android.systemui.statusbar.phone.CarrierLabel", lpparam.classLoader), new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
try {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
if (mContext != null) {
SignalListener signalListener = new SignalListener(param.thisObject);
TelephonyManager telephonyManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(signalListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
}
public static void execHookTSB442Fix(LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBarTransitions", lpparam.classLoader, "transitionTo", int.class, boolean.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[0] = 2;
}
});
} catch (Throwable ignore) {}
}
public static void execHook_anotherTSB44Fix(LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.internal.policy.impl.BarController", lpparam.classLoader, "applyTranslucentFlagLw", "android.view.WindowManagerPolicy.WindowState", int.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(final MethodHookParam param) throws Throwable {
Object win = param.args[0];
if (win != null && win.toString().contains("Keyguard"))
param.setResult(param.args[2]);
}
});
} catch (Throwable ignore) {}
}
//On 4.4.2 (and maybe 4.4 too) Assist is handled by SystemUI. Try to patch it, silently fail otherwise.
public static void execHook_OverrideAssist(LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "showSearchPanel", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
ControlsMods.assistAndSearchPanelOverride(param);
}
});
} catch (Throwable ignore) {}
}
public static void execHook_ChangeBrightnessQSTile(LoadPackageParam lpparam) {
try {
final Class<?> QSB = findClass("com.android.systemui.statusbar.quicksetting.QuickSettingBrightness", lpparam.classLoader);
XposedBridge.hookAllConstructors(QSB, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
int valnorm1 = Math.round(255 * XMain.pref.getInt("pref_key_sysui_brightqs_value1", 10) / 100 + 1); if (valnorm1 > 255) valnorm1 = 255;
int valnorm2 = Math.round(255 * XMain.pref.getInt("pref_key_sysui_brightqs_value2", 40) / 100 + 1); if (valnorm2 > 255) valnorm2 = 255;
int valnorm3 = Math.round(255 * XMain.pref.getInt("pref_key_sysui_brightqs_value3", 60) / 100 + 1); if (valnorm3 > 255) valnorm3 = 255;
int valnorm4 = Math.round(255 * XMain.pref.getInt("pref_key_sysui_brightqs_value4", 100) / 100 + 1); if (valnorm4 > 255) valnorm4 = 255;
XposedHelpers.setStaticObjectField(QSB, "BRIGHTNESS_LEVEL", new int[] { valnorm1, valnorm2, valnorm3, valnorm4 });
XposedHelpers.setStaticObjectField(QSB, "BRIGHTNESS_VALUE", new int[] { valnorm1, valnorm2, valnorm3, valnorm4 });
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
private static int numberToTimeout(int num) {
int timeout = 15000;
switch (num) {
case 0: timeout = 15000; break;
case 1: timeout = 30000; break;
case 2: timeout = 45000; break;
case 3: timeout = 60000; break;
case 4: timeout = 120000; break;
case 5: timeout = 600000; break;
case 6: timeout = 1800000; break;
case 7: timeout = 3600000; break;
}
return timeout;
}
public static void execHook_ChangeTimeoutQSTile(LoadPackageParam lpparam) {
try {
final Class<?> QST = findClass("com.android.systemui.statusbar.quicksetting.QuickSettingTimeout", lpparam.classLoader);
XposedBridge.hookAllConstructors(QST, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.setStaticObjectField(QST, "timeoutList", new int[] {
numberToTimeout(XMain.pref.getInt("pref_key_sysui_timeoutqs_value1", 7)),
numberToTimeout(XMain.pref.getInt("pref_key_sysui_timeoutqs_value2", 6)),
numberToTimeout(XMain.pref.getInt("pref_key_sysui_timeoutqs_value3", 4))
});
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
private static int getRotation(MethodHookParam param) {
Context ctx = ((View)param.thisObject).getContext();
WindowManager wm = (WindowManager)ctx.getSystemService(Context.WINDOW_SERVICE);
return wm.getDefaultDisplay().getRotation();
}
private static int getShortcutRes(int shortcut, boolean isLeft) {
int sRes = R.drawable.ic_action_apm;
if (isLeft) sRes = R.drawable.ic_action_voicedial;
switch (shortcut) {
case 1:
sRes = R.drawable.ic_action_apm;
break;
case 2:
sRes = R.drawable.ic_action_voicedial;
break;
case 4:
sRes = R.drawable.ic_action_sleep;
break;
case 5:
sRes = R.drawable.ic_action_lock;
break;
}
return sRes;
}
public static void execHook_SearchGlowPad() {
try {
XposedBridge.hookAllConstructors(findClass("com.android.internal.widget.multiwaveview.GlowPadView", null), new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.setFloatField(param.thisObject, "mFirstItemOffset", 0);
XposedHelpers.setIntField(param.thisObject, "mFeedbackCount", 1);
XposedHelpers.setBooleanField(param.thisObject, "mAllowScaling", false);
}
});
findAndHookMethod("com.android.internal.widget.multiwaveview.GlowPadView", null, "getSliceAngle", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
param.setResult((float)Math.toRadians(-45));
}
});
findAndHookMethod("com.android.internal.widget.multiwaveview.GlowPadView", null, "loadDrawableArray", int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
Class<?> TargetDrawable = findClass("com.android.internal.widget.multiwaveview.TargetDrawable", null);
Object stock_assist = TargetDrawable.getConstructor(Resources.class, int.class).newInstance(Resources.getSystem(), Resources.getSystem().getIdentifier("ic_action_assist_generic", "drawable", "android"));
Object dummy = TargetDrawable.getConstructor(Resources.class, int.class).newInstance(modRes, 0);
XMain.pref.reload();
int leftShortcut = Integer.parseInt(XMain.pref.getString("pref_key_controls_extendedpanel_left", "2"));
int rightShortcut = Integer.parseInt(XMain.pref.getString("pref_key_controls_extendedpanel_right", "1"));
Object leftObject = TargetDrawable.getConstructor(Resources.class, int.class).newInstance(modRes, getShortcutRes(leftShortcut, true));
Object rightObject = TargetDrawable.getConstructor(Resources.class, int.class).newInstance(modRes, getShortcutRes(rightShortcut, false));
ArrayList<Object> arraylist = new ArrayList<Object>();
int rot = getRotation(param);
if (rot == 1) {
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(rightObject);
arraylist.add(stock_assist);
arraylist.add(leftObject);
arraylist.add(dummy);
arraylist.add(dummy);
} else if (rot == 3) {
arraylist.add(stock_assist);
arraylist.add(leftObject);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(rightObject);
} else {
arraylist.add(dummy);
arraylist.add(rightObject);
arraylist.add(stock_assist);
arraylist.add(leftObject);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
arraylist.add(dummy);
}
param.setResult(arraylist);
}
});
findAndHookMethod("com.android.internal.widget.multiwaveview.GlowPadView", null, "loadDescriptions", int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
ArrayList<String> arraylist = new ArrayList<String>();
arraylist.add("");
arraylist.add("");
arraylist.add("");
arraylist.add("");
arraylist.add("");
arraylist.add("");
arraylist.add("");
arraylist.add("");
param.setResult(arraylist);
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_SearchGlowPadLaunch(LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.systemui.SearchPanelView.GlowPadTriggerListener", lpparam.classLoader, "onTrigger", View.class, int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
int item = (Integer)param.args[1];
View mGlowPadView = (View)param.args[0];
if (mGlowPadView == null) return;
Context ctx = mGlowPadView.getContext();
int resId = (Integer)XposedHelpers.callMethod(mGlowPadView, "getResourceIdForTarget", item);
switch (resId) {
case R.drawable.ic_action_apm:
Class<?> ActivityManagerNative = Class.forName("android.app.ActivityManagerNative");
Object activityManagerNative = XposedHelpers.callStaticMethod(ActivityManagerNative, "getDefault");
XposedHelpers.callMethod(activityManagerNative, "dismissKeyguardOnNextActivity");
OtherMods.startAPM(ctx);
break;
case R.drawable.ic_action_voicedial:
Intent intent = new Intent("com.htc.HTCSpeaker.HtcSpeakLauncher_QuickCall");
intent.setFlags(0x50000000);
intent.putExtra("LaunchBy", "LockScreen");
KeyguardManager kgm = (KeyguardManager)ctx.getSystemService(Context.KEYGUARD_SERVICE);
intent.putExtra("isKeyguardShow", kgm.inKeyguardRestrictedInputMode());
intent.putExtra("isKeyguardSecure", kgm.isKeyguardSecure());
intent.putExtra("isLockscreenDisable", !kgm.isKeyguardLocked());
ctx.startActivity(intent);
break;
case R.drawable.ic_action_lock:
ctx.sendBroadcast(new Intent("com.langerhans.one.mods.action.LockDevice"));
break;
case R.drawable.ic_action_sleep:
ctx.sendBroadcast(new Intent("com.langerhans.one.mods.action.GoToSleep"));
break;
}
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_HDThumbnails() {
try {
findAndHookMethod("com.android.server.wm.WindowManagerService", null, "screenshotApplications", IBinder.class, int.class, int.class, int.class, boolean.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.args[4] = false;
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_NoLowBatteryWarning(LoadPackageParam lpparam) {
try {
findAndHookMethod("com.android.systemui.power.PowerUI", lpparam.classLoader, "showLowBatteryWarningWithLevel", int.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(null);
}
});
findAndHookMethod("com.android.systemui.power.PowerUI", lpparam.classLoader, "startLowBatteryTone", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
param.setResult(null);
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public static void execHook_TranslucentNotifications(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.BaseStatusBar", lpparam.classLoader, "createNotificationViews", IBinder.class, StatusBarNotification.class, new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Object entry = param.getResult();
StatusBarNotification sbn = (StatusBarNotification)param.args[1];
if (entry == null) return;
View content = (View)XposedHelpers.getObjectField(entry, "content");
if (content != null) {
content.setBackgroundColor(Color.TRANSPARENT);
content.destroyDrawingCache();
content.invalidate();
}
View row = (View)XposedHelpers.getObjectField(entry, "row");
if (row != null) {
ViewGroup adaptive = (ViewGroup)row.findViewById(row.getResources().getIdentifier("adaptive", "id", "com.android.systemui"));
if (adaptive != null && adaptive.getChildCount() > 1) {
View adaptiveChild = adaptive.getChildAt(1);
if (adaptiveChild.getBackground() != null)
if (adaptiveChild instanceof LinearLayout) {
LinearLayout adaptiveLL = (LinearLayout)adaptiveChild;
adaptiveLL.setBackgroundColor(Color.TRANSPARENT);
adaptiveLL.destroyDrawingCache();
adaptiveLL.invalidate();
} else if (adaptiveChild instanceof FrameLayout) {
FrameLayout adaptiveFL = (FrameLayout)adaptiveChild;
adaptiveFL.setBackgroundColor(Color.TRANSPARENT);
adaptiveFL.destroyDrawingCache();
adaptiveFL.invalidate();
}
}
ArrayList<View> nViews = Helpers.getChildViewsRecursive(row);
for (View nView: nViews)
if (nView != null && nView.getResources() != null && nView.getId() > 0 && nView.getId() != 0xffffffff) try {
String name = nView.getResources().getResourceEntryName(nView.getId());
if (nView.getBackground() != null && nView.getVisibility() == 0 && !name.contains("glow") && !name.contains("icon")) {
nView.setBackgroundColor(Color.TRANSPARENT);
nView.destroyDrawingCache();
nView.invalidate();
}
if (sbn != null && name.contains("icon") && nView.getClass() == ImageView.class) {
ImageView icon = (ImageView)nView;
Context ctx = icon.getContext();
icon.setBackground(null);
icon.setImageDrawable(null);
Bitmap largeIcon = sbn.getNotification().largeIcon;
if (largeIcon != null) {
int dimen = densify(ctx, 64);
if (largeIcon.getWidth() > dimen || largeIcon.getHeight() > dimen) {
Bitmap newBmp = Bitmap.createScaledBitmap(sbn.getNotification().largeIcon, dimen, dimen, false);
icon.setImageBitmap(newBmp);
} else {
icon.setImageBitmap(largeIcon);
}
} else {
icon.setImageResource(sbn.getNotification().icon);
}
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
}
});
}
public static void execHook_TranslucentNotificationsDividers() {
try {
XResources.hookSystemWideLayout("android", "layout", "notification_action_list", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
LinearLayout nal = (LinearLayout)liparam.view;
if (nal != null) nal.setShowDividers(LinearLayout.SHOW_DIVIDER_NONE);
}
});
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_TranslucentNotificationsTV(InitPackageResourcesParam resparam) {
try {
resparam.res.setReplacement("com.htc.videohub.ui", "drawable", "notification_bg", Color.TRANSPARENT);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_TranslucentEQS(InitPackageResourcesParam resparam) {
try {
resparam.res.setReplacement("com.android.systemui", "drawable", "quick_settings_tile_background", Color.TRANSPARENT);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_TranslucentHorizEQS(InitPackageResourcesParam resparam) {
try {
resparam.res.setReplacement("com.android.systemui", "drawable", "quick_settings_minor_container_background", Color.TRANSPARENT);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
public static void execHook_TranslucentHorizEQSCode(LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader, "makeStatusBarView", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
FrameLayout mStatusBarWindow = (FrameLayout) getObjectField(param.thisObject, "mStatusBarWindow");
if (mStatusBarWindow != null) {
LinearLayout qsMinorContainer = (LinearLayout)mStatusBarWindow.findViewById(mStatusBarWindow.getResources().getIdentifier("quick_settings_minor_container", "id", "com.android.systemui"));
if (qsMinorContainer != null) qsMinorContainer.setShowDividers(0);
}
}
});
}
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(ScaleType.CENTER_INSIDE);
int size = Math.round(baseSize * density);
LinearLayout.LayoutParams lpi = new LinearLayout.LayoutParams(size, size);
if (baseSize > 22)
lpi.setMargins(0, Math.round(1 * density), Math.round(8 * density), 0);
else
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(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
tv.setText(ctx.getApplicationInfo().loadLabel(ctx.getPackageManager()) + ":");
tv.setTextColor(Color.WHITE);
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, toastText.getTextSize());
tv.setTypeface(toastText.getTypeface());
tv.setSingleLine(true);
tv.setAlpha(0.6f);
return tv;
}
public static void execHook_IconLabelToasts() {
XResources.hookSystemWideLayout("android", "layout", "transient_notification", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
XMain.pref.reload();
int option = Integer.parseInt(XMain.pref.getString("pref_key_other_iconlabletoasts", "1"));
if (option == 1) return;
Context ctx = liparam.view.getContext();
float density = ctx.getResources().getDisplayMetrics().density;
TextView toastText = (TextView)liparam.view.findViewById(android.R.id.message);
LinearLayout.LayoutParams lpt = (LinearLayout.LayoutParams)toastText.getLayoutParams();
lpt.gravity = Gravity.START;
LinearLayout toast = ((LinearLayout)liparam.view);
toast.setGravity(Gravity.START);
toast.setPadding(toast.getPaddingLeft() - Math.round(5 * density), toast.getPaddingTop(), toast.getPaddingRight(), toast.getPaddingBottom());
switch (option) {
case 2:
LinearLayout textOnly = new LinearLayout(ctx);
textOnly.setOrientation(LinearLayout.VERTICAL);
textOnly.setGravity(Gravity.START);
ImageView iv = createIcon(ctx, 22);
((LinearLayout)toastText.getParent()).removeAllViews();
textOnly.addView(toastText);
toast.setOrientation(LinearLayout.HORIZONTAL);
toast.addView(iv);
toast.addView(textOnly);
break;
case 3:
TextView tv = createLabel(ctx, toastText);
toast.setOrientation(LinearLayout.VERTICAL);
toast.addView(tv, 0);
break;
case 4:
LinearLayout textLabel = new LinearLayout(ctx);
textLabel.setOrientation(LinearLayout.VERTICAL);
textLabel.setGravity(Gravity.START);
ImageView iv2 = createIcon(ctx, 45);
TextView tv2 = createLabel(ctx, toastText);
((LinearLayout)toastText.getParent()).removeAllViews();
textLabel.addView(tv2);
textLabel.addView(toastText);
toast.setOrientation(LinearLayout.HORIZONTAL);
toast.addView(iv2);
toast.addView(textLabel);
break;
}
}
});
}
public static void execHook_DrawerFooterDynamicAlpha(LoadPackageParam lpparam, final int pref_footer) {
findAndHookMethod("com.android.systemui.statusbar.phone.NotificationPanelView", lpparam.classLoader, "draw", Canvas.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
FrameLayout panelView = (FrameLayout)param.thisObject;
if (panelView == null) return;
View mHandleView = (View)XposedHelpers.getObjectField(panelView, "mHandleView");
if (mHandleView != null && mHandleView.getBackground() != null) {
if (pref_footer == 3) {
mHandleView.getBackground().setAlpha(0);
} else if (pref_footer == 2) {
float drawerHeight = (float)panelView.getMeasuredHeight();
float headerHeight = 85 * panelView.getResources().getDisplayMetrics().density;
if (drawerHeight <= headerHeight)
mHandleView.getBackground().setAlpha(255);
else
mHandleView.getBackground().setAlpha(Math.round(255f * (1.0f - (drawerHeight - headerHeight) / ((float)panelView.getResources().getDisplayMetrics().heightPixels - headerHeight))));
}
}
}
});
}
public static BroadcastReceiver mBRScrDelete = new BroadcastReceiver() {
public void onReceive(final Context context, Intent intent) {
try {
Uri uri = intent.getParcelableExtra("screenshot_file");
if (uri != null) context.getContentResolver().delete(uri, null, null);
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE)).cancel(789);
} catch (Throwable t) {
XposedBridge.log(t);
}
}
};
public static void execHook_ScreenshotDelete(final LoadPackageParam lpparam) {
findAndHookMethod("com.android.systemui.screenshot.SaveImageInBackgroundTask", lpparam.classLoader, "doInBackground", "com.android.systemui.screenshot.SaveImageInBackgroundData[]", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Notification.Builder mNotificationBuilder = (Notification.Builder)XposedHelpers.getObjectField(param.thisObject, "mNotificationBuilder");
if (mNotificationBuilder != null) try {
Object[] saveImageData = (Object[])param.args[0];
Context ctx = (Context)XposedHelpers.getObjectField(saveImageData[0], "context");
Uri uri = (Uri)XposedHelpers.getObjectField(saveImageData[0], "imageUri");
if (ctx != null && uri != null) {
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
Intent intent = new Intent("com.langerhans.one.DELETE_SCREENSHOT");
intent.putExtra("screenshot_file", uri);
mNotificationBuilder.addAction(android.R.drawable.ic_menu_delete, Helpers.xl10n(modRes, R.string.delete), PendingIntent.getBroadcast(ctx, 0, intent, 0x10000000));
}
} catch (Throwable t) {
XposedBridge.log(t);
}
}
});
findAndHookMethod("com.android.systemui.screenshot.ScreenshotService", lpparam.classLoader, "start", new XC_MethodHook() {
@Override
protected void afterHookedMethod(final MethodHookParam param) throws Throwable {
Context mContext = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext");
mContext.registerReceiver(mBRScrDelete, new IntentFilter("com.langerhans.one.DELETE_SCREENSHOT"));
}
});
}
}