Skip to content

Instantly share code, notes, and snippets.

@GitaiQAQ
Created April 11, 2016 07:32
Show Gist options
  • Save GitaiQAQ/183a184047073b9cac2e7aadd491aeeb to your computer and use it in GitHub Desktop.
Save GitaiQAQ/183a184047073b9cac2e7aadd491aeeb to your computer and use it in GitHub Desktop.
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!");
}
}
}
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