package de.theknut.xposedgelsettings.hooks.notificationbadges;
import android.app.ActivityManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Point;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.WindowManager;
import java.util.ArrayList;
import de.theknut.xposedgelsettings.R;
import de.theknut.xposedgelsettings.hooks.Common;
import de.theknut.xposedgelsettings.hooks.HooksBaseClass;
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.Utils;
import static de.robv.android.xposed.XposedHelpers.callMethod;
import static de.robv.android.xposed.XposedHelpers.getObjectField;
public class NotificationBadgesHelper extends HooksBaseClass {
static PackageManager pm;
static ActivityManager activityManager;
public static int displayWidth = -1, displayHeigth = -1;
public static int measuredWidth = -1, measuredHeigth = -1;
public static int leftRightPadding, topBottomPadding;
public static int folderMarginLeftRight, folderMarginTopBottom;
public static int frameSize;
public static Intent missedItServiceIntent;
static ArrayList<PendingNotification> pendingNotifications = new ArrayList<PendingNotification>();
static BroadcastReceiver notificationReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent i) {
String action = i.getAction();
if (DEBUG) log("Received Intent: " + action);
if (action.equals(Common.MISSEDIT_CALL_NOTIFICATION)) {
if (i.hasExtra("COUNT")) {
handleMissedCalls(i.getIntExtra("COUNT", 0));
}
} else if (action.equals(Common.MISSEDIT_SMS_NOTIFICATION)) {
if (i.hasExtra("COUNT")) {
handleUnreadSMS(i.getIntExtra("COUNT", 0));
}
} else if (action.equals(Common.MISSEDIT_GMAIL_NOTIFICATION)) {
if (DEBUG) log("GMAIL NOTIFICATION " + i.getStringExtra("ACCOUNT"));
requestCounters();
} else if (action.equals(Common.MISSEDIT_APP_NOTIFICATION)) {
if (DEBUG) log("APP NOTIFICATION " + i.getStringExtra("COMPONENTNAME"));
if (i.hasExtra("COMPONENTNAME")) {
addPendingNotification(
new PendingNotification(
ComponentName.unflattenFromString(i.getStringExtra("COMPONENTNAME")),
i.getIntExtra("COUNT", 0)
)
);
}
} else if (action.equals(Common.MISSEDIT_COUNTERS_STATUS)) {
pendingNotifications.clear();
Bundle bundles = i.getBundleExtra("MISSED_CALLS");
if (bundles != null) {
handleMissedCalls(bundles.getInt("COUNT"));
} else {
if (DEBUG) log("No MISSED_CALLS");
}
bundles = i.getBundleExtra("UNREAD_SMS");
if (bundles != null) {
handleUnreadSMS(bundles.getInt("COUNT"));
} else {
if (DEBUG) log("No UNREAD_SMS");
}
bundles = i.getBundleExtra("PENDING_VOICEMAILS");
if (bundles != null) {
//handleUnreadSMS(bundles.getInt("COUNT"));
} else {
if (DEBUG) log("No PENDING_VOICEMAILS ");
}
handleEMailBundles(i, "GMAIL_ACCOUNTS", ComponentName.unflattenFromString("com.google.android.gm/com.google.android.gm.ConversationListActivityGmail"));
handleEMailBundles(i, "K9MAIL_ACCOUNTS", ComponentName.unflattenFromString("com.fsck.k9/com.fsck.k9.activity.Accounts"));
handleEMailBundles(i, "AQUAMAIL_ACCOUNTS", ComponentName.unflattenFromString("org.kman.AquaMail/org.kman.AquaMail.ui.AccountListActivity"));
bundles = i.getBundleExtra("APPLICATIONS");
if (bundles != null) {
for (int j = 0; j < bundles.size(); j++) {
Bundle bundle = bundles.getBundle("" + j);
if (bundle != null) {
if (bundle.containsKey("COMPONENTNAME")) {
addPendingNotification(
new PendingNotification(
ComponentName.unflattenFromString(bundle.getString("COMPONENTNAME")),
bundle.getInt("COUNT", 0)
)
);
}
}
}
} else {
if (DEBUG) log("No APPLICATIONS");
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
requestCounters();
}
invalidate();
}
private void invalidate() {
new AsyncTask<Void, Void, Void>(){
@Override
protected Void doInBackground(Void... params) {
ArrayList cellLayouts = (ArrayList) callMethod(Common.WORKSPACE_INSTANCE, Methods.wGetWorkspaceAndHotseatCellLayouts);
for (Object layoutParent : cellLayouts) {
ViewGroup layout = (ViewGroup) getObjectField(layoutParent, Fields.clShortcutsAndWidgets);
int childCount = layout.getChildCount();
for (int i = 0; i < childCount; ++i) {
layout.getChildAt(i).postInvalidate();
}
}
return null;
}
}.execute();
}
void handleEMailBundles(Intent intent, String bundleName, ComponentName componentName) {
Bundle bundles = intent.getBundleExtra(bundleName);
if (bundles != null) {
int totalCnt = 0;
for (int j = 0; j < bundles.size(); j++) {
Bundle bundle = bundles.getBundle("" + j);
if (bundle != null) {
totalCnt += bundle.getInt("COUNT", 0);
}
}
addPendingNotification(new PendingNotification(componentName, totalCnt));
} else {
if (DEBUG) log("No " + bundleName);
}
}
void handleUnreadSMS(int cnt) {
if (pm == null) pm = Common.LAUNCHER_CONTEXT.getPackageManager();
try {
String packageName = PreferencesHelper.notificationSMSApp;
ResolveInfo mInfo;
if (TextUtils.isEmpty(packageName)) {
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
smsIntent.setType("vnd.android-dir/mms-sms");
mInfo = pm.resolveActivity(smsIntent, 0);
packageName = mInfo.activityInfo.packageName;
if (packageName.equals("android")) {
throw new Exception();
}
} else {
mInfo = pm.resolveActivity(pm.getLaunchIntentForPackage(packageName), 0);
}
addPendingNotification(new PendingNotification(mInfo, cnt));
} catch (Exception ex) {
makeNotification("XGELS can't determine your default SMS app. Please configure it manually in the \"Notification badges\" - \"Advanced\" section. Click here to open XGELS!");
log("Couldn't resolve default sms app. Use advanced settings in notification badges menu.");
log("Show this to the dev: " + ex);
}
}
void handleMissedCalls(int cnt) {
if (pm == null) pm = Common.LAUNCHER_CONTEXT.getPackageManager();
try {
String packageName = PreferencesHelper.notificationDialerApp;
ResolveInfo mInfo;
if (TextUtils.isEmpty(packageName)) {
mInfo = pm.resolveActivity(new Intent(Intent.ACTION_DIAL) , 0);
packageName = mInfo.activityInfo.packageName;
if (packageName.equals("android")) {
throw new Exception();
}
} else {
mInfo = pm.resolveActivity(pm.getLaunchIntentForPackage(packageName), 0);
}
addPendingNotification(new PendingNotification(mInfo, cnt));
} catch (Exception ex) {
makeNotification("XGELS can't determine your default Dialer app. Please configure it manually in the \"Notification badges\" - \"Advanced\" section. Click here to open XGELS!");
log("Couldn't resolve default caller app. Use advanced settings in notification badges menu.");
log("Show this to the dev: " + ex);
}
}
void makeNotification(String msg) {
PackageManager pm = Common.LAUNCHER_CONTEXT.getPackageManager();
Intent LaunchIntent = pm.getLaunchIntentForPackage(Common.PACKAGE_NAME);
LaunchIntent.putExtra("fragment", "badges");
PendingIntent pInstallTab = PendingIntent.getActivity(Common.LAUNCHER_CONTEXT, 0xB00B5, LaunchIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.BigTextStyle notiStyle = new NotificationCompat.BigTextStyle();
notiStyle.setBigContentTitle("Oh snap!");
notiStyle.bigText(msg);
NotificationCompat.Builder builder = new NotificationCompat.Builder(Common.LAUNCHER_CONTEXT)
.setContentTitle("Oh snap!")
.setContentText(msg)
.setTicker("Something went wrong :-\\")
.setContentIntent(pInstallTab)
.setAutoCancel(true)
.setStyle(notiStyle)
.setSmallIcon(android.R.drawable.ic_dialog_alert);
((NotificationManager) Common.LAUNCHER_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE)).notify(null, 0, builder.build());
}
void addPendingNotification(PendingNotification pn) {
int idx = pendingNotifications.indexOf(pn);
if (idx != -1) {
if (pn.getCount() == 0) {
if (DEBUG) log("remove " + pn);
pendingNotifications.remove(idx);
} else {
if (DEBUG) log("update " + pn);
pendingNotifications.get(idx).setCount(pn.getCount());
}
} else {
if (DEBUG) log("add " + pn);
pendingNotifications.add(pn);
}
}
};
protected static void requestCounters() {
if (missedItServiceIntent == null) {
missedItServiceIntent = new Intent(Common.MISSEDIT_REQUESET_COUNTERS);
ResolveInfo r = Common.LAUNCHER_INSTANCE.getPackageManager().resolveService(missedItServiceIntent, 0);
if (r != null) {
missedItServiceIntent.setComponent(new ComponentName(r.serviceInfo.packageName, r.serviceInfo.name));
}
}
// start or call MissedIt service in order to receive notification intents
Common.LAUNCHER_CONTEXT.startService(missedItServiceIntent);
}
protected static void initMeasures() {
long time = System.currentTimeMillis();
//if (displayWidth == -1) {
WindowManager wm = (WindowManager) Common.LAUNCHER_CONTEXT.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
displayWidth = size.x;
displayHeigth = size.y;
DisplayMetrics displayMetrics = Common.LAUNCHER_CONTEXT.getResources().getDisplayMetrics();
measuredWidth = MeasureSpec.makeMeasureSpec(displayWidth, MeasureSpec.AT_MOST);
measuredHeigth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
leftRightPadding = Utils.dpToPx(PreferencesHelper.notificationBadgeLeftRightPadding, displayMetrics);
topBottomPadding = Utils.dpToPx(PreferencesHelper.notificationBadgeTopBottomPadding, displayMetrics);
folderMarginLeftRight = Math.round(Common.XGELS_CONTEXT.getResources().getDimension(R.dimen.notificationbadgemarginleftright));
folderMarginTopBottom = Math.round(Common.XGELS_CONTEXT.getResources().getDimension(R.dimen.notificationbadgemargintopbottom));
frameSize = Utils.dpToPx(PreferencesHelper.notificationBadgeFrameSize, displayMetrics);
if (DEBUG) log("InitMeasures - width: " + displayWidth +" height: " + displayHeigth + " took " + (System.currentTimeMillis() - time) + "ms");
}
}