package de.theknut.xposedgelsettings.hooks.androidintegration;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers.ClassNotFoundError;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
import de.theknut.xposedgelsettings.R;
import de.theknut.xposedgelsettings.hooks.Common;
import de.theknut.xposedgelsettings.hooks.HooksBaseClass;
import de.theknut.xposedgelsettings.hooks.PreferencesHelper;
import de.theknut.xposedgelsettings.ui.StatusBarTintApi;
import static de.robv.android.xposed.XposedHelpers.callMethod;
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;
public class SystemUIReceiver extends HooksBaseClass {
private static boolean errorMsgShown = false;
private static boolean IS_CLOCK_VISIBLE = true;
public static View CLOCK_VIEW;
public static ImageView HOME_BUTTON;
public static ImageView BACK_BUTTON;
//public static ImageView RECENTS_BUTTON;
public static Drawable ALL_APPS_BUTTON;
public static Drawable POWER_OFF_BUTTON;
//public static Drawable CLEAR_BUTTON;
public static Drawable HOME_BUTTON_ORIG;
public static Drawable BACK_BUTTON_ORIG;
//public static Drawable RECENTS_BUTTON_ORIG;
public static ScaleType BACK_BUTTON_ORIG_SCALE;
public static ActivityManager activityManager;
public static PowerManager powerManager;
public static boolean shown;
public static boolean allowFlipPanel;
public static int animationDuration = 300;
public static Drawable TMP_HOME_BUTTON;
public static Drawable TMP_BACK_BUTTON;
public static ScaleType TMP_BACK_BUTTON_SCALE;
public static boolean TMP_CLOCK_VISIBILITY;
public static Object PHONE_STATUSBAR_OBJECT;
public static Object ICON_CONTROLLER;
public static View STATUS_BAR_VIEW;
public static View NAVIGATION_BAR_VIEW;
public static int BACKGROUND_COLOR = Color.TRANSPARENT;
public static Drawable BACKGROUND_COLOR_DRAWABLE = new ColorDrawable(BACKGROUND_COLOR);
public static Drawable ORIG_BACKGROUND_STATUSBAR;
public static Drawable ORIG_BACKGROUND_NAVIGATIONBAR;
public static int ORIG_COLOR_STATUSBAR;
public static int ORIG_COLOR_NAVIGATIONBAR;
public static Context systemUIContext;
public static void initAllHooks(LoadPackageParam lpparam) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
findAndHookMethod("com.android.systemui.statusbar.phone.PanelView", lpparam.classLoader, "fling", float.class, boolean.class, float.class, boolean.class, new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (!(Boolean) callMethod(param.thisObject, "isFullyExpanded")) {
param.args[3] = true;
}
}
});
}
if (DEBUG) log("SystemUIReceiver: found SystemUI " + lpparam.packageName);
final Class<?> PhoneStatusBarClass = findClass("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader);
final Class<?> PanelBarClass = findClass("com.android.systemui.statusbar.phone.PanelBar", lpparam.classLoader);
Class<?> tmpnbe = null;
// extra stuff we have to hook because CM is doing crazy stuff
try {
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
tmpnbe = findClass("com.android.systemui.statusbar.NavigationButtons", lpparam.classLoader);
}
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
tmpnbe = findClass("com.android.systemui.statusbar.phone.NavbarEditor", lpparam.classLoader);
}
else {
log("SystemUIReceiver: YOUR ANDROID VERSION IS NOT SUPPORTED!!!");
return;
}
} catch (ClassNotFoundError cnfe) {
// not using CM -> going for AOSP then
}
final Class<?> nbe = tmpnbe;
XposedBridge.hookAllMethods(PhoneStatusBarClass, "addNavigationBar", new XC_MethodHook() {
@SuppressLint("NewApi")
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
long time = System.currentTimeMillis();
PHONE_STATUSBAR_OBJECT = param.thisObject;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ICON_CONTROLLER = getObjectField(param.thisObject, "mIconController");
}
STATUS_BAR_VIEW = (View) getObjectField(PHONE_STATUSBAR_OBJECT, "mStatusBarView");
NAVIGATION_BAR_VIEW = (View) getObjectField(PHONE_STATUSBAR_OBJECT, "mNavigationBarView");
systemUIContext = ((Context) getObjectField(PHONE_STATUSBAR_OBJECT, "mContext"));
powerManager = (PowerManager) systemUIContext.getSystemService(Context.POWER_SERVICE);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Common.XGELS_INTENT);
intentFilter.addAction(Common.XGELS_ACTION_RELOAD_SETTINGS);
systemUIContext.registerReceiver(new BroadcastReceiver() {
Context myContext = null;
boolean init(Context context) {
try {
myContext = context.createPackageContext(Common.PACKAGE_NAME, Context.CONTEXT_IGNORE_SECURITY);
ALL_APPS_BUTTON = myContext.getResources().getDrawable(R.drawable.ic_home_all_apps_holo_dark);
POWER_OFF_BUTTON = myContext.getResources().getDrawable(R.drawable.navbar_power_icon);
//CLEAR_BUTTON = myContext.getResources().getDrawable(R.drawable.navbar_clear_icon);
if (HOME_BUTTON == null || BACK_BUTTON == null) {
return false;
}
return true;
} catch (Throwable e) {
log("SystemUIReceiver: Something went wrong while initializing context in makeStatusBarView\n" + e);
return false;
}
}
@SuppressLint("SdCardPath")
@Override
public void onReceive(Context context, Intent intent) {
try {
if (intent.getAction().equals(Common.XGELS_ACTION_RELOAD_SETTINGS)) {
PreferencesHelper.init();
if (DEBUG) log("SystemUI: Settings reloaded");
return;
}
if (intent.getAction().equals(Common.XGELS_INTENT) && intent.hasExtra(Common.XGELS_ACTION)) {
if (intent.hasExtra(Common.XGELS_ACTION_EXTRA)
&& intent.getStringExtra(Common.XGELS_ACTION_EXTRA).equals(Common.XGELS_ACTION_NAVBAR)) {
if (myContext == null) {
if (!init(context)) {
if (!shown) {
XposedBridge.log("XGELS: Couldn't initialize in SystemUI Receiver");
shown = true;
}
return;
}
}
if (HOME_BUTTON == null || BACK_BUTTON == null) {
if (!shown) {
log("SystemUIReceiver: Couldn't initialize in SystemUI Receiver");
shown = true;
}
return;
}
if (intent.getStringExtra(Common.XGELS_ACTION).equals("ON_DEFAULT_HOMESCREEN")) {
if (PreferencesHelper.hideClock) {
showHideClock(false);
}
if (PreferencesHelper.dynamicHomebutton && PreferencesHelper.dynamicIconHomebutton
&& !HOME_BUTTON.getDrawable().getConstantState().equals(ALL_APPS_BUTTON.getConstantState())) {
setHomeButtonIcon(ALL_APPS_BUTTON);
}
if (PreferencesHelper.dynamicBackbutton && PreferencesHelper.dynamicIconBackbutton
&& !BACK_BUTTON.getDrawable().getConstantState().equals(POWER_OFF_BUTTON.getConstantState())) {
setBackButtonIcon(POWER_OFF_BUTTON, ScaleType.FIT_CENTER);
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("BACK_HOME_ORIG")) {
if (PreferencesHelper.dynamicHomebutton && PreferencesHelper.dynamicIconHomebutton
&& !HOME_BUTTON.getDrawable().getConstantState().equals(HOME_BUTTON_ORIG.getConstantState())) {
setHomeButtonIcon(HOME_BUTTON_ORIG);
}
if (PreferencesHelper.dynamicBackbutton && PreferencesHelper.dynamicIconBackbutton
&& !BACK_BUTTON.getDrawable().getConstantState().equals(BACK_BUTTON_ORIG.getConstantState())) {
setBackButtonIcon(BACK_BUTTON_ORIG, BACK_BUTTON_ORIG_SCALE);
}
if (PreferencesHelper.hideClock) {
showHideClock(true);
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("HOME_ORIG")) {
if (PreferencesHelper.dynamicHomebutton && PreferencesHelper.dynamicIconHomebutton
&& !HOME_BUTTON.getDrawable().getConstantState().equals(HOME_BUTTON_ORIG.getConstantState())) {
setHomeButtonIcon(HOME_BUTTON_ORIG);
}
if (PreferencesHelper.hideClock) {
showHideClock(true);
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("BACK_ORIG")) {
if (PreferencesHelper.dynamicBackbutton && PreferencesHelper.dynamicIconBackbutton
&& !BACK_BUTTON.getDrawable().getConstantState().equals(BACK_BUTTON_ORIG.getConstantState())) {
setBackButtonIcon(BACK_BUTTON_ORIG, BACK_BUTTON_ORIG_SCALE);
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("BACK_POWER_OFF")) {
if (PreferencesHelper.dynamicBackbutton && PreferencesHelper.dynamicIconBackbutton
&& !BACK_BUTTON.getDrawable().getConstantState().equals(POWER_OFF_BUTTON.getConstantState())) {
setBackButtonIcon(POWER_OFF_BUTTON, ScaleType.FIT_CENTER);
}
}
} else if (intent.hasExtra(Common.XGELS_ACTION_EXTRA)
&& intent.getStringExtra(Common.XGELS_ACTION_EXTRA).equals(Common.XGELS_ACTION_OTHER)) {
if (intent.getStringExtra(Common.XGELS_ACTION).equals("GO_TO_SLEEP")) {
if (powerManager == null) {
powerManager = (PowerManager) systemUIContext.getSystemService(Context.POWER_SERVICE);
}
callMethod(powerManager, "goToSleep",SystemClock.uptimeMillis());
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("GESTURE_LAST_APP")) {
if (activityManager == null) {
activityManager = (ActivityManager) systemUIContext.getSystemService(Context.ACTIVITY_SERVICE);
}
ArrayList<RecentTaskInfo> apps = (ArrayList<RecentTaskInfo>) activityManager.getRecentTasks(2, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
if (apps.size() == 2) {
RecentTaskInfo app = apps.get(1);
if (app.id != -1) {
activityManager.moveTaskToFront(app.id, ActivityManager.MOVE_TASK_WITH_HOME);
} else {
systemUIContext.startActivity(app.baseIntent);
}
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("SHOW_NOTIFICATION_BAR")) {
if (PHONE_STATUSBAR_OBJECT == null) return;
if (DEBUG) log("SystemUIReceiver: Show Notification Bar");
callMethod(PHONE_STATUSBAR_OBJECT, "animateExpandNotificationsPanel");
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("SHOW_SETTINGS_PANEL")) {
if (PHONE_STATUSBAR_OBJECT == null) return;
if (DEBUG) log("SystemUIReceiver: Show Settings Panel");
try {
callMethod(PHONE_STATUSBAR_OBJECT, "animateExpandSettingsPanel");
} catch (NoSuchMethodError nsme) {
callMethod(PHONE_STATUSBAR_OBJECT, "animateExpandSettingsPanel", false);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
try {
callMethod(PHONE_STATUSBAR_OBJECT, "animateExpandSettingsPanel");
} catch (NoSuchMethodError nsme) {
callMethod(PHONE_STATUSBAR_OBJECT, "animateExpandSettingsPanel", false);
}
}
}, 500);
}
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("SHOW_RECENTS")) {
if (PHONE_STATUSBAR_OBJECT == null) return;
if (DEBUG) log("SystemUIReceiver: Show Recents");
callMethod(PHONE_STATUSBAR_OBJECT, "toggleRecentApps");
} else if (intent.getStringExtra(Common.XGELS_ACTION).equals("SHADOWS")) {
if (!isLauncherInForeground()
|| (STATUS_BAR_VIEW == null || NAVIGATION_BAR_VIEW == null)
|| (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& powerManager.isPowerSaveMode())) return;
boolean show = intent.getBooleanExtra("SHOW", false);
if (DEBUG) log("SystemUIReceiver: " + (show ? "SHOW" : "HIDE") + " shadows");
if (ORIG_BACKGROUND_NAVIGATIONBAR == null) {
ORIG_BACKGROUND_NAVIGATIONBAR = NAVIGATION_BAR_VIEW.getBackground();
ORIG_BACKGROUND_STATUSBAR = STATUS_BAR_VIEW.getBackground();
}
STATUS_BAR_VIEW.setBackgroundDrawable(show ? ORIG_BACKGROUND_STATUSBAR : BACKGROUND_COLOR_DRAWABLE);
NAVIGATION_BAR_VIEW.setBackgroundDrawable(show ? ORIG_BACKGROUND_NAVIGATIONBAR : BACKGROUND_COLOR_DRAWABLE);
if (tsbIsInstalled()) {
STATUS_BAR_VIEW.setBackgroundColor(BACKGROUND_COLOR);
NAVIGATION_BAR_VIEW.setBackgroundColor(BACKGROUND_COLOR);
int color = show ? Color.parseColor("#66000000") : Color.TRANSPARENT;
StatusBarTintApi.sendColorChangeIntent(color, Color.WHITE, color, Color.WHITE, systemUIContext);
}
}
} else if (intent.hasExtra(Common.XGELS_ACTION_EXTRA)
&& intent.getStringExtra(Common.XGELS_ACTION_EXTRA).equals(Common.XGELS_ACTION_APP_REQUEST)) {
if (intent.getStringExtra(Common.XGELS_ACTION).equals("SAVE_LOGCAT")) {
log("Start saving logcat");
String logfilePath = "/mnt/sdcard/XposedGELSettings/logs/logcat_systemui.log";
File logfile = new File(logfilePath);
if (logfile.exists()) {
logfile.delete();
}
logfile.getParentFile().mkdirs();
logfile.createNewFile();
try {
Process process = Runtime.getRuntime().exec("logcat -v time -d");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder log = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line).append('\n');
}
FileWriter out = new FileWriter(logfile);
out.write(log.toString());
out.close();
} catch (IOException e) {}
log("Finished saving logcat");
}
}
}
} catch (NoSuchMethodError nsme) {
if (!errorMsgShown) {
errorMsgShown = true;
log("Something went wrong. Show this to the dev!");
log("Error: " + Log.getStackTraceString(nsme));
}
} catch (Exception ex) {
if (!errorMsgShown) {
errorMsgShown = true;
log("Ex Something went wrong. Show this to the dev!");
log("Exception: " + Log.getStackTraceString(ex));
}
}
}
private boolean tsbIsInstalled() {
try {
PackageManager pm = systemUIContext.getPackageManager();
pm.getPackageInfo("com.mohammadag.colouredstatusbar", PackageManager.GET_ACTIVITIES);
return true;
} catch (Exception ex) {
}
return false;
}
}, intentFilter);
Object navBar = null;
try {
try {
navBar = getObjectField(PHONE_STATUSBAR_OBJECT, "mNavigationBarView");
HOME_BUTTON = (ImageView) callMethod(navBar, "getHomeButton");
BACK_BUTTON = (ImageView) callMethod(navBar, "getBackButton");
//RECENTS_BUTTON = (ImageView) callMethod(navBar, "getRecentsButton");
HOME_BUTTON_ORIG = HOME_BUTTON.getDrawable();
BACK_BUTTON_ORIG = BACK_BUTTON.getDrawable();
BACK_BUTTON_ORIG_SCALE = BACK_BUTTON.getScaleType();
} catch (NoSuchMethodError nsme) {
// probably running CM
navBar = getObjectField(PHONE_STATUSBAR_OBJECT, "mNavigationBarView");
View mCurrentView = (View) getObjectField(navBar, "mCurrentView");
if (android.os.Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
HOME_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "HOME"));
BACK_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "BACK"));
//RECENTS_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "RECENT"));
}
else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
HOME_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "NAVBAR_HOME"));
BACK_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "NAVBAR_BACK"));
//RECENTS_BUTTON = (ImageView) mCurrentView.findViewWithTag(getStaticObjectField(nbe, "NAVBAR_RECENT"));
}
HOME_BUTTON_ORIG = HOME_BUTTON.getDrawable();
BACK_BUTTON_ORIG = BACK_BUTTON.getDrawable();
BACK_BUTTON_ORIG_SCALE = BACK_BUTTON.getScaleType();
//RECENTS_BUTTON_ORIG = RECENTS_BUTTON.getDrawable();
}
} catch (Exception ex) {
// okay probably not
log("SystemUIReceiver: Something went wrong when hooking to SystemUI. Changing the navigation bar icons will not work. Please show this to dev:");
log("SystemUIReceiver: " + ex);
}
if (DEBUG) log("SystemUI hooks took " + (System.currentTimeMillis() - time) + "ms");
};
});
XposedBridge.hookAllMethods(PhoneStatusBarClass, "flipToSettings", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (PHONE_STATUSBAR_OBJECT != null) {
boolean isExpanded = (Boolean) getObjectField(PHONE_STATUSBAR_OBJECT,"mExpandedVisible");
if (!isExpanded) {
if (DEBUG) log(param, "Don't flip Settings Panel");
callMethod(PHONE_STATUSBAR_OBJECT, "switchToSettings");
param.setResult(null);
} else {
if (DEBUG) log(param, "Allow flip Settings Panel");
}
}
}
});
if ((PreferencesHelper.dynamicBackbutton && PreferencesHelper.dynamicIconBackbutton)
|| (PreferencesHelper.dynamicHomebutton && PreferencesHelper.dynamicIconHomebutton)) {
XposedBridge.hookAllMethods(PanelBarClass, "onPanelFullyOpened", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (isLauncherInForeground()) {
TMP_CLOCK_VISIBILITY = IS_CLOCK_VISIBLE;
TMP_HOME_BUTTON = HOME_BUTTON.getDrawable();
TMP_BACK_BUTTON = BACK_BUTTON.getDrawable();
TMP_BACK_BUTTON_SCALE = BACK_BUTTON.getScaleType();
Intent myIntent = new Intent();
myIntent.putExtra(Common.XGELS_ACTION_EXTRA, Common.XGELS_ACTION_NAVBAR);
myIntent.putExtra(Common.XGELS_ACTION, "BACK_HOME_ORIG");
myIntent.setAction(Common.XGELS_INTENT);
systemUIContext.sendBroadcast(myIntent);
if (DEBUG) log(param, "Restore default navigation bar buttons");
}
}
});
XposedBridge.hookAllMethods(PanelBarClass, "collapseAllPanels", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
if (isLauncherInForeground()) {
if (TMP_HOME_BUTTON != null && TMP_BACK_BUTTON != null && TMP_BACK_BUTTON_SCALE != null) {
setHomeButtonIcon(TMP_HOME_BUTTON);
setBackButtonIcon(TMP_BACK_BUTTON, TMP_BACK_BUTTON_SCALE);
showHideClock(TMP_CLOCK_VISIBILITY);
TMP_HOME_BUTTON = null;
TMP_BACK_BUTTON = null;
TMP_BACK_BUTTON_SCALE = null;
if (DEBUG) log(param, "Restore previous navigation bar buttons");
}
}
}
});
}
}
public static boolean isLauncherInForeground() {
if (activityManager == null) {
activityManager = (ActivityManager) systemUIContext.getSystemService(Context.ACTIVITY_SERVICE);
}
List<RecentTaskInfo> appProcesses = activityManager.getRecentTasks(2, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
if (appProcesses.size() == 0) {
return true;
}
return Common.PACKAGE_NAMES.contains(appProcesses.get(0).baseIntent.getComponent().getPackageName().replace(":search", ""));
}
public static void setHomeButtonIcon(Drawable icon) {
HOME_BUTTON.setAlpha(0f);
HOME_BUTTON.setImageDrawable(icon);
if (PreferencesHelper.dynamicAnimateIconHomebutton) {
HOME_BUTTON.animate().alpha(1f).setDuration(animationDuration).start();
}
else {
HOME_BUTTON.setAlpha(1f);
}
}
public static void setBackButtonIcon(Drawable icon, ScaleType scaleType) {
BACK_BUTTON.setAlpha(0f);
BACK_BUTTON.setScaleType(scaleType);
BACK_BUTTON.setImageDrawable(icon);
if (PreferencesHelper.dynamicAnimateIconBackbutton) {
BACK_BUTTON.animate().alpha(1f).setDuration(animationDuration).start();
}
else {
BACK_BUTTON.setAlpha(1f);
}
}
public static void showHideClock(boolean show) {
if (PHONE_STATUSBAR_OBJECT == null) return;
IS_CLOCK_VISIBLE = show;
if (DEBUG) log("SystemUIReceiver: " + (show ? "Show" : "Hide") + " clock");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
callMethod(ICON_CONTROLLER, "setClockVisibility", show);
} else {
callMethod(PHONE_STATUSBAR_OBJECT, "showClock", show);
}
}
}