Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 05ad4820 authored by Christoph Studer's avatar Christoph Studer
Browse files

Add ZEN and speedbump to NotificationListenerService

Change-Id: I39fae5d77863e0d10cf236a096cc589167d146d3
parent 646b1db4
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -25589,20 +25589,24 @@ package android.service.notification {
    method public final deprecated void cancelNotification(java.lang.String, java.lang.String, int);
    method public final void cancelNotification(java.lang.String);
    method public final void cancelNotifications(java.lang.String[]);
    method public java.lang.String[] getActiveNotificationKeys();
    method public android.service.notification.StatusBarNotification[] getActiveNotifications();
    method public android.service.notification.StatusBarNotification[] getActiveNotifications(java.lang.String[]);
    method public java.lang.String[] getOrderedNotificationKeys();
    method public android.service.notification.NotificationListenerService.Ranking getCurrentRanking();
    method public android.os.IBinder onBind(android.content.Intent);
    method public void onListenerConnected(java.lang.String[]);
    method public void onNotificationOrderUpdate();
    method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
    method public void onNotificationRankingUpdate();
    method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
  }
  public class NotificationOrderUpdate implements android.os.Parcelable {
    ctor public NotificationOrderUpdate(android.os.Parcel);
  public static class NotificationListenerService.Ranking implements android.os.Parcelable {
    method public int describeContents();
    method public int getIndexOfKey(java.lang.String);
    method public java.lang.String[] getOrderedKeys();
    method public boolean isAmbient(java.lang.String);
    method public boolean isInterceptedByDoNotDisturb(java.lang.String);
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator CREATOR;
  }
+5 −5
Original line number Diff line number Diff line
@@ -17,15 +17,15 @@
package android.service.notification;

import android.service.notification.StatusBarNotification;
import android.service.notification.NotificationOrderUpdate;
import android.service.notification.NotificationRankingUpdate;

/** @hide */
oneway interface INotificationListener
{
    void onListenerConnected(in NotificationOrderUpdate update);
    void onListenerConnected(in NotificationRankingUpdate update);
    void onNotificationPosted(in StatusBarNotification notification,
            in NotificationOrderUpdate update);
            in NotificationRankingUpdate update);
    void onNotificationRemoved(in StatusBarNotification notification,
            in NotificationOrderUpdate update);
    void onNotificationOrderUpdate(in NotificationOrderUpdate update);
            in NotificationRankingUpdate update);
    void onNotificationRankingUpdate(in NotificationRankingUpdate update);
}
 No newline at end of file
+171 −46
Original line number Diff line number Diff line
@@ -24,12 +24,15 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

/**
 * A service that receives calls from the system when new notifications are posted or removed.
 * A service that receives calls from the system when new notifications are
 * posted or removed, or their ranking changed.
 * <p>To extend this class, you must declare the service in your manifest file with
 * the {@link android.Manifest.permission#BIND_NOTIFICATION_LISTENER_SERVICE} permission
 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
@@ -48,7 +51,7 @@ public abstract class NotificationListenerService extends Service {
            + "[" + getClass().getSimpleName() + "]";

    private INotificationListenerWrapper mWrapper = null;
    private String[] mNotificationKeys;
    private Ranking mRanking;

    private INotificationManager mNoMan;

@@ -102,11 +105,11 @@ public abstract class NotificationListenerService extends Service {
    }

    /**
     * Implement this method to be notified when the notification order cahnges.
     *
     * Call {@link #getOrderedNotificationKeys()} to retrieve the new order.
     * Implement this method to be notified when the notification ranking changes.
     * <P>
     * Call {@link #getCurrentRanking()} to retrieve the new ranking.
     */
    public void onNotificationOrderUpdate() {
    public void onNotificationRankingUpdate() {
        // optional
    }

@@ -223,6 +226,19 @@ public abstract class NotificationListenerService extends Service {
        return getActiveNotifications(null /*all*/);
    }

    /**
     * Request the list of notification keys in their current ranking order.
     * <p>
     * You can use the notification keys for subsequent retrieval via
     * {@link #getActiveNotifications(String[]) or dismissal via
     * {@link #cancelNotifications(String[]).
     *
     * @return An array of active notification keys, in their ranking order.
     */
    public String[] getActiveNotificationKeys() {
        return mRanking.getOrderedKeys();
    }

    /**
     * Request the list of outstanding notifications (that is, those that are visible to the
     * current user). Useful when you don't know what's already been posted.
@@ -242,15 +258,20 @@ public abstract class NotificationListenerService extends Service {
    }

    /**
     * Request the list of notification keys in their current natural order.
     * You can use the notification keys for subsequent retrieval via
     * {@link #getActiveNotifications(String[]) or dismissal via
     * {@link #cancelNotifications(String[]).
     * Returns current ranking information.
     *
     * <p>
     * The returned object represents the current ranking snapshot and only
     * applies for currently active notifications. Hence you must retrieve a
     * new Ranking after each notification event such as
     * {@link #onNotificationPosted(StatusBarNotification)},
     * {@link #onNotificationRemoved(StatusBarNotification)}, etc.
     *
     * @return An array of active notification keys, in their natural order.
     * @return A {@link NotificationListenerService.Ranking} object providing
     *     access to ranking information
     */
    public String[] getOrderedNotificationKeys() {
        return mNotificationKeys;
    public Ranking getCurrentRanking() {
        return mRanking;
    }

    @Override
@@ -308,59 +329,163 @@ public abstract class NotificationListenerService extends Service {
    private class INotificationListenerWrapper extends INotificationListener.Stub {
        @Override
        public void onNotificationPosted(StatusBarNotification sbn,
                NotificationOrderUpdate update) {
            try {
                NotificationRankingUpdate update) {
            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
            synchronized (mWrapper) {
                    updateNotificationKeys(update);
                applyUpdate(update);
                try {
                    NotificationListenerService.this.onNotificationPosted(sbn);
                }
                } catch (Throwable t) {
                Log.w(TAG, "Error running onOrderedNotificationPosted", t);
                    Log.w(TAG, "Error running onNotificationPosted", t);
                }
            }
        }
        @Override
        public void onNotificationRemoved(StatusBarNotification sbn,
                NotificationOrderUpdate update) {
            try {
                NotificationRankingUpdate update) {
            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
            synchronized (mWrapper) {
                    updateNotificationKeys(update);
                applyUpdate(update);
                try {
                    NotificationListenerService.this.onNotificationRemoved(sbn);
                }
                } catch (Throwable t) {
                    Log.w(TAG, "Error running onNotificationRemoved", t);
                }
            }
        }
        @Override
        public void onListenerConnected(NotificationOrderUpdate update) {
            try {
        public void onListenerConnected(NotificationRankingUpdate update) {
            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
            synchronized (mWrapper) {
                    updateNotificationKeys(update);
                    NotificationListenerService.this.onListenerConnected(mNotificationKeys);
                }
                applyUpdate(update);
                try {
                    NotificationListenerService.this.onListenerConnected(
                            mRanking.getOrderedKeys());
                } catch (Throwable t) {
                    Log.w(TAG, "Error running onListenerConnected", t);
                }
            }
        }
        @Override
        public void onNotificationOrderUpdate(NotificationOrderUpdate update)
        public void onNotificationRankingUpdate(NotificationRankingUpdate update)
                throws RemoteException {
            try {
            // protect subclass from concurrent modifications of (@link mNotificationKeys}.
            synchronized (mWrapper) {
                    updateNotificationKeys(update);
                    NotificationListenerService.this.onNotificationOrderUpdate();
                }
                applyUpdate(update);
                try {
                    NotificationListenerService.this.onNotificationRankingUpdate();
                } catch (Throwable t) {
                Log.w(TAG, "Error running onNotificationOrderUpdate", t);
                    Log.w(TAG, "Error running onNotificationRankingUpdate", t);
                }
            }
        }
    }

    private void updateNotificationKeys(NotificationOrderUpdate update) {
        // TODO: avoid garbage by comparing the lists
        mNotificationKeys = update.getOrderedKeys();
    private void applyUpdate(NotificationRankingUpdate update) {
        mRanking = new Ranking(update);
    }

    /**
     * Provides access to ranking information on currently active
     * notifications.
     *
     * <p>
     * Note that this object represents a ranking snapshot that only applies to
     * notifications active at the time of retrieval.
     */
    public static class Ranking implements Parcelable {
        private final NotificationRankingUpdate mRankingUpdate;

        private Ranking(NotificationRankingUpdate rankingUpdate) {
            mRankingUpdate = rankingUpdate;
        }

        /**
         * Request the list of notification keys in their current ranking
         * order.
         *
         * @return An array of active notification keys, in their ranking order.
         */
        public String[] getOrderedKeys() {
            return mRankingUpdate.getOrderedKeys();
        }

        /**
         * Returns the rank of the notification with the given key, that is the
         * index of <code>key</code> in the array of keys returned by
         * {@link #getOrderedKeys()}.
         *
         * @return The rank of the notification with the given key; -1 when the
         *      given key is unknown.
         */
        public int getIndexOfKey(String key) {
            // TODO: Optimize.
            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
            for (int i = 0; i < orderedKeys.length; i++) {
                if (orderedKeys[i].equals(key)) {
                    return i;
                }
            }
            return -1;
        }

        /**
         * Returns whether the notification with the given key was intercepted
         * by &quot;Do not disturb&quot;.
         */
        public boolean isInterceptedByDoNotDisturb(String key) {
            // TODO: Optimize.
            for (String interceptedKey : mRankingUpdate.getDndInterceptedKeys()) {
                if (interceptedKey.equals(key)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Returns whether the notification with the given key is an ambient
         * notification, that is a notification that doesn't require the user's
         * immediate attention.
         */
        public boolean isAmbient(String key) {
            // TODO: Optimize.
            int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex();
            if (firstAmbientIndex < 0) {
                return false;
            }
            String[] orderedKeys = mRankingUpdate.getOrderedKeys();
            for (int i = firstAmbientIndex; i < orderedKeys.length; i++) {
                if (orderedKeys[i].equals(key)) {
                    return true;
                }
            }
            return false;
        }

        // ----------- Parcelable

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeParcelable(mRankingUpdate, flags);
        }

        public static final Creator<Ranking> CREATOR = new Creator<Ranking>() {
            @Override
            public Ranking createFromParcel(Parcel source) {
                NotificationRankingUpdate rankingUpdate = source.readParcelable(null);
                return new Ranking(rankingUpdate);
            }

            @Override
            public Ranking[] newArray(int size) {
                return new Ranking[size];
            }
        };
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -16,4 +16,4 @@

package android.service.notification;

parcelable NotificationOrderUpdate;
parcelable NotificationRankingUpdate;
+77 −0
Original line number Diff line number Diff line
@@ -18,17 +18,26 @@ package android.service.notification;
import android.os.Parcel;
import android.os.Parcelable;

public class NotificationOrderUpdate implements Parcelable {
    // TODO replace this with an update instead of the whole array
/**
 * @hide
 */
public class NotificationRankingUpdate implements Parcelable {
    // TODO: Support incremental updates.
    private final String[] mKeys;
    private final String[] mDndInterceptedKeys;
    private final int mFirstAmbientIndex;

    /** @hide */
    public NotificationOrderUpdate(String[] keys) {
        this.mKeys = keys;
    public NotificationRankingUpdate(String[] keys, String[] dndInterceptedKeys,
                                     int firstAmbientIndex) {
        mKeys = keys;
        mFirstAmbientIndex = firstAmbientIndex;
        mDndInterceptedKeys = dndInterceptedKeys;
    }

    public NotificationOrderUpdate(Parcel in) {
        this.mKeys = in.readStringArray();
    public NotificationRankingUpdate(Parcel in) {
        mKeys = in.readStringArray();
        mFirstAmbientIndex = in.readInt();
        mDndInterceptedKeys = in.readStringArray();
    }

    @Override
@@ -38,25 +47,31 @@ public class NotificationOrderUpdate implements Parcelable {

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeStringArray(this.mKeys);
        out.writeStringArray(mKeys);
        out.writeInt(mFirstAmbientIndex);
        out.writeStringArray(mDndInterceptedKeys);
    }

    public static final Parcelable.Creator<NotificationOrderUpdate> CREATOR
            = new Parcelable.Creator<NotificationOrderUpdate>() {
        public NotificationOrderUpdate createFromParcel(Parcel parcel) {
            return new NotificationOrderUpdate(parcel);
    public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
            = new Parcelable.Creator<NotificationRankingUpdate>() {
        public NotificationRankingUpdate createFromParcel(Parcel parcel) {
            return new NotificationRankingUpdate(parcel);
        }

        public NotificationOrderUpdate[] newArray(int size) {
            return new NotificationOrderUpdate[size];
        public NotificationRankingUpdate[] newArray(int size) {
            return new NotificationRankingUpdate[size];
        }
    };

    /**
     * @hide
     * @return ordered list of keys
     */
    String[] getOrderedKeys() {
    public String[] getOrderedKeys() {
        return mKeys;
    }

    public int getFirstAmbientIndex() {
        return mFirstAmbientIndex;
    }

    public String[] getDndInterceptedKeys() {
        return mDndInterceptedKeys;
    }
}
Loading