Created
April 11, 2016 07:32
-
-
Save GitaiQAQ/183a184047073b9cac2e7aadd491aeeb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.gitai.phuckqq.xposed; | |
import android.app.Notification; | |
import android.app.NotificationManager; | |
import android.support.v4.app.NotificationCompat; | |
import android.app.PendingIntent; | |
import android.content.BroadcastReceiver; | |
import me.gitai.library.utils.L; | |
import android.app.AndroidAppHelper; | |
import android.app.Application; | |
import android.util.Log; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.os.Environment; | |
import android.os.UserHandle; | |
import me.gitai.phuckqq.BuildConfig; | |
import android.content.Context; | |
import android.graphics.Bitmap; | |
import java.util.Iterator; | |
import de.robv.android.xposed.IXposedHookLoadPackage; | |
import de.robv.android.xposed.XC_MethodReplacement; | |
import de.robv.android.xposed.XSharedPreferences; | |
import de.robv.android.xposed.XposedBridge; | |
import de.robv.android.xposed.XposedHelpers; | |
import de.robv.android.xposed.callbacks.XC_LoadPackage; | |
import me.gitai.phuckqq.util.StringUtils; | |
import me.gitai.phuckqq.data.QQNotification; | |
import java.util.List; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.Collection; | |
import java.util.HashSet; | |
/** | |
* Created by gitai on 16-4-10. | |
*/ | |
public class NotificationHook implements IXposedHookLoadPackage { | |
private List<QQNotification> mMessages = new ArrayList(); | |
private void notificationHook(XC_LoadPackage.LoadPackageParam lpparam) throws ClassNotFoundException,NoSuchFieldException,IllegalAccessException{ | |
String className = "android.app.NotificationManager"; //类名 | |
String methodName = "notify"; //方法名 | |
XposedHelpers.findAndHookMethod(className, lpparam.classLoader, methodName, | |
int.class, Notification.class, | |
new XC_MethodReplacement() { //替换 | |
@Override | |
protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { | |
int id = (int)param.args[0]; //操作id,可用于后期删除,更新等 | |
QQNotification notification = new QQNotification(id, (Notification)param.args[1]);//构造自定义通知对象 | |
mMessages.add(notification);//插入全局数组 | |
HashSet<String> contacts = new HashSet();//统计来源用户,Set不可重复特性,HashSet比较快~ | |
StringBuilder messagesBuilder = new StringBuilder();//构造通知正文 | |
List<QQNotification> messages = new ArrayList();//因为删除太麻烦,直接构造新数组替换 | |
for (int i = (mMessages.size()>notification.getLinesLimit())?(mMessages.size()-notification.getLinesLimit()):0; i < mMessages.size(); i++) {//从-10开始枚举 | |
QQNotification n = mMessages.get(i); | |
messages.add(n);//填入新数组 | |
contacts.add(n.getContact());//填入联系人,用于计数 | |
messagesBuilder.append(n.getSummary());//获取摘要,格式 NickName:Body | |
if (i < mMessages.size() - 1) { | |
messagesBuilder.append("\n"); | |
} | |
} | |
mMessages = messages; | |
Context context = (Context)XposedHelpers.getObjectField(param.thisObject, "mContext"); | |
String summary = String.format("%d messages from %d contacts", mMessages.size(), contacts.size()); | |
NotificationCompat.Builder builder = notification.getBuilder(context) //构造通知对象 | |
.setStyle(new NotificationCompat.BigTextStyle() | |
.setBigContentTitle(notification.getContact()) | |
.setSummaryText(summary) | |
.bigText(messagesBuilder.toString())); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN){ | |
builder.setPriority(Notification.PRIORITY_MAX); | |
} | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){ | |
builder.setCategory(Notification.CATEGORY_ALARM); | |
} | |
((NotificationManager)param.thisObject).notify(null, notification.number, builder.build()); | |
//((NotificationManager)param.thisObject).notify(null, notification.number + 1, notification.getNotification()); //启用原通知 | |
return null; | |
} | |
}); | |
} | |
@Override | |
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { | |
Application app = AndroidAppHelper.currentApplication(); | |
//初始化各种工具库 | |
L.setLogcatEnable(app, true); //启用 | |
L.setLogToFileEnable(true, app, "/sdcard/phuckqq/logs"); //输出外部文件 | |
L.setXposedMode(true); //启用xposed输出 | |
//L.d(lpparam.packageName); | |
if (lpparam.packageName.startsWith("com.tencent.qq")) { //所有(大概 的QQ的包名 | |
L.d("initializing..."); | |
//设备信息,习惯性输出 | |
L.i("Phone manufacturer: %s", Build.MANUFACTURER); | |
L.i("Phone model: %s", Build.MODEL); | |
L.i("Android version: %s", Build.VERSION.RELEASE); | |
L.i("Xposed bridge version: %d", XposedBridge.XPOSED_BRIDGE_VERSION); | |
L.i("Module Version: %s (%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE); | |
try { | |
notificationHook(lpparam); | |
} catch (Throwable e) { | |
L.d("Failed to hook NotificationManager of QQ" + "\n" + Log.getStackTraceString(e)); | |
throw e; | |
} | |
L.d("initialization complete!"); | |
} | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.gitai.phuckqq.data; | |
import de.robv.android.xposed.XposedHelpers; | |
import android.graphics.Bitmap; | |
import android.app.Notification; | |
import me.gitai.phuckqq.util.StringUtils; | |
import android.support.v4.app.NotificationCompat; | |
import android.content.Context; | |
/** | |
* Created by gitai on 16-4-11. | |
*/ | |
public class QQNotification { | |
public Notification mNotification; | |
public String title,titleBig,text,subText,infoText,summaryText,tickerText; | |
public int number,mId,icon,progress,progressMax; | |
public Bitmap largeIcon,largeIconBig,picture; | |
public boolean progressIndeterminate,showChronometer,showWhen; | |
public CharSequence[] textLines; | |
public String mGroupName,mNickName,mNickNameShort,mMessageText = ""; | |
public QQNotification(int id, Notification notification) { | |
this.mId = id; | |
this.number = notification.number; | |
this.mNotification = notification; | |
this.tickerText = (String)notification.tickerText; | |
this.title = (String)notification.extras.getCharSequence(Notification.EXTRA_TITLE); //Group/User Name | |
this.titleBig = (String)notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG); | |
this.text = (String)notification.extras.getCharSequence(Notification.EXTRA_TEXT); //NickName: MessageBody | |
this.subText = (String)notification.extras.getCharSequence(Notification.EXTRA_SUB_TEXT); | |
this.infoText = (String)notification.extras.getCharSequence(Notification.EXTRA_INFO_TEXT); | |
this.summaryText = (String)notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT); | |
this.icon = notification.extras.getInt(Notification.EXTRA_SMALL_ICON); //Application Icon for Notification | |
this.progress = notification.extras.getInt(Notification.EXTRA_PROGRESS); | |
this.progressMax = notification.extras.getInt(Notification.EXTRA_PROGRESS_MAX); | |
this.largeIcon = notification.largeIcon; //Group/User Avatar | |
//this.notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON); | |
this.largeIconBig = notification.extras.getParcelable(Notification.EXTRA_LARGE_ICON_BIG); | |
this.picture = notification.extras.getParcelable(Notification.EXTRA_PICTURE); | |
this.progressIndeterminate = notification.extras.getBoolean(Notification.EXTRA_PROGRESS_INDETERMINATE); | |
this.showChronometer = notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER); | |
this.showWhen = notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN); | |
this.textLines = notification.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES); | |
this.mGroupName = title; | |
String[] msg = text.split(": "); | |
if (msg.length > 1) { //拆通知~ | |
//群组类 | |
mNickName = msg[0]; | |
for (int i = 1; i < msg.length; i++) { | |
mMessageText = mMessageText + msg[i]; | |
} | |
}else{ | |
//私聊会话 | |
this.mNickName = this.mGroupName; | |
this.mGroupName = null; | |
this.mMessageText = text; | |
} | |
} | |
public int getLinesLimit(){ | |
//输出限制,用最后一个对象计算 | |
int count = 10; | |
try{count = Integer.parseInt(infoText);}catch(NumberFormatException ex){} | |
return (count > 10)?10:count; | |
} | |
public Notification getNotification() { | |
return mNotification; | |
} | |
public String getContact(){ | |
if (!StringUtils.isEmpty(mGroupName))return mGroupName; | |
return mNickName; | |
} | |
public String getNickName(){ | |
return mNickName; | |
} | |
public String getGroupName(){ | |
return mGroupName; | |
} | |
public String getMessageText(){ | |
return mMessageText; | |
} | |
public String getSummary(){ | |
if (mNickName.length() <= 5) return mNickName + ":" + mMessageText; //昵称直接输出 | |
if (!StringUtils.isEmpty(mNickNameShort)) return mNickNameShort + ":" + mMessageText; //昵称摘要输出 | |
return (mNickNameShort = mNickName.substring(0, 3) + "...") + ":" + mMessageText; // | |
} | |
public NotificationCompat.Builder getBuilder(Context context){ | |
return new NotificationCompat.Builder(context) | |
.setSmallIcon(mNotification.icon) | |
.setWhen(mNotification.when) | |
.setLargeIcon(largeIcon) | |
.setAutoCancel(true) | |
//.setContent(notification.contentView) | |
.setContentTitle(getContact()) | |
.setContentText(getSummary()) | |
.setContentInfo(infoText) | |
.setTicker(tickerText) | |
.setContentIntent(mNotification.contentIntent); | |
} | |
@Override | |
public String toString() { //给其他方法调用 | |
return getSummary(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment