├── .gitignore ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── libs │ └── lite-orm-1.9.2.jar ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── cn │ │ └── gavinliu │ │ └── notificationbox │ │ ├── NotificationBoxApp.java │ │ ├── model │ │ ├── AppInfo.java │ │ ├── ModelSource.java │ │ └── NotificationInfo.java │ │ ├── service │ │ └── NotificationListenerService.java │ │ ├── ui │ │ ├── BasePresenter.java │ │ ├── BaseView.java │ │ ├── applist │ │ │ ├── AppListActivity.java │ │ │ ├── AppListContract.java │ │ │ ├── AppListFragment.java │ │ │ └── AppListPresenter.java │ │ ├── detail │ │ │ ├── DetailActivity.java │ │ │ ├── DetailContract.java │ │ │ ├── DetailFragment.java │ │ │ └── DetailPresenter.java │ │ ├── main │ │ │ ├── MainActivity.java │ │ │ ├── MainContract.java │ │ │ ├── MainFragment.java │ │ │ └── MainPresenter.java │ │ ├── setting │ │ │ ├── SettingActivity.java │ │ │ └── SettingFragment.java │ │ └── welcome │ │ │ └── WelcomeActivity.java │ │ ├── utils │ │ ├── CommonUtils.java │ │ ├── DbUtils.java │ │ ├── PackageUtils.java │ │ └── SettingUtils.java │ │ └── widget │ │ ├── BaseActivity.java │ │ ├── BaseFragment.java │ │ ├── BaseListFragment.java │ │ └── BaseViewHolder.java │ └── res │ ├── drawable-xhdpi │ └── ic_add_white_24dp.png │ ├── drawable-xxhdpi │ ├── ic_add_white_24dp.png │ └── ic_navigate_next_black_24dp.png │ ├── drawable-xxxhdpi │ └── ic_add_white_24dp.png │ ├── layout │ ├── activity_applist.xml │ ├── activity_main.xml │ ├── activity_setting.xml │ ├── fragment_main.xml │ ├── item_applist.xml │ ├── item_detail.xml │ ├── item_main.xml │ ├── nb_base_list_fragment.xml │ ├── nb_empty_view.xml │ ├── nb_preference_screen.xml │ └── nb_progress_view.xml │ ├── menu │ └── menu_main.xml │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-zh-rCN │ └── strings.xml │ ├── values-zh-rHK │ └── strings.xml │ ├── values │ ├── colors.xml │ ├── dimens.xml │ ├── ids.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── setting.xml ├── build.gradle ├── screenshots.png └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | #Android generated 2 | bin 3 | gen 4 | gen* 5 | 6 | #Eclipse 7 | .project 8 | .classpath 9 | .settings 10 | 11 | #IntelliJ IDEA 12 | .idea 13 | *.iml 14 | *.ipr 15 | *.iws 16 | out 17 | 18 | #Maven 19 | target 20 | release.properties 21 | pom.xml.* 22 | 23 | #Ant 24 | build.xml 25 | local.properties 26 | proguard.cfg 27 | 28 | #Gradle 29 | .gradle 30 | build 31 | gradle.properties 32 | gradle/ 33 | gradlew 34 | gradlew.bat 35 | 36 | #OSX 37 | .DS_Store 38 | 39 | #Personal Files 40 | signing. 41 | 42 | # Built application files 43 | *.apk 44 | *.ap_ 45 | 46 | # Files for the Dalvik VM 47 | *.dex 48 | 49 | # Java class files 50 | *.class 51 | 52 | # Generated files 53 | bin/ 54 | gen/ 55 | 56 | # Gradle files 57 | .gradle/ 58 | build/ 59 | 60 | # Local configuration file (sdk path, etc) 61 | local.properties 62 | 63 | # Proguard folder generated by Eclipse 64 | proguard/ 65 | 66 | # Log Files 67 | *.log 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Liu Yunlong 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NotificationBox 2 | 3 | ![](app/src/main/res/mipmap-xxxhdpi/ic_launcher.png) 4 | 5 | ![](screenshots.png) 6 | 7 | ## Download 8 | 9 | - [Github Release](https://github.com/gavinliu/NotificationBox/releases) 10 | 11 | ## Features 12 | 13 | * Block notification 14 | * Notification history list 15 | * Support android device 19+ 16 | 17 | ## Todo 18 | 19 | * Save ``PendingIntent`` (save notification action) 20 | 21 | ## Acknowledgements 22 | 23 | - [RxAndroid](https://github.com/ReactiveX/RxAndroid) 24 | - [LiteOrm](https://github.com/litesuits/android-lite-orm) 25 | - [android-architecture](https://github.com/googlesamples/android-architecture) 26 | 27 | ## License 28 | 29 | MIT 30 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | defaultConfig { 7 | applicationId "cn.gavinliu.notificationbox" 8 | minSdkVersion 19 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | compile 'com.android.support:appcompat-v7:24.2.1' 25 | compile 'com.android.support:preference-v7:24.2.1' 26 | compile 'com.android.support:recyclerview-v7:24.2.1' 27 | compile 'com.android.support:design:24.2.1' 28 | 29 | compile 'io.reactivex:rxandroid:1.2.1' 30 | compile 'io.reactivex:rxjava:1.1.6' 31 | } 32 | -------------------------------------------------------------------------------- /app/libs/lite-orm-1.9.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/libs/lite-orm-1.9.2.jar -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/Gavin/Develop/android-sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 12 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 40 | 41 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/NotificationBoxApp.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.litesuits.orm.LiteOrm; 7 | 8 | /** 9 | * Created by Gavin on 2016/10/11. 10 | */ 11 | 12 | public class NotificationBoxApp extends Application { 13 | 14 | private static Context sAppContext; 15 | 16 | private volatile static LiteOrm sLiteOrm; 17 | 18 | @Override 19 | protected void attachBaseContext(Context base) { 20 | super.attachBaseContext(base); 21 | sAppContext = base; 22 | } 23 | 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | } 28 | 29 | public static Context get() { 30 | return sAppContext; 31 | } 32 | 33 | public static LiteOrm getLiteOrm() { 34 | if (sLiteOrm == null) { 35 | synchronized (NotificationBoxApp.class) { 36 | if (sLiteOrm == null) { 37 | sLiteOrm = LiteOrm.newSingleInstance(sAppContext, "box.db"); 38 | sLiteOrm.setDebugged(true); 39 | } 40 | } 41 | } 42 | return sLiteOrm; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/model/AppInfo.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.model; 2 | 3 | import android.graphics.drawable.Drawable; 4 | 5 | import com.litesuits.orm.db.annotation.Column; 6 | import com.litesuits.orm.db.annotation.Ignore; 7 | import com.litesuits.orm.db.annotation.NotNull; 8 | import com.litesuits.orm.db.annotation.PrimaryKey; 9 | import com.litesuits.orm.db.annotation.Table; 10 | import com.litesuits.orm.db.enums.AssignType; 11 | 12 | /** 13 | * Created by Gavin on 2016/10/11. 14 | */ 15 | @Table("apps") 16 | public class AppInfo { 17 | 18 | @PrimaryKey(AssignType.AUTO_INCREMENT) 19 | @Column("_id") 20 | private int id; 21 | 22 | @NotNull 23 | private String packageName; 24 | 25 | @NotNull 26 | private String appName; 27 | 28 | @Ignore 29 | private Drawable icon; 30 | 31 | @Ignore 32 | private boolean isSelect; 33 | 34 | public int getId() { 35 | return id; 36 | } 37 | 38 | public void setId(int id) { 39 | this.id = id; 40 | } 41 | 42 | public String getPackageName() { 43 | return packageName; 44 | } 45 | 46 | public void setPackageName(String packageName) { 47 | this.packageName = packageName; 48 | } 49 | 50 | public String getAppName() { 51 | return appName; 52 | } 53 | 54 | public void setAppName(String appName) { 55 | this.appName = appName; 56 | } 57 | 58 | public Drawable getIcon() { 59 | return icon; 60 | } 61 | 62 | public void setIcon(Drawable icon) { 63 | this.icon = icon; 64 | } 65 | 66 | public boolean isSelect() { 67 | return isSelect; 68 | } 69 | 70 | public void setSelect(boolean select) { 71 | isSelect = select; 72 | } 73 | 74 | @Override 75 | public boolean equals(Object obj) { 76 | if (obj instanceof AppInfo) { 77 | AppInfo o = (AppInfo) obj; 78 | if (o.getPackageName().equals(packageName)) { 79 | return true; 80 | } else { 81 | return false; 82 | } 83 | } 84 | 85 | return super.equals(obj); 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return super.hashCode() + packageName.hashCode(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/model/ModelSource.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.model; 2 | 3 | /** 4 | * Created by Gavin on 2016/10/13. 5 | */ 6 | 7 | public class ModelSource { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/model/NotificationInfo.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.model; 2 | 3 | import android.content.Intent; 4 | 5 | import com.litesuits.orm.db.annotation.Column; 6 | import com.litesuits.orm.db.annotation.Ignore; 7 | import com.litesuits.orm.db.annotation.NotNull; 8 | import com.litesuits.orm.db.annotation.PrimaryKey; 9 | import com.litesuits.orm.db.annotation.Table; 10 | import com.litesuits.orm.db.enums.AssignType; 11 | 12 | /** 13 | * Created by Gavin on 2016/10/11. 14 | */ 15 | @Table("notifications") 16 | public class NotificationInfo { 17 | 18 | @PrimaryKey(AssignType.AUTO_INCREMENT) 19 | @Column("_id") 20 | private int id; 21 | 22 | @NotNull 23 | private String packageName; 24 | 25 | private String title; 26 | 27 | private String text; 28 | 29 | private long time; 30 | 31 | @Ignore 32 | private Intent mIntent; 33 | 34 | public NotificationInfo(String packageName, String title, String text, long time) { 35 | this.packageName = packageName; 36 | this.title = title; 37 | this.text = text; 38 | this.time = time; 39 | } 40 | 41 | public int getId() { 42 | return id; 43 | } 44 | 45 | public void setId(int id) { 46 | this.id = id; 47 | } 48 | 49 | public String getPackageName() { 50 | return packageName; 51 | } 52 | 53 | public void setPackageName(String packageName) { 54 | this.packageName = packageName; 55 | } 56 | 57 | public String getTitle() { 58 | return title; 59 | } 60 | 61 | public void setTitle(String title) { 62 | this.title = title; 63 | } 64 | 65 | public String getText() { 66 | return text; 67 | } 68 | 69 | public void setText(String text) { 70 | this.text = text; 71 | } 72 | 73 | public long getTime() { 74 | return time; 75 | } 76 | 77 | public void setTime(long time) { 78 | this.time = time; 79 | } 80 | 81 | public Intent getIntent() { 82 | return mIntent; 83 | } 84 | 85 | public void setIntent(Intent intent) { 86 | mIntent = intent; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/service/NotificationListenerService.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.service; 2 | 3 | import android.app.Notification; 4 | import android.app.NotificationManager; 5 | import android.app.PendingIntent; 6 | import android.content.Intent; 7 | import android.os.Build; 8 | import android.os.IBinder; 9 | import android.service.notification.StatusBarNotification; 10 | import android.util.Log; 11 | import android.widget.Toast; 12 | 13 | import java.util.List; 14 | 15 | import cn.gavinliu.notificationbox.NotificationBoxApp; 16 | import cn.gavinliu.notificationbox.R; 17 | import cn.gavinliu.notificationbox.model.AppInfo; 18 | import cn.gavinliu.notificationbox.model.NotificationInfo; 19 | import cn.gavinliu.notificationbox.ui.detail.DetailActivity; 20 | import cn.gavinliu.notificationbox.utils.DbUtils; 21 | import cn.gavinliu.notificationbox.utils.SettingUtils; 22 | 23 | /** 24 | * Created by Gavin on 2016/10/11. 25 | */ 26 | 27 | public class NotificationListenerService extends android.service.notification.NotificationListenerService { 28 | 29 | private static final String TAG = "NLS"; 30 | 31 | @Override 32 | public IBinder onBind(Intent intent) { 33 | Log.d(TAG, "onBind"); 34 | return super.onBind(intent); 35 | } 36 | 37 | @Override 38 | public boolean onUnbind(Intent intent) { 39 | Log.d(TAG, "onUnbind"); 40 | return super.onUnbind(intent); 41 | } 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | Log.d(TAG, "onCreate"); 47 | } 48 | 49 | @Override 50 | public void onDestroy() { 51 | super.onDestroy(); 52 | Log.d(TAG, "onDestroy"); 53 | } 54 | 55 | @Override 56 | public int onStartCommand(Intent intent, int flags, int startId) { 57 | Log.d(TAG, "onStartCommand"); 58 | return super.onStartCommand(intent, flags, startId); 59 | } 60 | 61 | @Override 62 | public void onNotificationPosted(StatusBarNotification sbn) { 63 | super.onNotificationPosted(sbn); 64 | Log.d(TAG, "onNotificationPosted"); 65 | 66 | Notification notification = sbn.getNotification(); 67 | 68 | String packageName = sbn.getPackageName(); 69 | long time = sbn.getPostTime(); 70 | String title = notification.extras.getString(Notification.EXTRA_TITLE); 71 | String text = notification.extras.getString(Notification.EXTRA_TEXT); 72 | 73 | DbUtils.saveNotification(new NotificationInfo(packageName, title, text, time)); 74 | List blackList = DbUtils.getApp(); 75 | 76 | for (AppInfo app : blackList) { 77 | if (packageName.equals(app.getPackageName())) { 78 | Log.d(TAG, packageName + " 拦截:" + title + ": " + text); 79 | 80 | if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT_WATCH) { 81 | cancelNotification(sbn.getKey()); 82 | } else { 83 | cancelNotification(sbn.getPackageName(), sbn.getTag(), sbn.getId()); 84 | } 85 | 86 | if (SettingUtils.getInstance().isNotify()) { 87 | createNotification(app.getAppName(), packageName, title, text); 88 | } 89 | } 90 | } 91 | } 92 | 93 | @Override 94 | public void onNotificationRemoved(StatusBarNotification sbn) { 95 | super.onNotificationRemoved(sbn); 96 | } 97 | 98 | private void createNotification(String appName, String packageName, String title, String text) { 99 | 100 | Intent intent = new Intent(this, DetailActivity.class); 101 | intent.putExtra("appName", appName); 102 | intent.putExtra("packageName", packageName); 103 | 104 | PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); 105 | 106 | Notification.Builder notifyBuilder = new Notification.Builder(this) 107 | .setSmallIcon(R.mipmap.ic_launcher) 108 | .setWhen(System.currentTimeMillis()) 109 | .setContentTitle(getResources().getString(R.string.notify_blocking, appName)) 110 | .setContentText(title + ": " + text) 111 | .setContentIntent(contentIntent) 112 | .setDefaults(Notification.DEFAULT_LIGHTS); 113 | 114 | NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 115 | 116 | Notification notification = notifyBuilder.build(); 117 | notification.flags |= Notification.FLAG_AUTO_CANCEL; 118 | 119 | nm.notify(R.string.app_name, notification); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/BasePresenter.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui; 2 | 3 | /** 4 | * Created by Gavin on 2016/10/11. 5 | */ 6 | 7 | public interface BasePresenter { 8 | 9 | void start(); 10 | 11 | void subscribe(); 12 | 13 | void unsubscribe(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/BaseView.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui; 2 | 3 | /** 4 | * Created by Gavin on 2016/10/11. 5 | */ 6 | 7 | public interface BaseView { 8 | 9 | void setPresenter(T presenter); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/applist/AppListActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.applist; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import cn.gavinliu.notificationbox.R; 8 | 9 | /** 10 | * Created by Gavin on 16-10-17. 11 | */ 12 | 13 | public class AppListActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(@Nullable Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_applist); 19 | 20 | AppListFragment appListFragment = (AppListFragment) getSupportFragmentManager() 21 | .findFragmentById(R.id.fragment_applist); 22 | 23 | if (appListFragment == null) { 24 | appListFragment = AppListFragment.newInstance(); 25 | 26 | getSupportFragmentManager().beginTransaction() 27 | .add(R.id.content, appListFragment) 28 | .commit(); 29 | } 30 | 31 | new AppListPresenter(appListFragment); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/applist/AppListContract.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.applist; 2 | 3 | import android.content.pm.PackageManager; 4 | 5 | import java.util.List; 6 | 7 | import cn.gavinliu.notificationbox.model.AppInfo; 8 | import cn.gavinliu.notificationbox.ui.BasePresenter; 9 | import cn.gavinliu.notificationbox.ui.BaseView; 10 | 11 | /** 12 | * Created by Gavin on 16-10-17. 13 | */ 14 | 15 | public interface AppListContract { 16 | 17 | interface Presenter extends BasePresenter { 18 | 19 | void startLoad(PackageManager pm); 20 | 21 | void saveApp(AppInfo app); 22 | 23 | void deleteApp(AppInfo app); 24 | } 25 | 26 | interface View extends BaseView { 27 | 28 | void showProgress(boolean isShown); 29 | 30 | void showAppList(List appList); 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/applist/AppListFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.applist; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.CheckBox; 12 | import android.widget.ImageView; 13 | import android.widget.TextView; 14 | 15 | import java.util.List; 16 | 17 | import cn.gavinliu.notificationbox.R; 18 | import cn.gavinliu.notificationbox.model.AppInfo; 19 | import cn.gavinliu.notificationbox.widget.BaseListFragment; 20 | import cn.gavinliu.notificationbox.widget.BaseViewHolder; 21 | 22 | /** 23 | * Created by Gavin on 16-10-17. 24 | */ 25 | 26 | public class AppListFragment extends BaseListFragment implements AppListContract.View { 27 | 28 | public static AppListFragment newInstance() { 29 | AppListFragment fragment = new AppListFragment(); 30 | return fragment; 31 | } 32 | 33 | private AppListContract.Presenter mPresenter; 34 | 35 | @Override 36 | public void setPresenter(AppListContract.Presenter presenter) { 37 | mPresenter = presenter; 38 | } 39 | 40 | @Override 41 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 42 | super.onActivityCreated(savedInstanceState); 43 | if (mPresenter != null) mPresenter.startLoad(getActivity().getPackageManager()); 44 | } 45 | 46 | @Override 47 | public void setupActionBar(ActionBar actionBar) { 48 | actionBar.setDisplayHomeAsUpEnabled(true); 49 | } 50 | 51 | @Override 52 | public void onDestroy() { 53 | super.onDestroy(); 54 | if (mPresenter != null) mPresenter.unsubscribe(); 55 | getActivity().setResult(0); 56 | } 57 | 58 | @Override 59 | public void showProgress(boolean isShown) { 60 | if (isShown) { 61 | showProgressView(); 62 | } else { 63 | hideProgressView(); 64 | } 65 | } 66 | 67 | @Override 68 | public void showAppList(List appList) { 69 | mRecyclerView.setAdapter(new Adapter(getContext(), appList, mItemListener)); 70 | } 71 | 72 | private ItemListener mItemListener = new ItemListener() { 73 | @Override 74 | public void onCheckBoxSelect(boolean isChecked, AppInfo app) { 75 | if (isChecked) { 76 | mPresenter.saveApp(app); 77 | } else { 78 | mPresenter.deleteApp(app); 79 | } 80 | } 81 | }; 82 | 83 | private static class Adapter extends RecyclerView.Adapter { 84 | 85 | Context context; 86 | List appList; 87 | private ItemListener itemListener; 88 | 89 | public Adapter(Context context, List appList, ItemListener itemListener) { 90 | this.context = context; 91 | this.appList = appList; 92 | this.itemListener = itemListener; 93 | } 94 | 95 | @Override 96 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 97 | return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_applist, parent, false)); 98 | } 99 | 100 | @Override 101 | public void onBindViewHolder(ViewHolder holder, int position) { 102 | final AppInfo app = appList.get(position); 103 | 104 | holder.mIconView.setImageDrawable(app.getIcon()); 105 | holder.mNameView.setText(app.getAppName()); 106 | holder.mCheckBox.setChecked(app.isSelect()); 107 | 108 | holder.mCheckBox.setOnClickListener(new View.OnClickListener() { 109 | @Override 110 | public void onClick(View v) { 111 | boolean isChecked = ((CheckBox) v).isChecked(); 112 | app.setSelect(isChecked); 113 | itemListener.onCheckBoxSelect(isChecked, app); 114 | } 115 | }); 116 | } 117 | 118 | @Override 119 | public int getItemCount() { 120 | return appList != null ? appList.size() : 0; 121 | } 122 | } 123 | 124 | private static class ViewHolder extends BaseViewHolder { 125 | 126 | private ImageView mIconView; 127 | private TextView mNameView; 128 | private CheckBox mCheckBox; 129 | 130 | 131 | public ViewHolder(View itemView) { 132 | super(itemView); 133 | 134 | mIconView = (ImageView) itemView.findViewById(R.id.icon); 135 | mNameView = (TextView) itemView.findViewById(R.id.name); 136 | mCheckBox = (CheckBox) itemView.findViewById(R.id.checkbox); 137 | } 138 | } 139 | 140 | private interface ItemListener { 141 | void onCheckBoxSelect(boolean isChecked, AppInfo app); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/applist/AppListPresenter.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.applist; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.PackageManager; 5 | 6 | import java.util.List; 7 | 8 | import cn.gavinliu.notificationbox.model.AppInfo; 9 | import cn.gavinliu.notificationbox.utils.DbUtils; 10 | import cn.gavinliu.notificationbox.utils.PackageUtils; 11 | import rx.Observable; 12 | import rx.Observer; 13 | import rx.Scheduler; 14 | import rx.Subscriber; 15 | import rx.Subscription; 16 | import rx.android.schedulers.AndroidSchedulers; 17 | import rx.schedulers.Schedulers; 18 | import rx.subscriptions.CompositeSubscription; 19 | 20 | /** 21 | * Created by Gavin on 16-10-17. 22 | */ 23 | 24 | public class AppListPresenter implements AppListContract.Presenter { 25 | 26 | private AppListContract.View mView; 27 | 28 | private CompositeSubscription mSubscriptions; 29 | 30 | public AppListPresenter(AppListContract.View view) { 31 | mView = view; 32 | 33 | mSubscriptions = new CompositeSubscription(); 34 | mView.setPresenter(this); 35 | } 36 | 37 | @Override 38 | public void start() { 39 | 40 | } 41 | 42 | @Override 43 | public void startLoad(PackageManager pm) { 44 | mView.showProgress(true); 45 | Subscription subscription = PackageUtils.getInstallPackages(pm) 46 | .subscribeOn(Schedulers.io()) 47 | .observeOn(AndroidSchedulers.mainThread()) 48 | .subscribe(new Observer>() { 49 | @Override 50 | public void onCompleted() { 51 | 52 | } 53 | 54 | @Override 55 | public void onError(Throwable e) { 56 | 57 | } 58 | 59 | @Override 60 | public void onNext(List list) { 61 | mView.showProgress(false); 62 | mView.showAppList(list); 63 | } 64 | }); 65 | 66 | mSubscriptions.add(subscription); 67 | } 68 | 69 | @Override 70 | public void subscribe() { 71 | 72 | } 73 | 74 | @Override 75 | public void unsubscribe() { 76 | mSubscriptions.clear(); 77 | } 78 | 79 | 80 | @Override 81 | public void saveApp(AppInfo app) { 82 | DbUtils.saveApp(app); 83 | } 84 | 85 | @Override 86 | public void deleteApp(AppInfo app) { 87 | DbUtils.deleteApp(app); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/detail/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.detail; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.AppCompatActivity; 7 | 8 | import cn.gavinliu.notificationbox.R; 9 | 10 | /** 11 | * Created by Gavin on 2016/10/11. 12 | */ 13 | 14 | public class DetailActivity extends AppCompatActivity { 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_applist); 20 | 21 | DetailFragment detailFragment = (DetailFragment) getSupportFragmentManager() 22 | .findFragmentById(R.id.fragment_applist); 23 | 24 | if (detailFragment == null) { 25 | Intent intent = getIntent(); 26 | Bundle bundle = intent.getExtras(); 27 | detailFragment = DetailFragment.newInstance(bundle.getString("appName"), bundle.getString("packageName")); 28 | 29 | getSupportFragmentManager().beginTransaction() 30 | .add(R.id.content, detailFragment) 31 | .commit(); 32 | } 33 | 34 | new DetailPresenter(detailFragment); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/detail/DetailContract.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.detail; 2 | 3 | import java.util.List; 4 | 5 | import cn.gavinliu.notificationbox.model.NotificationInfo; 6 | import cn.gavinliu.notificationbox.ui.BasePresenter; 7 | import cn.gavinliu.notificationbox.ui.BaseView; 8 | 9 | /** 10 | * Created by Gavin on 16-10-17. 11 | */ 12 | 13 | public interface DetailContract { 14 | 15 | interface Presenter extends BasePresenter { 16 | 17 | void startLoad(String packageName); 18 | 19 | } 20 | 21 | interface View extends BaseView { 22 | 23 | void showProgress(boolean isShown); 24 | 25 | void showEmpty(); 26 | 27 | void showNotifications(List notifications); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/detail/DetailFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.detail; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.util.Log; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.TextView; 13 | 14 | import java.util.List; 15 | 16 | import cn.gavinliu.notificationbox.R; 17 | import cn.gavinliu.notificationbox.model.NotificationInfo; 18 | import cn.gavinliu.notificationbox.utils.CommonUtils; 19 | import cn.gavinliu.notificationbox.widget.BaseListFragment; 20 | import cn.gavinliu.notificationbox.widget.BaseViewHolder; 21 | 22 | /** 23 | * Created by Gavin on 2016/10/11. 24 | */ 25 | 26 | public class DetailFragment extends BaseListFragment implements DetailContract.View { 27 | 28 | DetailContract.Presenter mPresenter; 29 | 30 | private String mAppName; 31 | private String mPackageName; 32 | 33 | public static DetailFragment newInstance(String appName, String packageName) { 34 | if (appName == null || packageName == null) { 35 | throw new IllegalArgumentException("appName and packageName can not is null"); 36 | } 37 | 38 | Bundle args = new Bundle(); 39 | args.putString("appName", appName); 40 | args.putString("packageName", packageName); 41 | 42 | DetailFragment fragment = new DetailFragment(); 43 | fragment.setArguments(args); 44 | return fragment; 45 | } 46 | 47 | @Override 48 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 49 | super.onActivityCreated(savedInstanceState); 50 | if (mPresenter != null) mPresenter.startLoad(mPackageName); 51 | } 52 | 53 | @Override 54 | public void onDestroy() { 55 | super.onDestroy(); 56 | if (mPresenter != null) mPresenter.unsubscribe(); 57 | } 58 | 59 | @Override 60 | public void getArguments(Bundle bundle) { 61 | if (bundle != null) { 62 | mAppName = bundle.getString("appName"); 63 | mPackageName = bundle.getString("packageName"); 64 | } 65 | } 66 | 67 | @Override 68 | public void setupActionBar(ActionBar actionBar) { 69 | actionBar.setTitle(mAppName); 70 | actionBar.setDisplayHomeAsUpEnabled(true); 71 | } 72 | 73 | @Override 74 | public void showProgress(boolean isShown) { 75 | if (isShown) { 76 | showProgressView(); 77 | } else { 78 | hideProgressView(); 79 | } 80 | } 81 | 82 | @Override 83 | public void showEmpty() { 84 | hideProgressView(); 85 | showEmptyView(); 86 | setEmptyText(getText(R.string.empty_detail)); 87 | } 88 | 89 | @Override 90 | public void showNotifications(List notifications) { 91 | mRecyclerView.setAdapter(new Adapter(getContext(), notifications)); 92 | } 93 | 94 | @Override 95 | public void setPresenter(DetailContract.Presenter presenter) { 96 | mPresenter = presenter; 97 | } 98 | 99 | 100 | private static class Adapter extends RecyclerView.Adapter { 101 | 102 | Context context; 103 | List notificationList; 104 | 105 | public Adapter(Context context, List notificationList) { 106 | this.context = context; 107 | this.notificationList = notificationList; 108 | } 109 | 110 | @Override 111 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 112 | return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_detail, parent, false)); 113 | } 114 | 115 | @Override 116 | public void onBindViewHolder(ViewHolder holder, int position) { 117 | NotificationInfo notification = notificationList.get(position); 118 | holder.title.setText(notification.getTitle()); 119 | holder.text.setText(notification.getText()); 120 | holder.time.setText(CommonUtils.getTimeStr(notification.getTime())); 121 | } 122 | 123 | @Override 124 | public int getItemCount() { 125 | return notificationList != null ? notificationList.size() : 0; 126 | } 127 | } 128 | 129 | 130 | private static class ViewHolder extends BaseViewHolder { 131 | 132 | TextView title; 133 | TextView text; 134 | TextView time; 135 | 136 | public ViewHolder(View itemView) { 137 | super(itemView); 138 | title = (TextView) itemView.findViewById(R.id.title); 139 | text = (TextView) itemView.findViewById(R.id.text); 140 | time = (TextView) itemView.findViewById(R.id.time); 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/detail/DetailPresenter.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.detail; 2 | 3 | import java.util.List; 4 | 5 | import cn.gavinliu.notificationbox.model.NotificationInfo; 6 | import cn.gavinliu.notificationbox.utils.DbUtils; 7 | import rx.subscriptions.CompositeSubscription; 8 | 9 | /** 10 | * Created by Gavin on 16-10-17. 11 | */ 12 | 13 | public class DetailPresenter implements DetailContract.Presenter { 14 | 15 | DetailContract.View mView; 16 | 17 | private CompositeSubscription mSubscriptions; 18 | 19 | public DetailPresenter(DetailContract.View view) { 20 | mView = view; 21 | 22 | mSubscriptions = new CompositeSubscription(); 23 | mView.setPresenter(this); 24 | } 25 | 26 | @Override 27 | public void start() { 28 | 29 | } 30 | 31 | @Override 32 | public void startLoad(String packageName) { 33 | mView.showProgress(false); 34 | 35 | List infos = DbUtils.getNotification(packageName); 36 | 37 | if (infos == null || infos.size() == 0) { 38 | mView.showEmpty(); 39 | } else { 40 | mView.showNotifications(infos); 41 | } 42 | } 43 | 44 | @Override 45 | public void subscribe() { 46 | 47 | } 48 | 49 | @Override 50 | public void unsubscribe() { 51 | mSubscriptions.unsubscribe(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.main; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.design.widget.FloatingActionButton; 6 | import android.support.design.widget.Snackbar; 7 | import android.support.v4.app.Fragment; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.support.v7.widget.Toolbar; 10 | import android.view.Menu; 11 | import android.view.MenuItem; 12 | import android.view.View; 13 | 14 | import cn.gavinliu.notificationbox.R; 15 | import cn.gavinliu.notificationbox.service.NotificationListenerService; 16 | import cn.gavinliu.notificationbox.ui.setting.SettingActivity; 17 | import cn.gavinliu.notificationbox.utils.CommonUtils; 18 | 19 | public class MainActivity extends AppCompatActivity { 20 | 21 | FloatingActionButton mFloatingActionButton; 22 | private MainPresenter mMainPresenter; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | 29 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 30 | setSupportActionBar(toolbar); 31 | 32 | mFloatingActionButton = (FloatingActionButton) findViewById(R.id.fab); 33 | mFloatingActionButton.setOnClickListener(new View.OnClickListener() { 34 | @Override 35 | public void onClick(View view) { 36 | mMainPresenter.addApp(); 37 | } 38 | }); 39 | 40 | MainFragment mainFragment = (MainFragment) getSupportFragmentManager() 41 | .findFragmentById(R.id.fragment_main); 42 | 43 | if (mainFragment == null) { 44 | mainFragment = MainFragment.newInstance(); 45 | 46 | getSupportFragmentManager().beginTransaction() 47 | .add(R.id.content, mainFragment) 48 | .commit(); 49 | } 50 | 51 | mMainPresenter = new MainPresenter(mainFragment); 52 | } 53 | 54 | @Override 55 | protected void onResume() { 56 | super.onResume(); 57 | if (!CommonUtils.checkNotificationReadPermission(this)) { 58 | Snackbar.make(mFloatingActionButton, getText(R.string.no_read_notification_promission), Snackbar.LENGTH_INDEFINITE) 59 | .setAction(getText(R.string.action_settings), new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); 63 | startActivity(intent); 64 | } 65 | }) 66 | .show(); 67 | } 68 | } 69 | 70 | @Override 71 | public boolean onCreateOptionsMenu(Menu menu) { 72 | getMenuInflater().inflate(R.menu.menu_main, menu); 73 | return true; 74 | } 75 | 76 | @Override 77 | public boolean onOptionsItemSelected(MenuItem item) { 78 | int id = item.getItemId(); 79 | 80 | if (id == R.id.action_settings) { 81 | Intent intent = new Intent(this, SettingActivity.class); 82 | startActivity(intent); 83 | return true; 84 | } 85 | 86 | return super.onOptionsItemSelected(item); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/main/MainContract.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.main; 2 | 3 | import android.content.pm.PackageManager; 4 | 5 | import java.util.List; 6 | 7 | import cn.gavinliu.notificationbox.model.AppInfo; 8 | import cn.gavinliu.notificationbox.ui.BasePresenter; 9 | import cn.gavinliu.notificationbox.ui.BaseView; 10 | 11 | /** 12 | * Created by Gavin on 2016/10/11. 13 | */ 14 | 15 | public interface MainContract { 16 | 17 | interface Presenter extends BasePresenter { 18 | 19 | void addApp(); 20 | 21 | void openDetail(AppInfo app); 22 | 23 | void startLoad(PackageManager pm); 24 | } 25 | 26 | interface View extends BaseView { 27 | 28 | void showProgress(boolean isShown); 29 | 30 | void showEmpty(); 31 | 32 | void showApp(List apps); 33 | 34 | void showAppList(); 35 | 36 | void showDetail(String appName, String packageName); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/main/MainFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.main; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.annotation.Nullable; 7 | import android.support.v7.widget.RecyclerView; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import java.util.List; 15 | 16 | import cn.gavinliu.notificationbox.R; 17 | import cn.gavinliu.notificationbox.model.AppInfo; 18 | import cn.gavinliu.notificationbox.ui.applist.AppListActivity; 19 | import cn.gavinliu.notificationbox.ui.detail.DetailActivity; 20 | import cn.gavinliu.notificationbox.widget.BaseListFragment; 21 | import cn.gavinliu.notificationbox.widget.BaseViewHolder; 22 | 23 | /** 24 | * Created by Gavin on 2016/10/11. 25 | */ 26 | 27 | public class MainFragment extends BaseListFragment implements MainContract.View { 28 | 29 | MainContract.Presenter mPresenter; 30 | 31 | public static MainFragment newInstance() { 32 | Bundle args = new Bundle(); 33 | 34 | MainFragment fragment = new MainFragment(); 35 | fragment.setArguments(args); 36 | return fragment; 37 | } 38 | 39 | @Override 40 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 41 | super.onActivityCreated(savedInstanceState); 42 | if (mPresenter != null) mPresenter.startLoad(getActivity().getPackageManager()); 43 | } 44 | 45 | @Override 46 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 47 | super.onActivityResult(requestCode, resultCode, data); 48 | if (mPresenter != null) mPresenter.startLoad(getActivity().getPackageManager()); 49 | } 50 | 51 | @Override 52 | public void onDestroy() { 53 | super.onDestroy(); 54 | if (mPresenter != null) mPresenter.unsubscribe(); 55 | } 56 | 57 | @Override 58 | public void setPresenter(MainContract.Presenter presenter) { 59 | mPresenter = presenter; 60 | } 61 | 62 | @Override 63 | public void showProgress(boolean isShown) { 64 | if (isShown) { 65 | hideEmptyView(); 66 | showProgressView(); 67 | } else { 68 | hideProgressView(); 69 | } 70 | } 71 | 72 | @Override 73 | public void showEmpty() { 74 | hideProgressView(); 75 | showEmptyView(); 76 | showApp(null); 77 | setEmptyText(getText(R.string.empty_app)); 78 | } 79 | 80 | @Override 81 | public void showApp(List apps) { 82 | mRecyclerView.setAdapter(new Adapter(getContext(), apps, mItemListener)); 83 | } 84 | 85 | @Override 86 | public void showAppList() { 87 | Intent intent = new Intent(getContext(), AppListActivity.class); 88 | startActivityForResult(intent, 0); 89 | } 90 | 91 | @Override 92 | public void showDetail(String appName, String packageName) { 93 | Intent intent = new Intent(getContext(), DetailActivity.class); 94 | intent.putExtra("appName", appName); 95 | intent.putExtra("packageName", packageName); 96 | startActivity(intent); 97 | } 98 | 99 | private ItemListener mItemListener = new ItemListener() { 100 | @Override 101 | public void onItemClick(AppInfo app) { 102 | mPresenter.openDetail(app); 103 | } 104 | }; 105 | 106 | private static class Adapter extends RecyclerView.Adapter { 107 | 108 | Context context; 109 | List appList; 110 | ItemListener itemListener; 111 | 112 | public Adapter(Context context, List appList, ItemListener itemListener) { 113 | this.context = context; 114 | this.appList = appList; 115 | this.itemListener = itemListener; 116 | } 117 | 118 | @Override 119 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 120 | return new ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_main, parent, false)); 121 | } 122 | 123 | @Override 124 | public void onBindViewHolder(ViewHolder holder, int position) { 125 | final AppInfo app = appList.get(position); 126 | 127 | holder.mIconView.setImageDrawable(app.getIcon()); 128 | holder.mNameView.setText(app.getAppName()); 129 | 130 | holder.itemView.setOnClickListener(new View.OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | itemListener.onItemClick(app); 134 | } 135 | }); 136 | } 137 | 138 | @Override 139 | public int getItemCount() { 140 | return appList != null ? appList.size() : 0; 141 | } 142 | } 143 | 144 | private static class ViewHolder extends BaseViewHolder { 145 | 146 | private ImageView mIconView; 147 | private TextView mNameView; 148 | 149 | 150 | public ViewHolder(View itemView) { 151 | super(itemView); 152 | 153 | mIconView = (ImageView) itemView.findViewById(R.id.icon); 154 | mNameView = (TextView) itemView.findViewById(R.id.name); 155 | } 156 | } 157 | 158 | private interface ItemListener { 159 | void onItemClick(AppInfo app); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/main/MainPresenter.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.main; 2 | 3 | import android.content.pm.PackageManager; 4 | 5 | import java.util.List; 6 | 7 | import cn.gavinliu.notificationbox.model.AppInfo; 8 | import cn.gavinliu.notificationbox.utils.PackageUtils; 9 | import rx.Observer; 10 | import rx.Subscription; 11 | import rx.android.schedulers.AndroidSchedulers; 12 | import rx.schedulers.Schedulers; 13 | import rx.subscriptions.CompositeSubscription; 14 | 15 | /** 16 | * Created by Gavin on 2016/10/12. 17 | */ 18 | 19 | public class MainPresenter implements MainContract.Presenter { 20 | 21 | private MainContract.View mView; 22 | 23 | private CompositeSubscription mSubscriptions; 24 | 25 | public MainPresenter(MainContract.View view) { 26 | mView = view; 27 | 28 | mSubscriptions = new CompositeSubscription(); 29 | mView.setPresenter(this); 30 | } 31 | 32 | @Override 33 | public void start() { 34 | 35 | } 36 | 37 | @Override 38 | public void startLoad(PackageManager pm) { 39 | mView.showProgress(true); 40 | 41 | Subscription subscription = PackageUtils.getAppDbList(pm) 42 | .subscribeOn(Schedulers.io()) 43 | .observeOn(AndroidSchedulers.mainThread()) 44 | .subscribe(new Observer>() { 45 | @Override 46 | public void onCompleted() { 47 | 48 | } 49 | 50 | @Override 51 | public void onError(Throwable e) { 52 | 53 | } 54 | 55 | @Override 56 | public void onNext(List appInfos) { 57 | mView.showProgress(false); 58 | if (appInfos == null || appInfos.size() == 0) { 59 | mView.showEmpty(); 60 | } else { 61 | mView.showApp(appInfos); 62 | } 63 | 64 | } 65 | }); 66 | 67 | mSubscriptions.add(subscription); 68 | } 69 | 70 | @Override 71 | public void openDetail(AppInfo app) { 72 | mView.showDetail(app.getAppName(), app.getPackageName()); 73 | } 74 | 75 | @Override 76 | public void subscribe() { 77 | 78 | } 79 | 80 | @Override 81 | public void unsubscribe() { 82 | mSubscriptions.unsubscribe(); 83 | } 84 | 85 | @Override 86 | public void addApp() { 87 | mView.showAppList(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/setting/SettingActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.setting; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.MenuItem; 6 | 7 | import cn.gavinliu.notificationbox.R; 8 | import cn.gavinliu.notificationbox.widget.BaseActivity; 9 | 10 | /** 11 | * Created by Gavin on 2016/10/12. 12 | */ 13 | 14 | public class SettingActivity extends BaseActivity { 15 | 16 | @Override 17 | protected void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_setting); 20 | if (getSupportActionBar() != null) { 21 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 22 | } 23 | } 24 | 25 | @Override 26 | public boolean onOptionsItemSelected(MenuItem item) { 27 | switch (item.getItemId()) { 28 | case android.R.id.home: 29 | finish(); 30 | break; 31 | } 32 | return super.onOptionsItemSelected(item); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/setting/SettingFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.setting; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.support.v7.preference.Preference; 7 | import android.support.v7.preference.PreferenceFragmentCompat; 8 | 9 | import cn.gavinliu.notificationbox.R; 10 | 11 | /** 12 | * Created by Gavin on 2016/10/25. 13 | */ 14 | 15 | public class SettingFragment extends PreferenceFragmentCompat { 16 | 17 | @Override 18 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 19 | addPreferencesFromResource(R.xml.setting); 20 | } 21 | 22 | @Override 23 | public void onActivityCreated(Bundle savedInstanceState) { 24 | super.onActivityCreated(savedInstanceState); 25 | 26 | findPreference("permission").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 27 | @Override 28 | public boolean onPreferenceClick(Preference preference) { 29 | Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); 30 | startActivity(intent); 31 | return true; 32 | } 33 | }); 34 | 35 | findPreference("openSource").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 36 | @Override 37 | public boolean onPreferenceClick(Preference preference) { 38 | Intent intent = new Intent(); 39 | intent.setAction("android.intent.action.VIEW"); 40 | intent.setData(Uri.parse("https://github.com/gavinliu/NotificationBox")); 41 | startActivity(intent); 42 | return true; 43 | } 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/ui/welcome/WelcomeActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.ui.welcome; 2 | 3 | /** 4 | * Created by Gavin on 2016/10/11. 5 | */ 6 | 7 | public class WelcomeActivity { 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/utils/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.ComponentName; 5 | import android.provider.Settings; 6 | import android.text.TextUtils; 7 | 8 | import java.text.SimpleDateFormat; 9 | import java.util.Date; 10 | 11 | /** 12 | * Created by Gavin on 2016/10/12. 13 | */ 14 | 15 | public class CommonUtils { 16 | 17 | public static boolean checkNotificationReadPermission(Activity activity) { 18 | String notiStr = Settings.Secure.getString(activity.getContentResolver(), "enabled_notification_listeners"); 19 | if (notiStr != null && !TextUtils.isEmpty(notiStr)) { 20 | final String[] names = notiStr.split(":"); 21 | for (String name : names) { 22 | ComponentName cn = ComponentName.unflattenFromString(name); 23 | if (cn != null) { 24 | if (activity.getPackageName().equals(cn.getPackageName())) { 25 | return true; 26 | } 27 | } 28 | } 29 | } 30 | return false; 31 | } 32 | 33 | public static String getTimeStr(long time) { 34 | SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 35 | Date date = new Date(time); 36 | return format.format(date); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/utils/DbUtils.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.utils; 2 | 3 | import com.litesuits.orm.db.assit.QueryBuilder; 4 | import com.litesuits.orm.db.assit.WhereBuilder; 5 | 6 | import java.util.List; 7 | 8 | import cn.gavinliu.notificationbox.NotificationBoxApp; 9 | import cn.gavinliu.notificationbox.model.AppInfo; 10 | import cn.gavinliu.notificationbox.model.NotificationInfo; 11 | 12 | /** 13 | * Created by Gavin on 16-10-15. 14 | */ 15 | 16 | public class DbUtils { 17 | 18 | public static void saveNotification(NotificationInfo info) { 19 | if (info.getTitle() == null || info.getText() == null) return; 20 | NotificationBoxApp.getLiteOrm().save(info); 21 | } 22 | 23 | public static List getNotification(String packageName) { 24 | return NotificationBoxApp.getLiteOrm().query(new QueryBuilder(NotificationInfo.class) 25 | .where("packageName = ?", packageName).orderBy("time desc")); 26 | } 27 | 28 | public static List getApp() { 29 | return NotificationBoxApp.getLiteOrm().query(AppInfo.class); 30 | } 31 | 32 | public static void saveApp(AppInfo info) { 33 | NotificationBoxApp.getLiteOrm().save(info); 34 | } 35 | 36 | public static void deleteApp(AppInfo info) { 37 | NotificationBoxApp.getLiteOrm().delete(new WhereBuilder(AppInfo.class) 38 | .where("packageName = ?", info.getPackageName())); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/utils/PackageUtils.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.utils; 2 | 3 | import android.content.Intent; 4 | import android.content.pm.ApplicationInfo; 5 | import android.content.pm.PackageInfo; 6 | import android.content.pm.PackageManager; 7 | import android.content.pm.ResolveInfo; 8 | import android.util.Log; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | import cn.gavinliu.notificationbox.model.AppInfo; 14 | import rx.Observable; 15 | import rx.Subscriber; 16 | 17 | /** 18 | * Created by Gavin on 16-10-18. 19 | */ 20 | 21 | public class PackageUtils { 22 | 23 | public static Observable> getInstallPackages(final PackageManager pm) { 24 | return Observable.create(new Observable.OnSubscribe>() { 25 | @Override 26 | public void call(Subscriber> subscriber) { 27 | List appInfos = new ArrayList<>(); 28 | 29 | Intent intent = new Intent(); 30 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 31 | intent.setAction(Intent.ACTION_MAIN); 32 | List resolveInfoList = pm.queryIntentActivities(intent, 0); 33 | 34 | for (ResolveInfo info : resolveInfoList) { 35 | AppInfo app = new AppInfo(); 36 | app.setIcon(info.loadIcon(pm)); 37 | app.setAppName(info.loadLabel(pm).toString()); 38 | app.setPackageName(info.activityInfo.packageName); 39 | 40 | appInfos.add(app); 41 | } 42 | 43 | List db = DbUtils.getApp(); 44 | List temp = new ArrayList<>(); 45 | 46 | for (AppInfo info : appInfos) { 47 | for (AppInfo a : db) { 48 | if (a.getPackageName().equals(info.getPackageName())) { 49 | info.setSelect(true); 50 | temp.add(info); 51 | } 52 | } 53 | } 54 | 55 | appInfos.removeAll(temp); 56 | appInfos.addAll(0, temp); 57 | 58 | subscriber.onNext(appInfos); 59 | } 60 | }); 61 | } 62 | 63 | public static Observable> getAppDbList(final PackageManager pm) { 64 | return Observable.create(new Observable.OnSubscribe>() { 65 | 66 | @Override 67 | public void call(Subscriber> subscriber) { 68 | List appInfos = new ArrayList<>(); 69 | 70 | 71 | List db = DbUtils.getApp(); 72 | 73 | Intent intent = new Intent(); 74 | intent.addCategory(Intent.CATEGORY_LAUNCHER); 75 | intent.setAction(Intent.ACTION_MAIN); 76 | List resolveInfoList = pm.queryIntentActivities(intent, 0); 77 | 78 | for (ResolveInfo info : resolveInfoList) { 79 | for (AppInfo app : db) { 80 | if (info.activityInfo.packageName.equals(app.getPackageName())) { 81 | app.setIcon(info.loadIcon(pm)); 82 | 83 | appInfos.add(app); 84 | } 85 | } 86 | } 87 | 88 | subscriber.onNext(appInfos); 89 | } 90 | }); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/utils/SettingUtils.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.support.v7.preference.PreferenceManager; 6 | 7 | import cn.gavinliu.notificationbox.NotificationBoxApp; 8 | 9 | /** 10 | * Created by Gavin on 16-10-26. 11 | */ 12 | 13 | public class SettingUtils { 14 | 15 | private static SettingUtils util; 16 | private SharedPreferences mPreference; 17 | 18 | private synchronized static void createInstance(Context ctx) { 19 | if (util == null) { 20 | util = new SettingUtils(ctx); 21 | } 22 | } 23 | 24 | public static SettingUtils getInstance() { 25 | if (util == null) { 26 | createInstance(NotificationBoxApp.get()); 27 | } 28 | return util; 29 | } 30 | 31 | private SettingUtils(Context ctx) { 32 | mPreference = PreferenceManager.getDefaultSharedPreferences(ctx); 33 | } 34 | 35 | public boolean isNotify() { 36 | return mPreference.getBoolean("isNotify", false); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/widget/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.widget; 2 | 3 | import android.support.v7.app.AppCompatActivity; 4 | 5 | /** 6 | * Created by Gavin on 16-10-17. 7 | */ 8 | 9 | public abstract class BaseActivity extends AppCompatActivity { 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/widget/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.widget; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.app.ActionBar; 7 | import android.support.v7.app.AppCompatActivity; 8 | import android.view.MenuItem; 9 | 10 | /** 11 | * Created by Gavin on 16-10-17. 12 | */ 13 | 14 | public abstract class BaseFragment extends Fragment { 15 | 16 | @Override 17 | public void onCreate(@Nullable Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setHasOptionsMenu(true); 20 | } 21 | 22 | @Override 23 | public void onActivityCreated(@Nullable Bundle savedInstanceState) { 24 | super.onActivityCreated(savedInstanceState); 25 | getArguments(getArguments()); 26 | setupActionBar(((AppCompatActivity) getActivity()).getSupportActionBar()); 27 | } 28 | 29 | public void getArguments(Bundle bundle) { 30 | 31 | } 32 | 33 | public void setupActionBar(ActionBar actionBar) { 34 | 35 | } 36 | 37 | @Override 38 | public boolean onOptionsItemSelected(MenuItem item) { 39 | switch (item.getItemId()) { 40 | case android.R.id.home: 41 | getActivity().finish(); 42 | break; 43 | } 44 | return super.onOptionsItemSelected(item); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/widget/BaseListFragment.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.widget; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import cn.gavinliu.notificationbox.R; 12 | 13 | /** 14 | * Created by Gavin on 16-10-22. 15 | */ 16 | 17 | public abstract class BaseListFragment extends BaseFragment { 18 | 19 | protected View mView; 20 | protected RecyclerView mRecyclerView; 21 | protected View mEmptyLayout; 22 | protected TextView mEmptyText; 23 | protected View mProgressLayout; 24 | 25 | @Override 26 | public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | if (mView == null) { 28 | mView = inflater.inflate(R.layout.nb_base_list_fragment, null, false); 29 | } 30 | return mView; 31 | } 32 | 33 | @Override 34 | public void onViewCreated(View view, Bundle savedInstanceState) { 35 | if (view != null) { 36 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); 37 | mEmptyLayout = view.findViewById(R.id.empty_layout); 38 | mProgressLayout = view.findViewById(R.id.progress_layout); 39 | mEmptyText = (TextView) view.findViewById(R.id.empty_text); 40 | } 41 | 42 | setupRecyclerView(mRecyclerView); 43 | } 44 | 45 | protected void showEmptyView() { 46 | mEmptyLayout.setVisibility(View.VISIBLE); 47 | } 48 | 49 | protected void hideEmptyView() { 50 | mEmptyLayout.setVisibility(View.GONE); 51 | } 52 | 53 | protected void showProgressView() { 54 | mProgressLayout.setVisibility(View.VISIBLE); 55 | } 56 | 57 | protected void hideProgressView() { 58 | mProgressLayout.setVisibility(View.GONE); 59 | } 60 | 61 | protected void setEmptyText(CharSequence text){ 62 | mEmptyText.setText(text); 63 | } 64 | 65 | protected void setupRecyclerView(RecyclerView recyclerView) { 66 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/cn/gavinliu/notificationbox/widget/BaseViewHolder.java: -------------------------------------------------------------------------------- 1 | package cn.gavinliu.notificationbox.widget; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.View; 5 | 6 | /** 7 | * Created by Gavin on 2016/10/12. 8 | */ 9 | 10 | public abstract class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ 11 | 12 | public BaseViewHolder(View itemView) { 13 | super(itemView); 14 | itemView.setOnClickListener(this); 15 | } 16 | 17 | @Override 18 | public void onClick(View v) { 19 | 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/drawable-xhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/drawable-xxhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_navigate_next_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/drawable-xxhdpi/ic_navigate_next_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/drawable-xxxhdpi/ic_add_white_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_applist.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 22 | 23 | 24 | 25 | 30 | 31 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_applist.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 26 | 27 | 33 | 34 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 27 | 28 | 40 | 41 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nb_base_list_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nb_empty_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nb_preference_screen.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/nb_progress_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-v21/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rCN/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 消息盒子 3 | 消息监听服务 4 | 5 | 软件列表 6 | 7 | 设置 8 | 9 | 功能 10 | 关于 11 | 开放源码 12 | 拦截提醒 13 | 拦截到消息后提醒 14 | 配置权限 15 | 如果拦截失效,请取消权限后,重新配置权限 16 | 17 | 没有监听通知栏的权限 18 | 19 | 点击右下角的按钮,添加所需拦截的App 20 | 还未拦截到该软件的通知消息 21 | 22 | 拦截: %1$s 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values-zh-rHK/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 消息盒子 3 | 消息監聽服務 4 | 5 | 軟件列表 6 | 7 | 設置 8 | 9 | 功能 10 | 關於 11 | 開放源碼 12 | 攔截提醒 13 | 攔截到消息後提醒 14 | 配置權限 15 | 如果攔截失效,請取消權限後,重新配置權限 16 | 17 | 沒有監聽通知欄的權限 18 | 19 | 點擊右下角的按鈕,添加所需攔截的App 20 | 還未攔截到該軟件的通知消息 21 | 22 | 攔截: %1$s 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #607D8B 4 | #455A64 5 | #03A9F4 6 | 7 | #212121 8 | #757575 9 | #BDBDBD 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 24dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/ids.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | NotificationBox 3 | Notification Listener Service 4 | 5 | App List 6 | 7 | Settings 8 | 9 | Feature 10 | About 11 | OpenSource 12 | Intercept reminder 13 | Intercept notification after the reminder 14 | Set permissions 15 | If the blocking is disabled, reset the permissions 16 | 17 | No read notification permissions 18 | 19 | Click on the lower right corner of the button, add the blocking App 20 | The notification message to the app has not yet been intercepted 21 | 22 | Intercept: %1$s 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 19 | 20 | 28 | 29 | 33 | 34 | 41 | 42 | 57 | 58 | 62 | 63 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/xml/setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 7 | 8 | 13 | 14 | 19 | 20 | 21 | 22 | 24 | 25 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.2' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /screenshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gavinliu/NotificationBox/d2844df1c7a5e3f2e1aabd40c57c9201a2715d79/screenshots.png -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------