22

我正在尝试实现在 android 4.3 中添加的 NotificationListnerService,但我无法获取通知详细信息。

我的代码如下

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setSmallIcon(R.drawable.ic_launcher);
        mBuilder.setContentTitle("notification test");
        mBuilder.setContentText("Notification text");
        mBuilder.setAutoCancel(true);
        Intent resultIntent = new Intent(this, ResultActivity.class);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        // Adds the back stack for the Intent (but not the Intent itself)
        stackBuilder.addParentStack(ResultActivity.class);
        // Adds the Intent that starts the Activity to the top of the stack
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                stackBuilder.getPendingIntent(
                    0,
                    PendingIntent.FLAG_UPDATE_CURRENT
                );
        mBuilder.setContentIntent(resultPendingIntent);
        NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
        manager.notify(1, mBuilder.build());
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}

public class NotificationListenerTesting extends NotificationListenerService{

    public static String TAG = "NotificationListenerTesting";
    //private StatusBarNotification[] mStatusBarNotification;

    @Override
    public void onCreate(){
        super.onCreate();
        Log.d(TAG, "Inside on create");
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        TAG = "onNotificationPosted";
        Log.d(TAG, "id = " + sbn.getId() + "Package Name" + sbn.getPackageName() + 
                "Post time = " + sbn.getPostTime() + "Tag = " + sbn.getTag());
    }
    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        TAG = "onNotificationRemoved";
        Log.d(TAG, "id = " + sbn.getId() + "Package Name" + sbn.getPackageName() + 
                "Post time = " + sbn.getPostTime() + "Tag = " + sbn.getTag());

    }

}

Android清单文件是

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.notificationtest"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.notificationtest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name="com.example.notificationtest.ResultActivity"></activity>
        <service android:name="com.example.notificationtest.NotificationListenerTesting"
            android:label="notification"
            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
            <intent-filter>
                <action android:name="android.service.notification.NotificationListenerService"/>
            </intent-filter>
        </service>
    </application>
</manifest>

但是在通知单击或通知帖子后 NotificationListenerService 没有被调用,这有什么问题还是我错过了什么?如何实施?

4

9 回答 9

26

您需要授予对应用程序的访问权限才能阅读通知:“设置 > 安全性 > 通知访问权限”并检查您的应用程序。

于 2013-07-29T22:47:27.933 回答
25

在 NotificationListenerService 内部,您需要一个循环器来与 GUI 线程通信,以便您可以创建一个广播来处理 GUI 交互。

希望这个例子对你有所帮助。

于 2013-08-06T06:58:11.597 回答
10

您的代码至少有一个问题是您的 onBind() 实现

没有必要重写此方法。但如果必须,那么至少返回超类返回的 IBinder。

@Override
public IBinder onBind(Intent intent) {
    return super.onBind(intent);
}
于 2013-08-01T08:28:31.553 回答
6

可能有点晚了。但几个月前,我还在努力让 NotificationListenerService 工作。

从那以后,我学会了如何实现它,并想建立一个实现教程来帮助和我一样经历过的其他人

如果有人感兴趣,请在此处查看项目: https ://github.com/Chagall/notification-listener-service-example

希望它可以帮助正在为此苦苦挣扎的人。

于 2016-09-16T04:00:59.520 回答
4

我知道回答这个问题为时已晚,但由于我无法找到设置>声音和通知->通知访问,所以我通过触发此意图直接允许访问我的应用程序的通知:

startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));

于 2017-04-27T07:28:06.917 回答
1

我遇到了同样的问题,并找到了一些线索。

NotificationListenerServicebindService()除非您调用启动它,否则它可能不会运行。

有时它会在您启用“通知访问”时自动启动,有时则不会。

于 2013-08-02T19:12:13.367 回答
0

我正在做与 GitHub 相同的事情,但我仍然没有进入通知类。

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;

/**
 * @author dinesh
 *
 */
public class UserNotificationService extends NotificationListenerService {

    private String TAG = "UserNotificationService";
    UserNotificationServiceReceiver notfRcvr;

    @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("de.tu.darmstadt.moodsense.services.Notification");
    i.putExtra("notification event", "On notification removed");
    sendBroadcast(i);

    }

    @Override
    public IBinder onBind(Intent intent) {
        return super.onBind(intent);
    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {

        Log.i(TAG,"**********  onNotificationPosted");
    Log.i(TAG,"ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText + "\t" + sbn.getPackageName());
    Intent i = new Intent("de.tu.darmstadt.moodsense.services.Notification");
    i.putExtra("notification event", "On notification posted");
    sendBroadcast(i);

    }

    @Override
    public void onCreate() {
        super.onCreate();
        notfRcvr = new UserNotificationServiceReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("de.tu.darmstadt.moodsense.services.Notification");
        registerReceiver(notfRcvr, filter);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(notfRcvr);
    }

    class UserNotificationServiceReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            // TODO Auto-generated method stub
            if(intent.getStringExtra("command").equals("clearall")) {
                UserNotificationService.this.cancelAllNotifications();
            }
        }

    }
}



import java.lang.Thread.State;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import twitter4j.Status;
import twitter4j.TwitterException;
import de.tu.darmstadt.moodsense.R;
import de.tu.darmstadt.moodsense.app.UserMood;
import de.tu.darmstadt.moodsense.constants.Constants;
import de.tu.darmstadt.moodsense.util.MqttMoodClient;
import de.tu.darmstadt.moodsense.util.TwitterMoodUtils;
import de.tu.darmstadt.moodsense.util.TwitterUtils;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;


/**
 * @author dinesh
 * Added for V1.1
 * Code style based on : https://newcircle.com/s/post/1049/
 *                       tutorial_services_part_1_android_bootcamp_series_2012
 *
 */
public class UserMoodService extends Service{

    static final String TAG = "UserMoodService";
    public static boolean userMoodSet = false;
    //declarations for twitter
    private SharedPreferences prefs;
    SharedPreferences userPref;
    String userTwitterMood = "";
    String worldTwitterMood = "";
    String screenName, userName;
    int m_counter;
    long shortMinutes;
    boolean m_enterMood;
    int m_myMood;
    int m_moodIntensity;
    MqttMoodClient mqc;
    TwitterMoodUtils tmu;
    Calendar cal = Calendar.getInstance();  

    private static final int MY_NOTIFICATION_ID=1;
    NotificationManager notificationManager;
    Notification myNotification;
    UserMoodNotificationReceiver usrMoodNotfnnRcvr;

    public UserMoodService() {
        // TODO Auto-generated constructor stub
        mqc = new MqttMoodClient();
        tmu = new TwitterMoodUtils();
    }
    public void reset() {

        m_myMood = Constants.NUM_MOOD_TYPES;
        m_moodIntensity = Constants.MILD;
        m_enterMood = false;

        m_counter = 0;

    }
    @Override
    public IBinder onBind(Intent arg0) {    
        return null;
    }

    @Override
    public void onTaskRemoved(Intent rootIntent) {
        // TODO Auto-generated method stub
        Intent restartService = new Intent(getApplicationContext(),this.getClass());
        restartService.setPackage(getPackageName());
        PendingIntent restartServicePI = PendingIntent.getService(getApplicationContext(),
                1, restartService, PendingIntent.FLAG_ONE_SHOT);

         AlarmManager alarmService = (AlarmManager)getApplicationContext().getSystemService(Context.ALARM_SERVICE);
        alarmService.set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() +100, restartServicePI);
    }

    /** (non-Javadoc)
     * @see android.app.Service#onCreate()
     */
    @Override
    public void onCreate() {
        Log.d(TAG, "OnCreation");
        //super.onCreate();
        usrMoodNotfnnRcvr = new UserMoodNotificationReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction("Notofication Obj");
        registerReceiver(usrMoodNotfnnRcvr, filter);

    }


    /** (non-Javadoc)
     * @see android.app.Service#onStartCommand(android.content.Intent, int, int)
     */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {  
        Log.d(TAG, "OnStartCommand");
        try {
            ConnectivityManager cm =
                (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo netInfo = cm.getActiveNetworkInfo();
            if (netInfo != null && netInfo.isConnectedOrConnecting()) { 
                Log.d(TAG,"Twitter loop enter");
                //Check the user's mood on twitter
                computeMoodOnTwitter();
                if(userMoodSet) {
                    Log.d(TAG, "user's twitter mood" + userTwitterMood);
                } /*else {
                    Log.d(TAG, "user mood not set, world mood computation started");
                    //If user's mood is not set then check for world's mood
                }*/

            }
        } catch(Exception e) {
            e.printStackTrace();
        }

        return START_STICKY;
    }

    private void computeMoodOnTwitter() {
        // TODO Auto-generated method stub
        reset();
        this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
        Thread twitterThread;
        twitterThread = new Thread() {
            public void run() {
                //userMoodSet = false;
                Log.d(TAG, "User mood is :: "+ userMoodSet);
            /*try {
                  String usrNme =  TwitterUtils.getUserName(prefs).toString();

                  List<Status> statuses = TwitterUtils.getHomeTimeline(prefs);

                     for(int i=0; i < Constants.NUM_MOOD_TYPES; i++) {                  
                        for (int j =0 ; j < Constants.NUM_MOOD_TYPES; j++)
                        {           
                            for (twitter4j.Status status : statuses) {

                                //Check if the status is from the user and it matches our mood strings
                            if(status.getText().contains(Constants.searchStrings[i][j])
                                    && (status.getUser().getScreenName().equals(usrNme))) {
                                Date date = status.getCreatedAt();
                                long Minutes = tmu.getMinuteDifference(cal.getTime(), date);

                                if((Constants.sdf.format(date).equals(Constants.sdf.format(cal.getTime())))) {
                                  //Increment counter for each tweet
                                    Log.d(TAG, "User has a status");
                                    userMoodSet = true;
                                    m_counter++;
                                   //track time for the first tweet
                                   if(m_counter == 1) {
                                    shortMinutes = Minutes;
                                    m_moodIntensity = computeMoodIntensity(i,j);
                                    m_myMood = i;
                                    Log.d(TAG, "intensity + mood" + m_moodIntensity +","+ m_myMood);
                                    Log.d(TAG,"SocialMood:: mymood- " + Constants.moodIntensityNames[m_moodIntensity]+
                                               " "+ Constants.moodNames[m_myMood]);                                    
                                    Log.d(TAG, "SocialMood:: status-"+status.getText());                                        

                                   } else //counter more than 1   //track time for the later tweets 
                                   {  //take latest tweet only if logged minutes is shorter than earlier minutes
                                       if(Minutes < shortMinutes) {
                                          shortMinutes = Minutes;
                                          Log.d(TAG, "Called compute mood_intensity :: "+ m_counter);
                                          m_moodIntensity = computeMoodIntensity(i,j);
                                          m_myMood = i;
                                        }

                                   }                                    
                                  }
                                }
                              }
                            }
                         }                                                                               
                    } catch(TwitterException te) {
                      userMoodSet = false;                                  
                        Log.d(TAG, "Unable to process twitter get requests "+te.getErrorCode()+ " "+ te.getErrorMessage());

                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        Log.d(TAG,"Error msg");
                        e.printStackTrace();
                    }*/

                try {
                    stopThread(this);
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        };

        twitterThread.start();  

    }

    public int computeMoodIntensity(int m_detect, int m_type) {
        // TODO Auto-generated method stub
        for(int j=0; j < Constants.m_extreme.length; j++) {
            if(m_type == Constants.m_extreme[m_detect][j])
                return Constants.EXTREME;
        }
        for(int j=0; j < Constants.m_considerable.length; j++) {
            if(m_type == Constants.m_considerable[m_detect][j])
                return Constants.CONSIDERABLE;
        }

        return Constants.MILD;

    }

    private String userStatusToMood(int myMood) {
        // TODO Auto-generated method stub
        String userMood = Constants.userNoTwitter;
         if(m_myMood >= Constants.NUM_MOOD_TYPES) {
             m_enterMood = true;                
         Log.d(TAG, userMood);
         //Unreachable code - maybe we need to delete this ?? QNS
         /*Intent i = new Intent(UserMoodService.this,UserMood.class);
             i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             startActivity(i);*/
         }
         else {
             userMood = "User mood is "+ Constants.moodNames[m_myMood];
             userTwitterMood = Constants.moodIntensityNames[m_moodIntensity]
                     +" "+Constants.moodNames[m_myMood];

             Log.d(TAG, "Updated user mood is "+userTwitterMood);   
             //call MQTT
             MqttMoodClient mqc = new MqttMoodClient();

             mqc.setupMqttClient();
             mqc.sendMessage(userTwitterMood);

         }
         return userMood;
    }

    private void stopThread(Thread theThread) throws Exception {
        // method to stop the worker thread once the process needed to do has been completed
        Log.d(TAG,"userMoodSet :: "+ userMoodSet);
        if (theThread != null)
        {
            theThread = null;
            Log.d(TAG, "Execution complete inside stop thread");
            if(userMoodSet)
                userStatusToMood(m_myMood);         
        }

        if(!userMoodSet) {
            Log.d(TAG, "In world thread");
            //Call world Service
            //WorldMoodService worldService = new WorldMoodService();
            //worldService.computeWorldMood(this);
            //show notification!!
            /**
             * V1.1 
             * @author dinesh
             * Code adapted from : http://android-er.blogspot.de/2013/06/
             *                     start-activity-once-notification-clicked.html
             */
            Intent myIntent = new Intent(UserMoodService.this, UserMood.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(
                    UserMoodService.this, 
                0, 
                myIntent, 
                Intent.FLAG_ACTIVITY_NEW_TASK);

            myNotification = new NotificationCompat.Builder(UserMoodService.this)
            .setContentTitle("MoodSense notification")
            .setContentText("Please enter mood to play music as per your mood")
            .setTicker("Please enter mood to play music as per your mood")
            .setWhen(System.currentTimeMillis())
            .setContentIntent(pendingIntent)
            .setDefaults(Notification.DEFAULT_SOUND)
            .setAutoCancel(true)
            .setSmallIcon(R.drawable.app_icon)
            .build();

            notificationManager = 
                       (NotificationManager)UserMoodService.this.
                       getSystemService(Context.NOTIFICATION_SERVICE);
                     notificationManager.notify(MY_NOTIFICATION_ID, myNotification);                                

        } else if (userMoodSet) {
            Intent i = new Intent("de.tu.darmstadt.moodsense.services.Notification");
            i.putExtra("command", "clear all");
            sendBroadcast(i);
        }
    }

    public class UserMoodNotificationReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String temp = intent.getStringExtra("notification event");

        }

    }
    /** (non-Javadoc)
     * @see android.app.Service#onDestroy()
     */
    @Override
    public void onDestroy() {   
        Log.d(TAG, "OnDeletion");
        super.onDestroy();
    }   
}

于 2015-07-01T03:05:31.470 回答
0

更新 2020 Kotlin 和 AndroidX

在此处输入图像描述

package com.hiteshsahu.notificationlistener.notification

import android.app.Activity
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.service.notification.NotificationListenerService
import android.service.notification.StatusBarNotification
import android.util.Log
import androidx.localbroadcastmanager.content.LocalBroadcastManager

class CustomNotificationListenerService : NotificationListenerService() {

    private var commandFromUIReceiver: CommandFromUIReceiver? = null


    override fun onCreate() {
        super.onCreate()

        // Register broadcast from UI
        commandFromUIReceiver = CommandFromUIReceiver()
        val filter = IntentFilter()
        filter.addAction(READ_COMMAND_ACTION)
        registerReceiver(commandFromUIReceiver, filter)
    }


    /**
     * New Notn Added Callback
     */
    override fun onNotificationPosted(newNotification: StatusBarNotification) {
        Log.i(
            TAG,
            "-------- onNotificationPosted(): " + "ID :" + newNotification.id + "\t" + newNotification.notification.tickerText + "\t" + newNotification.packageName
        )
        sendResultOnUI("onNotificationPosted :" + newNotification.packageName + "\n")
    }

    /**
     * Notn Removed callback
     */
    override fun onNotificationRemoved(removedNotification: StatusBarNotification) {
        Log.i(
            TAG,
            "-------- onNotificationRemoved() :" + "ID :" + removedNotification.id + "\t" + removedNotification.notification.tickerText + "\t" + removedNotification.packageName
        )
        sendResultOnUI("onNotificationRemoved: " + removedNotification.packageName + "\n")
    }


    internal inner class CommandFromUIReceiver : BroadcastReceiver() {

        override fun onReceive(context: Context, intent: Intent) {
            if (intent.getStringExtra(COMMAND_KEY) == CLEAR_NOTIFICATIONS)
                 // remove Notns
                cancelAllNotifications()
            else if (intent.getStringExtra(COMMAND_KEY) == GET_ACTIVE_NOTIFICATIONS)
                // Read Notns
                fetchCurrentNotifications()
        }
    }


    /**
     * Fetch list of Active Notns
     */
    private fun fetchCurrentNotifications() {
        sendResultOnUI("===== Notification List START ====")

        val activeNotnCount = this@CustomNotificationListenerService.activeNotifications.size

        if (activeNotnCount > 0) {
            for (count in 0..activeNotnCount) {
                val sbn = this@CustomNotificationListenerService.activeNotifications[count]
                sendResultOnUI("#" + count.toString() + " Package: " + sbn.packageName + "\n")
            }
        } else {
            sendResultOnUI("No active Notn found")
        }

        sendResultOnUI("===== Notification List END====")
    }


    // sendMessage success result on UI
    private fun sendResultOnUI(result: String?) {
        val resultIntent = Intent(UPDATE_UI_ACTION)
        resultIntent.putExtra(RESULT_KEY, Activity.RESULT_OK)
        resultIntent.putExtra(RESULT_VALUE, result)
        LocalBroadcastManager.getInstance(this).sendBroadcast(resultIntent)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(commandFromUIReceiver)
    }

    companion object {


        const val TAG = "NotificationListener"

        //Update UI action
        const val UPDATE_UI_ACTION =   "ACTION_UPDATE_UI"
        const val READ_COMMAND_ACTION = "ACTION_READ_COMMAND"


        // Bundle Key Value Pair
        const val RESULT_KEY = "readResultKey"
        const val RESULT_VALUE = "readResultValue"


        //Actions sent from UI
        const val COMMAND_KEY = "READ_COMMAND"
        const val CLEAR_NOTIFICATIONS = "clearall"
        const val GET_ACTIVE_NOTIFICATIONS = "list"


    }
}

完成项目

https://github.com/hiteshsahu/Android-Notification-Demo

于 2020-02-13T14:05:03.143 回答
-1

您构建的通知没有“tickerText”。我发现如果通知没有tickerText,则不会调用onNotificationPosted。

在您的代码中添加 mBuilder.setTicker("your text here")。

onNotificationPosted 现在应该被调用,假设 NotificationListenerService 设置的其余部分是 copacci。

于 2013-10-02T13:01:28.317 回答