├── assets
└── xposed_init
├── .gitignore
├── ic_launcher-web.png
├── res
├── drawable-hdpi
│ ├── ic_launcher.png
│ └── heads_up_window_bg.9.png
├── drawable-mdpi
│ ├── ic_launcher.png
│ └── heads_up_window_bg.9.png
├── drawable-xhdpi
│ ├── ic_launcher.png
│ └── heads_up_window_bg.9.png
├── drawable-xxhdpi
│ ├── ic_launcher.png
│ └── heads_up_window_bg.9.png
├── values-v11
│ └── styles.xml
├── values
│ ├── entries.xml
│ ├── styles.xml
│ └── strings.xml
├── values-v14
│ └── styles.xml
├── layout
│ └── blacklist_item.xml
└── xml
│ └── preferences.xml
├── .classpath
├── project.properties
├── proguard-project.txt
├── .project
├── AndroidManifest.xml
└── src
└── com
└── mohammadag
└── headsupenabler
├── SettingsActivity.java
├── SettingsHelper.java
├── Blacklist.java
└── XposedMod.java
/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.mohammadag.headsupenabler.XposedMod
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | bin/
3 | gen/
4 | out/
5 | *.apk
6 | *.iml
7 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/ic_launcher-web.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/heads_up_window_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-hdpi/heads_up_window_bg.9.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/heads_up_window_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-mdpi/heads_up_window_bg.9.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/heads_up_window_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-xhdpi/heads_up_window_bg.9.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/heads_up_window_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ns130291/Xposed-Heads-Up-Notifications/master/res/drawable-xxhdpi/heads_up_window_bg.9.png
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values/entries.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - @string/pref_blacklist_title
5 | - @string/pref_whitelist_title
6 |
7 |
8 | - blacklist
9 | - whitelist
10 |
11 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | HeadsUpEnabler
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
37 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/res/layout/blacklist_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
15 |
16 |
25 |
26 |
36 |
37 |
47 |
48 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Heads Up Notifications
4 | Copyright © 2014 – MohammadAG / GermainZ\nVisit support thread
5 | Loading…
6 | Notification delay
7 | Delay (in ms) before the Heads Up notification
8 | disappears. A reboot is required to apply this option
9 | Notification filtering
10 | Blacklist
11 | Ignore notifications from certain apps
12 | Whitelist
13 | Only show notifications from certain apps
14 | Ongoing notifications
15 | Enable heads up for ongoing (persistent) notifications
16 | Only when fullscreen
17 | Enable Heads Up only when in fullscreen apps
18 | Hide low priority notifications
19 | Hides notifications with low and minimum priority
20 | Only when unlocked
21 | Enable Heads Up only when phone is unlocked
22 | Remove Heads Up padding
23 | Remove the padding on the sides of the Heads Up notification,
24 | and have it show on top of the status bar. A reboot is required to apply this option
25 | Application icon
26 |
27 |
--------------------------------------------------------------------------------
/src/com/mohammadag/headsupenabler/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.mohammadag.headsupenabler;
2 |
3 | import android.os.Bundle;
4 | import android.preference.ListPreference;
5 | import android.preference.Preference;
6 | import android.preference.PreferenceActivity;
7 |
8 | public class SettingsActivity extends PreferenceActivity {
9 | @SuppressWarnings("deprecation")
10 | @Override
11 | protected void onCreate(Bundle savedInstanceState) {
12 | super.onCreate(savedInstanceState);
13 | getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE);
14 | addPreferencesFromResource(R.xml.preferences);
15 |
16 | final ListPreference notificationFilterTypePref = (ListPreference) findPreference("notification_filter_type");
17 | final Preference notificationList = findPreference("notification_list");
18 |
19 | if (notificationFilterTypePref.getValue().equals("blacklist")) {
20 | notificationFilterTypePref.setSummary(R.string.pref_blacklist_title);
21 | notificationList.setTitle(R.string.pref_blacklist_title);
22 | notificationList.setSummary(R.string.pref_blacklist_summary);
23 | } else {
24 | notificationFilterTypePref.setSummary(R.string.pref_whitelist_title);
25 | notificationList.setTitle(R.string.pref_whitelist_title);
26 | notificationList.setSummary(R.string.pref_whitelist_summary);
27 | }
28 |
29 | notificationFilterTypePref.setOnPreferenceChangeListener(new ListPreference.OnPreferenceChangeListener() {
30 | @Override
31 | public boolean onPreferenceChange(Preference preference, Object newValue) {
32 | if (newValue.equals("blacklist")) {
33 | notificationFilterTypePref.setSummary(R.string.pref_blacklist_title);
34 | notificationList.setTitle(R.string.pref_blacklist_title);
35 | notificationList.setSummary(R.string.pref_blacklist_summary);
36 | } else {
37 | notificationFilterTypePref.setSummary(R.string.pref_whitelist_title);
38 | notificationList.setTitle(R.string.pref_whitelist_title);
39 | notificationList.setSummary(R.string.pref_whitelist_summary);
40 | }
41 | return true;
42 | }
43 | });
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
11 |
12 |
13 |
17 |
18 |
22 |
23 |
27 |
28 |
32 |
33 |
37 |
38 |
44 |
45 |
51 |
52 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/src/com/mohammadag/headsupenabler/SettingsHelper.java:
--------------------------------------------------------------------------------
1 | package com.mohammadag.headsupenabler;
2 |
3 | import java.util.HashSet;
4 |
5 | import android.content.Context;
6 | import android.content.SharedPreferences;
7 | import de.robv.android.xposed.XSharedPreferences;
8 |
9 | public class SettingsHelper {
10 | private static final String PACKAGE_NAME = "com.mohammadag.headsupenabler";
11 | private static final String PREFS = PACKAGE_NAME + "_preferences";
12 | // called "blacklist" for compatibility with previous versions, but can be a whitelist too
13 | private static final String NOTIFICATION_FILTER_LIST = "blacklist";
14 | private XSharedPreferences mXSharedPreferences = null;
15 | private SharedPreferences mSharedPreferences = null;
16 | private Context mContext = null;
17 | private HashSet mListItems;
18 | private String mListType;
19 |
20 | // Called from module's classes.
21 | public SettingsHelper() {
22 | mXSharedPreferences = new XSharedPreferences(PACKAGE_NAME, PREFS);
23 | mXSharedPreferences.makeWorldReadable();
24 | }
25 |
26 | // Called from activities.
27 | @SuppressWarnings("deprecation")
28 | public SettingsHelper(Context context) {
29 | mSharedPreferences = context.getSharedPreferences(PREFS, Context.MODE_WORLD_READABLE);
30 | mContext = context;
31 | }
32 |
33 | public void reload() {
34 | mXSharedPreferences.reload();
35 | mListItems = getListItems();
36 | mListType = getListType();
37 | }
38 |
39 | public void addListItem(String listItem) {
40 | mListItems.add(listItem);
41 | SharedPreferences.Editor prefEditor = mSharedPreferences.edit();
42 | prefEditor.putStringSet(NOTIFICATION_FILTER_LIST, mListItems);
43 | prefEditor.apply();
44 | }
45 |
46 | public void removeListItem(String listItem) {
47 | SharedPreferences.Editor prefEditor = mSharedPreferences.edit();
48 | mListItems.remove(listItem);
49 | prefEditor.putStringSet(NOTIFICATION_FILTER_LIST, mListItems);
50 | prefEditor.apply();
51 | }
52 |
53 | public boolean isListed(String s) {
54 | if (mListItems == null)
55 | mListItems = getListItems();
56 | return mListItems.contains(s);
57 | }
58 |
59 | public boolean shouldIgnore(String s) {
60 | return mListType.equals("blacklist") ? isListed(s) : !isListed(s);
61 | }
62 |
63 | public HashSet getListItems() {
64 | HashSet set = new HashSet();
65 | if (mSharedPreferences != null)
66 | set.addAll(mSharedPreferences.getStringSet(NOTIFICATION_FILTER_LIST, set));
67 | else if (mXSharedPreferences != null)
68 | set.addAll(mXSharedPreferences.getStringSet(NOTIFICATION_FILTER_LIST, set));
69 | return set;
70 | }
71 |
72 | public String getListType() {
73 | if (mSharedPreferences != null)
74 | return mSharedPreferences.getString("notification_filter_type", "blacklist");
75 | else if (mXSharedPreferences != null)
76 | return mXSharedPreferences.getString("notification_filter_type", "blacklist");
77 | return null;
78 | }
79 |
80 | public int getHeadsUpNotificationDecay() {
81 | return Integer.parseInt(mXSharedPreferences.getString("heads_up_notification_decay", "3700"));
82 | }
83 |
84 | public boolean isEnabledForOngoingNotifications() {
85 | return mXSharedPreferences.getBoolean("enabled_for_ongoing_notifications", false);
86 | }
87 |
88 | public boolean isEnabledOnlyWhenFullscreen() {
89 | return mXSharedPreferences.getBoolean("enabled_only_when_fullscreen", false);
90 | }
91 |
92 | public boolean isDisabledForLowPriority(){
93 | return mXSharedPreferences.getBoolean("disabled_for_low_priority", false);
94 | }
95 |
96 | public boolean isEnabledOnlyWhenUnlocked() {
97 | return mXSharedPreferences.getBoolean("enabled_only_when_unlocked", false);
98 | }
99 |
100 | public boolean shouldRemovePadding() {
101 | return mXSharedPreferences.getBoolean("remove_padding", false);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/com/mohammadag/headsupenabler/Blacklist.java:
--------------------------------------------------------------------------------
1 | package com.mohammadag.headsupenabler;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.Comparator;
6 | import java.util.List;
7 |
8 | import android.app.ProgressDialog;
9 | import android.content.Context;
10 | import android.content.pm.ApplicationInfo;
11 | import android.content.pm.PackageManager;
12 | import android.graphics.drawable.Drawable;
13 | import android.os.AsyncTask;
14 | import android.os.Bundle;
15 | import android.preference.PreferenceActivity;
16 | import android.view.LayoutInflater;
17 | import android.view.MenuItem;
18 | import android.view.View;
19 | import android.view.ViewGroup;
20 | import android.widget.ArrayAdapter;
21 | import android.widget.CheckBox;
22 | import android.widget.ImageView;
23 | import android.widget.TextView;
24 |
25 | public class Blacklist extends PreferenceActivity {
26 | private static SettingsHelper mSettingsHelper;
27 | private static BlacklistAdapter mAdapter;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | mSettingsHelper = new SettingsHelper(this);
33 | new LoadAppsInfoTask().execute();
34 | if (mSettingsHelper.getListType().equals("blacklist"))
35 | getActionBar().setTitle(R.string.pref_blacklist_title);
36 | else
37 | getActionBar().setTitle(R.string.pref_whitelist_title);
38 | getActionBar().setDisplayHomeAsUpEnabled(true);
39 | }
40 |
41 | @Override
42 | public boolean onOptionsItemSelected(MenuItem item) {
43 | if (item.getItemId() == android.R.id.home)
44 | onBackPressed();
45 | return true;
46 | }
47 |
48 | private static class AppInfo {
49 | String title;
50 | String summary;
51 | Drawable icon;
52 | boolean enabled;
53 | }
54 |
55 | private List loadApps(ProgressDialog dialog) {
56 | PackageManager packageManager = getPackageManager();
57 | List packages = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
58 | List apps = new ArrayList();
59 |
60 | dialog.setMax(packages.size());
61 | int i = 1;
62 |
63 | for (ApplicationInfo app : packages) {
64 | AppInfo appInfo = new AppInfo();
65 | appInfo.title = (String) app.loadLabel(packageManager);
66 | appInfo.summary = app.packageName;
67 | appInfo.icon = app.loadIcon(packageManager);
68 | appInfo.enabled = mSettingsHelper.isListed(app.packageName);
69 | apps.add(appInfo);
70 | dialog.setProgress(i++);
71 | }
72 |
73 | Collections.sort(apps, new Comparator() {
74 | @Override
75 | public int compare(AppInfo appInfo1, AppInfo appinfo2) {
76 | return appInfo1.title.compareToIgnoreCase(appinfo2.title);
77 | }
78 | });
79 |
80 | return apps;
81 | }
82 |
83 | private static class BlacklistAdapter extends ArrayAdapter {
84 | LayoutInflater mInflater;
85 |
86 | public BlacklistAdapter(Context context, List items) {
87 | super(context, 0, items);
88 | mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
89 | }
90 |
91 | private static class Holder {
92 | ImageView icon;
93 | TextView title;
94 | TextView summary;
95 | CheckBox checkbox;
96 | }
97 |
98 | @Override
99 | public View getView(int position, View convertView, ViewGroup parent) {
100 | final Holder holder;
101 | final AppInfo item = getItem(position);
102 | View view;
103 |
104 | if (convertView == null) {
105 | holder = new Holder();
106 | view = mInflater.inflate(R.layout.blacklist_item, parent, false);
107 | holder.icon = (ImageView) view.findViewById(R.id.icon);
108 | holder.title = (TextView) view.findViewById(android.R.id.title);
109 | holder.summary = (TextView) view.findViewById(android.R.id.summary);
110 | holder.checkbox = (CheckBox) view.findViewById(R.id.checkbox);
111 | view.setTag(holder);
112 | } else {
113 | view = convertView;
114 | holder = (Holder) view.getTag();
115 | }
116 |
117 | holder.title.setText(item.title);
118 | holder.summary.setText(item.summary);
119 | holder.icon.setImageDrawable(item.icon);
120 |
121 | holder.checkbox.setChecked(item.enabled);
122 | holder.checkbox.setOnClickListener(new View.OnClickListener() {
123 | @Override
124 | public void onClick(View v) {
125 | item.enabled = holder.checkbox.isChecked();
126 | if (holder.checkbox.isChecked()) {
127 | mSettingsHelper.addListItem(item.summary);
128 | } else {
129 | mSettingsHelper.removeListItem(item.summary);
130 | }
131 | }
132 | });
133 |
134 | return view;
135 | }
136 |
137 | }
138 |
139 | private class LoadAppsInfoTask extends AsyncTask {
140 | ProgressDialog dialog;
141 | List appInfos;
142 |
143 | @Override
144 | protected void onPreExecute() {
145 | dialog = new ProgressDialog(Blacklist.this);
146 | dialog.setMessage(getString(R.string.loading));
147 | dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
148 | dialog.setCancelable(false);
149 | dialog.show();
150 | }
151 |
152 | @Override
153 | protected Void doInBackground(Void... params) {
154 | appInfos = loadApps(dialog);
155 | return null;
156 | }
157 |
158 | @Override
159 | protected void onProgressUpdate(Void... progress) {
160 | mAdapter.notifyDataSetChanged();
161 | }
162 |
163 | @Override
164 | protected void onPostExecute(Void void_) {
165 | super.onPostExecute(void_);
166 | mAdapter = new BlacklistAdapter(Blacklist.this, appInfos);
167 | setListAdapter(mAdapter);
168 | dialog.dismiss();
169 | }
170 |
171 | }
172 |
173 | }
174 |
--------------------------------------------------------------------------------
/src/com/mohammadag/headsupenabler/XposedMod.java:
--------------------------------------------------------------------------------
1 | package com.mohammadag.headsupenabler;
2 |
3 | import static de.robv.android.xposed.XposedHelpers.callMethod;
4 | import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
5 | import static de.robv.android.xposed.XposedHelpers.findClass;
6 | import static de.robv.android.xposed.XposedHelpers.getAdditionalInstanceField;
7 | import static de.robv.android.xposed.XposedHelpers.getBooleanField;
8 | import static de.robv.android.xposed.XposedHelpers.getObjectField;
9 | import static de.robv.android.xposed.XposedHelpers.setAdditionalInstanceField;
10 | import static de.robv.android.xposed.XposedHelpers.setBooleanField;
11 | import static de.robv.android.xposed.XposedHelpers.setObjectField;
12 | import static de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;
13 |
14 | import android.app.Notification;
15 | import android.content.Context;
16 | import android.content.res.XModuleResources;
17 | import android.graphics.PixelFormat;
18 | import android.os.PowerManager;
19 | import android.app.KeyguardManager;
20 | import android.service.notification.StatusBarNotification;
21 | import android.view.Gravity;
22 | import android.view.MotionEvent;
23 | import android.view.View;
24 | import android.view.WindowManager;
25 |
26 | import de.robv.android.xposed.IXposedHookInitPackageResources;
27 | import de.robv.android.xposed.IXposedHookLoadPackage;
28 | import de.robv.android.xposed.IXposedHookZygoteInit;
29 | import de.robv.android.xposed.XC_MethodHook;
30 | import de.robv.android.xposed.XC_MethodReplacement;
31 | import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
32 |
33 | public class XposedMod implements IXposedHookLoadPackage, IXposedHookInitPackageResources, IXposedHookZygoteInit {
34 | private static SettingsHelper mSettingsHelper;
35 | private static String MODULE_PATH;
36 | private int mStatusBarVisibility;
37 |
38 | @Override
39 | public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
40 | if (!lpparam.packageName.equals("com.android.systemui")) {
41 | return;
42 | }
43 |
44 | if (mSettingsHelper == null) {
45 | mSettingsHelper = new SettingsHelper();
46 | }
47 |
48 | /*
49 | * Determine when to show a Heads Up notification.
50 | */
51 | Class> BaseStatusBar = findClass("com.android.systemui.statusbar.BaseStatusBar", lpparam.classLoader);
52 | findAndHookMethod(BaseStatusBar, "shouldInterrupt", StatusBarNotification.class,
53 | new XC_MethodReplacement() {
54 | @Override
55 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
56 | StatusBarNotification n = (StatusBarNotification) param.args[0];
57 | mSettingsHelper.reload();
58 | PowerManager powerManager = (PowerManager) getObjectField(param.thisObject, "mPowerManager");
59 | // mKeyguardManager missing in OmniRom
60 | //KeyguardManager keyguardManager = (KeyguardManager) getObjectField(param.thisObject, "mKeyguardManager");
61 | Context ctx = (Context) getObjectField(param.thisObject, "mContext");
62 | KeyguardManager keyguardManager = (KeyguardManager) ctx.getSystemService(Context.KEYGUARD_SERVICE);
63 | // Ignore if the notification is ongoing and we haven't enabled that in the settings
64 | return !(n.isOngoing() && !mSettingsHelper.isEnabledForOngoingNotifications())
65 | // Ignore if we're not in a fullscreen app and the "only when fullscreen" setting is
66 | // enabled
67 | && !(!((mStatusBarVisibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == View.SYSTEM_UI_FLAG_FULLSCREEN)
68 | && mSettingsHelper.isEnabledOnlyWhenFullscreen())
69 | // Ignore if phone is locked and the "only when unlocked" setting is enabled
70 | && !(keyguardManager.isKeyguardLocked() && mSettingsHelper.isEnabledOnlyWhenUnlocked())
71 | // Screen must be on
72 | && powerManager.isScreenOn()
73 | // Ignore blacklisted/non whitelisted packages
74 | && !mSettingsHelper.isListed(n.getPackageName())
75 | // Check if low priority
76 | && !(mSettingsHelper.isDisabledForLowPriority()
77 | && !(n.getNotification().priority > Notification.PRIORITY_LOW));
78 | }
79 | }
80 | );
81 |
82 | /*
83 | * Stop breaking the normal notification ordering.
84 | * The current AOSP implementation considers the interruption state (= has it been shown to the user using a
85 | * Heads Up?) more important than the notification's score when comparing notifications (to set the order).
86 | * This breaks the normal order of notifications, so we're nuking the method that sets the interruption state.
87 | */
88 | Class> NotificationDataEntry = findClass("com.android.systemui.statusbar.NotificationData$Entry",
89 | lpparam.classLoader);
90 | findAndHookMethod(NotificationDataEntry, "setInterruption", XC_MethodReplacement.DO_NOTHING);
91 |
92 | /*
93 | * Enable one handed expansion for the Heads Up view.
94 | */
95 | Class> HeadsUpNotificationView = findClass("com.android.systemui.statusbar.policy.HeadsUpNotificationView",
96 | lpparam.classLoader);
97 | findAndHookMethod(HeadsUpNotificationView, "onAttachedToWindow", new XC_MethodHook() {
98 | @Override
99 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
100 | setAdditionalInstanceField(getObjectField(param.thisObject, "mExpandHelper"), "headsUp", true);
101 | }
102 | });
103 |
104 | Class> ExpandHelper = findClass("com.android.systemui.ExpandHelper", lpparam.classLoader);
105 | findAndHookMethod(ExpandHelper, "onInterceptTouchEvent", MotionEvent.class, new XC_MethodHook() {
106 | @Override
107 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
108 | int action = ((MotionEvent) param.args[0]).getAction();
109 | Object headsUp = getAdditionalInstanceField(param.thisObject, "headsUp");
110 | if (headsUp != null && (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
111 | setObjectField(param.thisObject, "mWatchingForPull", true);
112 | }
113 | }
114 | });
115 |
116 | /*
117 | * Monitor status bar visibility changes.
118 | */
119 | Class> PhoneStatusBar = findClass("com.android.systemui.statusbar.phone.PhoneStatusBar", lpparam.classLoader);
120 | findAndHookMethod(PhoneStatusBar, "setSystemUiVisibility", int.class, int.class, new XC_MethodHook() {
121 | @Override
122 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
123 | mStatusBarVisibility = (Integer) param.args[0];
124 | }
125 | });
126 |
127 | /*
128 | * Make the Heads Up notification show on top of the status bar by setting the y position to 0.
129 | * It could allow for other changes (e.g. change the gravity) in the future as well.
130 | */
131 | findAndHookMethod(PhoneStatusBar, "addHeadsUpView", new XC_MethodReplacement() {
132 | @Override
133 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
134 | Context context = (Context) getObjectField(param.thisObject, "mContext");
135 | WindowManager windowManager = (WindowManager) getObjectField(param.thisObject, "mWindowManager");
136 | View headsUpNotificationView = (View) getObjectField(param.thisObject, "mHeadsUpNotificationView");
137 | int animation = context.getResources().getIdentifier("Animation_StatusBar_HeadsUp", "style",
138 | "com.android.systemui");
139 |
140 | WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
141 | WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT,
142 | WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, // above the status bar!
143 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
144 | | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
145 | | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
146 | | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
147 | | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
148 | | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,
149 | PixelFormat.TRANSLUCENT
150 | );
151 | lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
152 | lp.gravity = Gravity.TOP;
153 | if (mSettingsHelper.shouldRemovePadding())
154 | lp.y = 0;
155 | else
156 | lp.y = (Integer) callMethod(param.thisObject, "getStatusBarHeight");
157 | lp.setTitle("Heads Up");
158 | lp.packageName = context.getPackageName();
159 | lp.windowAnimations = animation;
160 |
161 | windowManager.addView(headsUpNotificationView, lp);
162 | return null;
163 | }
164 | });
165 |
166 | /*
167 | * Enable Heads Up on startup.
168 | */
169 | findAndHookMethod(PhoneStatusBar, "start", new XC_MethodHook() {
170 | @Override
171 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
172 | if (!getBooleanField(param.thisObject, "mUseHeadsUp")) {
173 | setBooleanField(param.thisObject, "mUseHeadsUp", true);
174 | callMethod(param.thisObject, "addHeadsUpView");
175 | }
176 | }
177 | });
178 |
179 | }
180 |
181 | @Override
182 | public void initZygote(StartupParam startupParam) throws Throwable {
183 | MODULE_PATH = startupParam.modulePath;
184 | }
185 |
186 | @Override
187 | public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
188 | if (!resparam.packageName.equals("com.android.systemui"))
189 | return;
190 |
191 | if (mSettingsHelper == null) {
192 | mSettingsHelper = new SettingsHelper();
193 | }
194 |
195 |
196 | // Set the delay before the Heads Up notification is hidden.
197 | resparam.res.setReplacement("com.android.systemui", "integer", "heads_up_notification_decay",
198 | mSettingsHelper.getHeadsUpNotificationDecay());
199 |
200 | // Replace the Heads Up notification's background to remove the padding.
201 | if (mSettingsHelper.shouldRemovePadding()) {
202 | XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, resparam.res);
203 | resparam.res.setReplacement("com.android.systemui", "drawable", "heads_up_window_bg",
204 | modRes.fwd(R.drawable.heads_up_window_bg));
205 | }
206 | }
207 |
208 | }
209 |
--------------------------------------------------------------------------------