package de.theknut.xposedgelsettings.hooks.notificationbadges;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.TextView;
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.callbacks.XC_LoadPackage.LoadPackageParam;
import de.theknut.xposedgelsettings.hooks.Common;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Classes;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Fields;
import de.theknut.xposedgelsettings.hooks.ObfuscationHelper.Methods;
import de.theknut.xposedgelsettings.hooks.PreferencesHelper;
import de.theknut.xposedgelsettings.hooks.common.CommonHooks;
import de.theknut.xposedgelsettings.hooks.common.XGELSCallback;
import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import static de.robv.android.xposed.XposedHelpers.getObjectField;
public class NotificationBadgesHooks extends NotificationBadgesHelper {
public static void initAllHooks(LoadPackageParam lpparam) {
if (!PreferencesHelper.enableBadges) return;
CommonHooks.LauncherOnCreateListeners.add(new XGELSCallback() {
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
final Context mContext = (Context) callMethod(Common.LAUNCHER_INSTANCE, "getApplicationContext");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
intentFilter.addAction(Common.MISSEDIT_COUNTERS_STATUS);
intentFilter.addAction(Common.MISSEDIT_CALL_NOTIFICATION);
intentFilter.addAction(Common.MISSEDIT_SMS_NOTIFICATION);
intentFilter.addAction(Common.MISSEDIT_APP_NOTIFICATION);
intentFilter.addAction(Common.MISSEDIT_GMAIL_NOTIFICATION);
mContext.registerReceiver(notificationReceiver, intentFilter);
}
});
XposedBridge.hookAllMethods(Classes.Launcher, "onDestroy", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Common.LAUNCHER_CONTEXT.unregisterReceiver(notificationReceiver);
}
});
CommonHooks.OpenFolderListeners.add(new XGELSCallback() {
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
if (DEBUG) log(param, "Request Counters");
requestCounters();
}
});
XC_MethodHook requestCountersHook = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
if (DEBUG) log(param, "Request Counters");
requestCounters();
}
};
findAndHookMethod(Classes.Workspace, Methods.wOnDragEnd, requestCountersHook);
if (Common.IS_GNL && Common.IS_M_GNL) {
findAndHookMethod(Classes.Launcher, Methods.lFinishBindingItems, requestCountersHook);
} else
{
findAndHookMethod(Classes.Launcher, Methods.lFinishBindingItems, boolean.class, requestCountersHook);
}
CommonHooks.OnLauncherTransitionEndListeners.add(new XGELSCallback() {
int TOWORKSPACE = Common.GNL_VERSION >= ObfuscationHelper.GNL_5_6_22 ? 0 : 2;
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
if ((Boolean) param.args[TOWORKSPACE]) {
if (DEBUG) log(param, "Transitioning to Workspace - do nothing");
} else {
if (DEBUG) log(param, "Transitioning to All Apps - Request Counters");
requestCounters();
}
}
});
XC_MethodHook drawHook = new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Class parent = ((View) param.thisObject).getParent().getParent().getClass();
if (PreferencesHelper.hideBadgesFromAppDrawer
&& (parent.equals(Classes.AppsCustomizeCellLayout) || parent.equals(Classes.AllAppsRecyclerViewContainerView))) {
return;
}
ComponentName cmp = getComponentName(param.thisObject);
if (cmp == null) return;
int idx = findPendingNotification(cmp);
if (idx != -1) {
drawBadge((TextView) param.thisObject, (Canvas) param.args[0], pendingNotifications.get(idx).getCount());
}
}
private void drawBadge(TextView v, Canvas c, int count) {
if (count != 0) {
Drawable d = new Badge(count).getDrawable();
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
c.translate(getTranslationX(v, d), getTranslationY(v, d));
d.draw(c);
}
}
private float getTranslationX(TextView v, Drawable d) {
if (PreferencesHelper.notificationBadgePosition == 0
|| PreferencesHelper.notificationBadgePosition == 3) {
return v.getScrollX()
+ (v.getWidth() / 2)
- (v.getCompoundDrawables()[1].getIntrinsicWidth() / 2);
}
return v.getScrollX()
+ (v.getWidth() / 2)
+ (v.getCompoundDrawables()[1].getIntrinsicWidth() / 2)
- d.getIntrinsicWidth();
}
private float getTranslationY(TextView v, Drawable d) {
if (PreferencesHelper.notificationBadgePosition == 0
|| PreferencesHelper.notificationBadgePosition == 1) {
return v.getScrollY()
+ v.getPaddingTop();
}
return v.getScrollY()
+ v.getPaddingTop()
+ v.getCompoundDrawables()[1].getIntrinsicHeight()
- d.getIntrinsicHeight();
}
};
if (!PreferencesHelper.hideBadgesFromAppDrawer && Common.IS_PRE_GNL_4) {
findAndHookMethod(Classes.PagedViewIcon, "draw", Canvas.class, drawHook);
}
findAndHookMethod(Classes.BubbleTextView, "draw", Canvas.class, drawHook);
CommonHooks.FolderIconDispatchDrawListeners.add(new XGELSCallback() {
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
ArrayList<View> items = (ArrayList<View>) callMethod(getObjectField(param.thisObject, Fields.fiFolder), Methods.fGetItemsInReadingOrder);
int count = 0;
for (View item : items) {
int idx = findPendingNotification(getComponentName(item));
if (idx != -1) {
count += pendingNotifications.get(idx).getCount();
}
}
if (count != 0) {
View bg = (View) getObjectField(param.thisObject, Fields.fiPreviewBackground);
Drawable d = new Badge(count).getDrawable();
Canvas c = (Canvas) param.args[0];
c.translate(getTranslationX(bg, d), getTranslationY(bg, d));
d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
d.draw(c);
}
}
private float getTranslationX(View bg, Drawable d) {
if (PreferencesHelper.notificationBadgePosition == 0
|| PreferencesHelper.notificationBadgePosition == 3) {
return bg.getX()
+ folderMarginLeftRight;
}
return bg.getX()
+ bg.getWidth()
- d.getIntrinsicWidth()
- folderMarginLeftRight;
}
private float getTranslationY(View bg, Drawable d) {
if (PreferencesHelper.notificationBadgePosition == 0
|| PreferencesHelper.notificationBadgePosition == 1) {
return bg.getY()
+ d.getIntrinsicHeight() / 2;
}
return bg.getY()
+ bg.getHeight()
- d.getIntrinsicHeight()
- folderMarginTopBottom;
}
});
CommonHooks.LauncherOnResumeListeners.add(new XGELSCallback() {
@Override
public void onAfterHookedMethod(MethodHookParam param) throws Throwable {
if (activityManager == null) {
activityManager = (ActivityManager) Common.LAUNCHER_CONTEXT.getSystemService(Context.ACTIVITY_SERVICE);
}
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (Common.PACKAGE_NAMES.contains(appProcesses.get(0).processName)) {
if (DEBUG) log(param, "Request Counters");
requestCounters();
}
}
});
}
private static ComponentName getComponentName(Object o) {
try {
return ((Intent) callMethod(((View) o).getTag(), "getIntent")).getComponent();
} catch (Exception ex) {
return null;
} catch (Error ex) {
return null;
}
}
private static int findPendingNotification(ComponentName cmp) {
for (int i = 0; i < pendingNotifications.size(); i++) {
if (pendingNotifications.get(i).equals(cmp)) {
return i;
}
}
return -1;
}
}