【问题标题】:Android - cancel/replace calendar notification with a custom oneAndroid - 用自定义取消/替换日历通知
【发布时间】:2017-03-26 16:06:08
【问题描述】:

我正在尝试使用 NotificationManager 将内置日历提醒的通知替换为自定义内置通知。

我添加了一个广播接收器,它拦截日历提醒的通知,例如:

     <receiver
        android:name=".receivers.CalendarNotificationBroadcastReceiver">
        <intent-filter>
            <action android:name="android.intent.action.EVENT_REMINDER"/>
            <data android:scheme="content"/>
            <data android:host="com.android.calendar"/>
        </intent-filter>
    </receiver>

intent 被传递给 onReceive 方法,如下所示:

Q1:如何使用 ContentResolver API 来查找有关触发通知的事件的信息(例如,我需要 TITLE 字段来构建新通知)?

Q2:如何取消intent,不触发日历事件的提醒通知? 我已经尝试按照这篇文章中的建议进行操作,但无济于事: How to cancel this repeating alarm? 另外,我尝试过(没有成功):

PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();

编辑 ******************

在遵循 Ovidiu Latcu 的建议后,我为 NotificationListenerService 提供了一个实现,该实现还具有用于新通知的 BroadcastReceiver

AndroidManifest

<service android:name=".service.CalendarNotificationListenerService"
    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>

NotificationListenerService

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
/**
 * Due to an android bug: https://stackoverflow.com/questions/17911883/cannot-get-the-notificationlistenerservice-class-to-work
 * This class' name should be changed before each debug use, because if not, onReceive will never get called.
 */
public class CalendarNotificationListenerService extends NotificationListenerService {

    private String TAG = this.getClass().getSimpleName();
    private CalendarNotificationBroadcastReceiver receiver;

@Override
public void onCreate() {
    Log.i(TAG,"********** Service is created");
    super.onCreate();
    receiver = new CalendarNotificationBroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter("android.intent.action.EVENT_REMINDER");
    intentFilter.addDataScheme("content");
    registerReceiver(receiver, intentFilter);
}

@Override
public void onDestroy() {
    Log.i(TAG,"**********  Service is destroyed");
    super.onDestroy();
    unregisterReceiver(receiver);
}

@Override
public IBinder onBind(Intent mIntent) {
    IBinder mIBinder = super.onBind(mIntent);
    Log.i(TAG, "**********  onBind");
    return mIBinder;
}

@Override
public boolean onUnbind(Intent mIntent) {
    boolean mOnUnbind = super.onUnbind(mIntent);
    Log.i(TAG, "**********  onUnbind");
    return mOnUnbind;
}

@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
    Log.i(TAG,"**********  onNotificationPosted");
    Log.i(TAG,"ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText + "\t" + sbn.getPackageName());

    Notification currentNotification = sbn.getNotification();

    String notificationTitle = (String) sbn.getNotification().extras.get("android.title");

    if(notificationTitle == null || !notificationTitle.startsWith("CALLERQ:")){
        return;
    }

    //Seem to only be able to cancel a notification after it is posted.
    CalendarNotificationListenerService.this.cancelNotification(sbn.getKey());

    Intent i = new  Intent("com.enginizer.NOTIFICATION_LISTENER_EXAMPLE");
    i.putExtra("notification_event","onNotificationPosted :" + sbn.getPackageName() + "\n");
    sendBroadcast(i);
}

@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
    Log.i(TAG,"********** onNOtificationRemoved");
    Log.i(TAG,"ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText +"\t" + sbn.getPackageName());
    Intent i = new  Intent("com.enginizer.NOTIFICATION_LISTENER_EXAMPLE");
    i.putExtra("notification_event","onNotificationRemoved :" + sbn.getPackageName() + "\n");

    sendBroadcast(i);
}


class CalendarNotificationBroadcastReceiver extends BroadcastReceiver {

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "********** Notification received");
        String intentAction = intent.getAction();
        Log.i(TAG, "********** " + intentAction);
        intent.getBundleExtra(CalendarContract.EXTRA_CUSTOM_APP_URI);

        ContentResolver contentResolver = context.getContentResolver();

        //This throws an java.lang.IllegalArgumentException 
        Cursor cursor = contentResolver.query(intent.getData(), new String[]{CalendarContract.Events.DESCRIPTION}, null, null, null);

        CalendarNotificationListenerService.this.cancelAllNotifications();
    }
}

@Override
public void onListenerConnected() {
    Log.i(TAG,"********** Listener connected");
    super.onListenerConnected();
}

}

对于第一季度的回答,我正在尝试查询日历以查找 mData 字段中记录的事件。这样做时,我会收到以下信息:

java.lang.IllegalArgumentException: Unknown URL content://com.android.calendar/1491653055193

对于第二季度,我无法从 onReceive 方法中取消通知,因为我无法在意图上找到它。我只能在 onNotificationPosted 方法中取消通知,这比预期的要晚。

取消一个日历提醒通知,换成自定义的,真的要这么纠结吗?

【问题讨论】:

    标签: android notifications calendar


    【解决方案1】:

    Q1:mData 字段包含该事件的URI。您可能应该查询 URI 并找到有关该事件的所有信息。

    Q2:从 API 18 开始,您可以使用 NotificationListenerService 拦截通知何时发布,并使用 cancelNotification(String key) 取消通知

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-07
      相关资源
      最近更新 更多