Crashes android app when notification comes
My LogCat
2021-09-05 12:12:57.343 14670-14670/com.example.benedis.messagemonitoring E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.benedis.messagemonitoring, PID: 14670
java.lang.RuntimeException: Error receiving broadcast Intent { act=com.example.benedis.messagemonitoring flg=0x10 (has extras) } in com.example.benedis.messagemonitoring.MainActivity$1@9717375
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1566)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.String java.lang.CharSequence.toString()' on a null object reference
at java.lang.String.contains(String.java:2224)
at com.example.benedis.messagemonitoring.MainActivity$1.onReceive(MainActivity.java:120)
at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0$LoadedApk$ReceiverDispatcher$Args(LoadedApk.java:1556)
at android.app.-$$Lambda$LoadedApk$ReceiverDispatcher$Args$_BumDX2UKsnxLVrE6UJsJZkotuA.run(Unknown Source:2)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
My MainActivity
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
private AlertDialog enableNotificationListenerAlertDialog;
public static String messageFromUser = null;
public static String messageFromBot = null;
private ReceiveBroadcastReceiver imageChangeBroadcastReceiver;
private TextView contact;
public Button addContact;
private TextView msg;
public static String replyName;
private static final int CONTACT_PICK_CODE = 2;
private static final String TAG = MainActivity.class.getSimpleName();
private static final int USER = 10001;
private static final int BOT = 10002;
private final String uuid = UUID.randomUUID().toString();
private SessionsClient sessionsClient;
private SessionName session;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
msg = this.findViewById(R.id.message_to_view);
contact = this.findViewById(R.id.contact_to_View);
addContact = this.findViewById(R.id.btn_PickContact);
// Finally we register a receiver to tell the MainActivity when a notification has been received
imageChangeBroadcastReceiver = new ReceiveBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.benedis.messagemonitoring");
registerReceiver(imageChangeBroadcastReceiver, intentFilter);
if (!isNotificationServiceEnabled()) {
enableNotificationListenerAlertDialog = buildNotificationServiceAlertDialog();
enableNotificationListenerAlertDialog.show();
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, 100);
addContact.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pickContactIntent();
}
});
}
initV2Chatbot();
}
private void initV2Chatbot() {
try {
InputStream stream = getResources().openRawResource(R.raw.credential);
GoogleCredentials credentials = GoogleCredentials.fromStream(stream);
String projectId = ((ServiceAccountCredentials)credentials).getProjectId();
SessionsSettings.Builder settingsBuilder = SessionsSettings.newBuilder();
SessionsSettings sessionsSettings = settingsBuilder.setCredentialsProvider(FixedCredentialsProvider.create(credentials)).build();
sessionsClient = SessionsClient.create(sessionsSettings);
session = SessionName.of(projectId, uuid);
} catch (Exception e) {
e.printStackTrace();
}
}
private void sendMessage() {
// Java V2
QueryInput queryInput = QueryInput.newBuilder().setText(TextInput.newBuilder().setText(messageFromUser).setLanguageCode("ru-RU")).build();
new RequestJavaV2Task(MainActivity.this, session, sessionsClient, queryInput).execute();
}
public void callbackV2(DetectIntentResponse response) {
if (response != null) {
// process aiResponse here
String botReply = response.getQueryResult().getFulfillmentText();
messageFromBot = botReply;
Log.d(TAG, "V2 Bot Reply: " + botReply);
//showTextView(botReply, BOT);
botReply = null;
} else {
Log.d(TAG, "Bot Reply: Null");
//showTextView("There was some communication issue. Please Try again!", BOT);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
if (requestCode == CONTACT_PICK_CODE) {
contact.setText("");
Cursor cursor1, cursor2;
Uri uri = data.getData();
cursor1 = getContentResolver().query(uri, null, null, null, null);
if (cursor1.moveToFirst()) {
String contactId = null;
String contactName = null;
String idResults = null;
contactId = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts._ID));
contactName = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
idResults = cursor1.getString(cursor1.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
int idResultsHold = Integer.parseInt(idResults);
contact.append(contactName);
replyName = contactName;
}
}
} else {
}
}
private void pickContactIntent() {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI);
startActivityForResult(intent, CONTACT_PICK_CODE);
}
private boolean isNotificationServiceEnabled() {
String pkgName = getPackageName();
final String flat = Settings.Secure.getString(getContentResolver(),
ENABLED_NOTIFICATION_LISTENERS);
if (!TextUtils.isEmpty(flat)) {
final String[] names = flat.split(":");
for (int i = 0; i < names.length; i++) {
final ComponentName cn = ComponentName.unflattenFromString(names[i]);
if (cn != null) {
if (TextUtils.equals(pkgName, cn.getPackageName())) {
return true;
}
}
}
}
return false;
}
private AlertDialog buildNotificationServiceAlertDialog() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle(R.string.notification_listener_service);
alertDialogBuilder.setMessage(R.string.notification_listener_service_explanation);
alertDialogBuilder.setPositiveButton(R.string.yes,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
startActivity(new Intent(ACTION_NOTIFICATION_LISTENER_SETTINGS));
}
});
alertDialogBuilder.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// If you choose to not enable the notification listener
// the app. will not work as expected
}
});
return (alertDialogBuilder.create());
}
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
return false;
}
public class ReceiveBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String packages = intent.getStringExtra("package");
String title = intent.getStringExtra("title");
String text = intent.getStringExtra("text");
if (MainActivity.replyName.contains(title)) {
if (text != null) {
msg.setText("\nPackages : " + packages + "\nTitle : " + title + "\nText : " + text);
messageFromUser = text;
sendMessage();
}
}
}
}
}
Classes
public class MessengerAccessibilityService extends NotificationListenerService{
/*
These are the package names of the apps. for which we want to
listen the notifications
*/
private static final class ApplicationPackageNames {
public static final String FACEBOOK_PACK_NAME = "com.facebook.katana";
public static final String FACEBOOK_MESSENGER_PACK_NAME = "com.facebook.orca";
public static final String WHATSAPP_PACK_NAME = "com.whatsapp";
//public static final String INSTAGRAM_PACK_NAME = "com.instagram.android";
public static final String TELEGRAM_PACK_NAME = "org.telegram.messenger";
public static final String VIBER_PACK_NAME = "com.viber.voip";
//public static final String LINE_PACK_NAME = "jp.naver.line.android";
//public static final String WECHAT_PACK_NAME = "";
}
/*
These are the return codes we use in the method which intercepts
the notifications, to decide whether we should do something or not
*/
public static final class InterceptedNotificationCode {
public static final int FACEBOOK_CODE = 1;
public static final int WHATSAPP_CODE = 2;
//public static final int INSTAGRAM_CODE = 3;
public static final int TELEGRAM_CODE = 4;
public static final int VIBER_CODE = 5;
//public static final int LINE_CODE = 6;
//public static final int WECHAT_CODE = 7;
public static final int OTHER_NOTIFICATIONS_CODE = 8; // We ignore all notification with code == 8
}
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onNotificationPosted(StatusBarNotification sbn){
int notificationCode = matchNotificationCode(sbn);
if(notificationCode != InterceptedNotificationCode.OTHER_NOTIFICATIONS_CODE)
{
String pack = sbn.getPackageName();
Bundle extras = sbn.getNotification().extras;
String title = extras.getString("android.title");
String text = extras.getCharSequence("android.text").toString();
String subtext = "";
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)) {
/* Used for SendBroadcast */
if (subtext.isEmpty()) {
subtext = text;
}
Log.d("Details :", subtext);
Intent intent = new Intent("com.example.benedis.messagemonitoring");
intent.putExtra("Notification Code", notificationCode);
intent.putExtra("package", pack);
intent.putExtra("title", title);
intent.putExtra("text", subtext);
intent.putExtra("id", sbn.getId());
sendBroadcast(intent);
if (text != null) {
if (!text.contains("new messages") && !text.contains("WhatsApp Web is currently active") && !text.contains("WhatsApp Web login")) {
if(MainActivity.replyName!=null && MainActivity.replyName.contains(title)) {
MessengerAccessibilityService.this.cancelNotification(sbn.getKey());
Action action = NotificationUtils.getQuickReplyAction(sbn.getNotification(), getPackageName());
if (action != null) {
Log.i(TAG, "success");
try {
while(MainActivity.messageFromUser!=null){
action.sendReply(getApplicationContext(), MainActivity.messageFromBot);
}
} catch (PendingIntent.CanceledException e) {
Log.i(TAG, "CRAP " + e.toString());
}
} else {
Log.i(TAG, "not success");
}
}
}
}
}
}
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn){
int notificationCode = matchNotificationCode(sbn);
if(notificationCode != InterceptedNotificationCode.OTHER_NOTIFICATIONS_CODE)
{
StatusBarNotification[] activeNotifications = this.getActiveNotifications();
if(activeNotifications != null && activeNotifications.length > 0) {
for (int i = 0; i < activeNotifications.length; i++) {
if (notificationCode == matchNotificationCode(activeNotifications[i])) {
Intent intent = new Intent("com.example.benedis.messagemonitoring");
intent.putExtra("Notification Code", notificationCode);
sendBroadcast(intent);
break;
}
}
}
}
}
private int matchNotificationCode(StatusBarNotification sbn) {
String packageName = sbn.getPackageName();
if(packageName.equals(ApplicationPackageNames.FACEBOOK_PACK_NAME)
|| packageName.equals(ApplicationPackageNames.FACEBOOK_MESSENGER_PACK_NAME)){
return(InterceptedNotificationCode.FACEBOOK_CODE);
}
/*else if(packageName.equals(ApplicationPackageNames.INSTAGRAM_PACK_NAME)){
return(InterceptedNotificationCode.INSTAGRAM_CODE);
}*/
else if(packageName.equals(ApplicationPackageNames.WHATSAPP_PACK_NAME)){
return(InterceptedNotificationCode.WHATSAPP_CODE);
}
else if(packageName.equals(ApplicationPackageNames.TELEGRAM_PACK_NAME)){
return(InterceptedNotificationCode.TELEGRAM_CODE);
}
else if(packageName.equals(ApplicationPackageNames.VIBER_PACK_NAME)){
return(InterceptedNotificationCode.VIBER_CODE);
}
/*else if(packageName.equals(ApplicationPackageNames.LINE_PACK_NAME)){
return(InterceptedNotificationCode.LINE_CODE);
}*/
/*else if(packageName.equals(ApplicationPackageNames.WEECHAT_PACK_NAME)){
return(InterceptedNotificationCode.WEECHAT_CODE);
}*/
else{
return(InterceptedNotificationCode.OTHER_NOTIFICATIONS_CODE);
}
}
}
Gradle app
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.example.benedis.messagemonitoring"
minSdkVersion 20
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
packagingOptions {
exclude 'project.properties'
exclude 'META-INF/INDEX.LIST'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/notice.txt'
exclude 'META-INF/ASL2.0'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:30.0.0'
implementation 'com.android.support:design:30.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation ('io.grpc:grpc-okhttp:1.30.1') {
exclude group: "com.squareup.okhttp"
}
implementation 'com.github.iamrobj:NotificationHelperLibrary:2.0.5'
implementation 'com.google.cloud:google-cloud-dialogflow:2.0.0'
// for Remote Procedure Call to avoid "No functional channel service provider found" error while creating SessionsClient
implementation 'io.grpc:grpc-okhttp:1.30.1'
def multidex_version = "2.0.1"
implementation "androidx.multidex:multidex:$multidex_version"
}
My Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:uses-permission="http://schemas.android.com/apk/res-auto"
package="com.example.benedis.messagemonitoring">
<!--Read contact permission-->
<uses-permission android:name="android:permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MessengerAccessibilityService"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
</manifest>