implement assistant service connection
Added a guest-mode to ManagedServices. Like system services, the lifecycle of a guest is not managed. Unlike system services, guests are not considered privledged. The Assistant gets all the usual listener events. Implemented adjustImportance. Future work: enqueued, clicked, visibility, removed, annotations Bug: 22455414 Change-Id: Ic41c0bf625b5e98cb577b49098bba23a539bb507
This commit is contained in:
@@ -226,7 +226,6 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/service/carrier/ICarrierMessagingService.aidl \
|
||||
core/java/android/service/gatekeeper/IGateKeeperService.aidl \
|
||||
core/java/android/service/notification/INotificationListener.aidl \
|
||||
core/java/android/service/notification/INotificationAssistant.aidl \
|
||||
core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
|
||||
core/java/android/service/notification/IConditionListener.aidl \
|
||||
core/java/android/service/notification/IConditionProvider.aidl \
|
||||
|
||||
@@ -33491,20 +33491,13 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
|
||||
}
|
||||
|
||||
public class NotificationAdjustment implements android.os.Parcelable {
|
||||
ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
|
||||
ctor public NotificationAssistantService();
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
|
||||
method public final void clearAnnotation(java.lang.String);
|
||||
method public void onNotificationActionClick(java.lang.String, long, int);
|
||||
method public void onNotificationClick(java.lang.String, long);
|
||||
method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public void onNotificationRemoved(java.lang.String, long, int);
|
||||
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
|
||||
method public final void setAnnotation(java.lang.String, android.app.Notification);
|
||||
@@ -33524,6 +33517,10 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
|
||||
}
|
||||
|
||||
public class NotificationAssistantService.Adjustment {
|
||||
ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
}
|
||||
|
||||
public abstract class NotificationListenerService extends android.app.Service {
|
||||
ctor public NotificationListenerService();
|
||||
method public final void cancelAllNotifications();
|
||||
|
||||
@@ -35633,20 +35633,13 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
|
||||
}
|
||||
|
||||
public class NotificationAdjustment implements android.os.Parcelable {
|
||||
ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
|
||||
ctor public NotificationAssistantService();
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
|
||||
method public final void clearAnnotation(java.lang.String);
|
||||
method public void onNotificationActionClick(java.lang.String, long, int);
|
||||
method public void onNotificationClick(java.lang.String, long);
|
||||
method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public void onNotificationRemoved(java.lang.String, long, int);
|
||||
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
|
||||
method public final void setAnnotation(java.lang.String, android.app.Notification);
|
||||
@@ -35666,6 +35659,10 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
|
||||
}
|
||||
|
||||
public class NotificationAssistantService.Adjustment {
|
||||
ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
}
|
||||
|
||||
public abstract class NotificationListenerService extends android.app.Service {
|
||||
ctor public NotificationListenerService();
|
||||
method public final void cancelAllNotifications();
|
||||
|
||||
@@ -33494,20 +33494,13 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
|
||||
}
|
||||
|
||||
public class NotificationAdjustment implements android.os.Parcelable {
|
||||
ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
|
||||
ctor public NotificationAssistantService();
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
|
||||
method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
|
||||
method public final void clearAnnotation(java.lang.String);
|
||||
method public void onNotificationActionClick(java.lang.String, long, int);
|
||||
method public void onNotificationClick(java.lang.String, long);
|
||||
method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
|
||||
method public void onNotificationRemoved(java.lang.String, long, int);
|
||||
method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
|
||||
method public final void setAnnotation(java.lang.String, android.app.Notification);
|
||||
@@ -33527,6 +33520,10 @@ package android.service.notification {
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
|
||||
}
|
||||
|
||||
public class NotificationAssistantService.Adjustment {
|
||||
ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
|
||||
}
|
||||
|
||||
public abstract class NotificationListenerService extends android.app.Service {
|
||||
ctor public NotificationListenerService();
|
||||
method public final void cancelAllNotifications();
|
||||
|
||||
@@ -78,6 +78,8 @@ interface INotificationManager
|
||||
void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
|
||||
void setInterruptionFilter(String pkg, int interruptionFilter);
|
||||
|
||||
void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
|
||||
|
||||
ComponentName getEffectsSuppressor();
|
||||
boolean matchesCallFilter(in Bundle extras);
|
||||
boolean isSystemConditionProviderEnabled(String path);
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2015, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.notification;
|
||||
|
||||
import android.service.notification.NotificationAdjustment;
|
||||
import android.service.notification.IStatusBarNotificationHolder;
|
||||
import android.service.notification.NotificationRankingUpdate;
|
||||
|
||||
/** @hide */
|
||||
interface INotificationAssistant
|
||||
{
|
||||
void onListenerConnected(in NotificationRankingUpdate update);
|
||||
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
|
||||
in NotificationRankingUpdate update);
|
||||
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
|
||||
void onListenerHintsChanged(int hints);
|
||||
void onInterruptionFilterChanged(int interruptionFilter);
|
||||
NotificationAdjustment onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
|
||||
void onNotificationVisibilityChanged(String key, long time, boolean visible);
|
||||
void onNotificationClick(String key, long time);
|
||||
void onNotificationActionClick(String key, long time, int actionIndex);
|
||||
void onNotificationRemoved(String key, long time, int reason);
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import android.service.notification.NotificationRankingUpdate;
|
||||
/** @hide */
|
||||
oneway interface INotificationListener
|
||||
{
|
||||
// listeners and assistants
|
||||
void onListenerConnected(in NotificationRankingUpdate update);
|
||||
void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
|
||||
in NotificationRankingUpdate update);
|
||||
@@ -31,4 +32,11 @@ oneway interface INotificationListener
|
||||
void onNotificationRankingUpdate(in NotificationRankingUpdate update);
|
||||
void onListenerHintsChanged(int hints);
|
||||
void onInterruptionFilterChanged(int interruptionFilter);
|
||||
|
||||
// assistants only
|
||||
void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
|
||||
void onNotificationVisibilityChanged(String key, long time, boolean visible);
|
||||
void onNotificationClick(String key, long time);
|
||||
void onNotificationActionClick(String key, long time, int actionIndex);
|
||||
void onNotificationRemovedReason(String key, long time, int reason);
|
||||
}
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package android.service.notification;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class NotificationAdjustment implements Parcelable {
|
||||
int mImportance;
|
||||
CharSequence mExplanation;
|
||||
Uri mReference;
|
||||
|
||||
/**
|
||||
* Create a notification importance adjustment.
|
||||
*
|
||||
* @param importance The final importance of the notification.
|
||||
* @param explanation A human-readable justification for the adjustment.
|
||||
* @param reference A reference to an external object that augments the
|
||||
* explanation, such as a
|
||||
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
|
||||
* or null.
|
||||
*/
|
||||
public NotificationAdjustment(int importance, CharSequence explanation, Uri reference) {
|
||||
mImportance = importance;
|
||||
mExplanation = explanation;
|
||||
mReference = reference;
|
||||
}
|
||||
|
||||
private NotificationAdjustment(Parcel source) {
|
||||
this(source.readInt(), source.readCharSequence(),
|
||||
(Uri) source.readParcelable(NotificationAdjustment.class.getClassLoader()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mImportance);
|
||||
dest.writeCharSequence(mExplanation);
|
||||
dest.writeParcelable(mReference, 0);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<NotificationAdjustment> CREATOR
|
||||
= new Parcelable.Creator<NotificationAdjustment>() {
|
||||
@Override
|
||||
public NotificationAdjustment createFromParcel(Parcel source) {
|
||||
return new NotificationAdjustment(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationAdjustment[] newArray(int size) {
|
||||
return new NotificationAdjustment[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -20,8 +20,11 @@ import android.annotation.SdkConstant;
|
||||
import android.app.Notification;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* A service that helps the user manage notifications by modifying the
|
||||
@@ -39,6 +42,8 @@ import android.os.Parcelable;
|
||||
* </service></pre>
|
||||
*/
|
||||
public abstract class NotificationAssistantService extends NotificationListenerService {
|
||||
private static final String TAG = "NotificationAssistant";
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
@@ -85,6 +90,36 @@ public abstract class NotificationAssistantService extends NotificationListenerS
|
||||
/** Notification was canceled because it was an invisible member of a group. */
|
||||
public static final int REASON_GROUP_OPTIMIZATION = 13;
|
||||
|
||||
public class Adjustment {
|
||||
int mImportance;
|
||||
CharSequence mExplanation;
|
||||
Uri mReference;
|
||||
|
||||
/**
|
||||
* Create a notification importance adjustment.
|
||||
*
|
||||
* @param importance The final importance of the notification.
|
||||
* @param explanation A human-readable justification for the adjustment.
|
||||
* @param reference A reference to an external object that augments the
|
||||
* explanation, such as a
|
||||
* {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
|
||||
* or null.
|
||||
*/
|
||||
public Adjustment(int importance, CharSequence explanation, Uri reference) {
|
||||
mImportance = importance;
|
||||
mExplanation = explanation;
|
||||
mReference = reference;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new NotificationAssistantWrapper();
|
||||
}
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* A notification was posted by an app. Called before alert.
|
||||
*
|
||||
@@ -93,7 +128,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
|
||||
* @param user true if the initial importance reflects an explicit user preference.
|
||||
* @return an adjustment or null to take no action, within 100ms.
|
||||
*/
|
||||
abstract public NotificationAdjustment onNotificationEnqueued(StatusBarNotification sbn,
|
||||
abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
|
||||
int importance, boolean user);
|
||||
|
||||
/**
|
||||
@@ -150,9 +185,15 @@ public abstract class NotificationAssistantService extends NotificationListenerS
|
||||
* @param key the notification key
|
||||
* @param adjustment the new importance with an explanation
|
||||
*/
|
||||
public final void adjustImportance(String key, NotificationAdjustment adjustment)
|
||||
public final void adjustImportance(String key, Adjustment adjustment)
|
||||
{
|
||||
// TODO: pack up the adjustment and send it to the NotificationManager.
|
||||
if (!isBound()) return;
|
||||
try {
|
||||
getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
|
||||
adjustment.mImportance, adjustment.mExplanation);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -160,7 +201,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
|
||||
* be fired when the host notification is deleted, or when this annotation
|
||||
* is removed or replaced.
|
||||
*
|
||||
* @param key the notification key
|
||||
* @param key the key of the notification to be annotated
|
||||
* @param annotation the new annotation object
|
||||
*/
|
||||
public final void setAnnotation(String key, Notification annotation)
|
||||
@@ -171,10 +212,74 @@ public abstract class NotificationAssistantService extends NotificationListenerS
|
||||
/**
|
||||
* Remove the annotation from a notification.
|
||||
*
|
||||
* @param key the notification key
|
||||
* @param key the key of the notification to be cleansed of annotatons
|
||||
*/
|
||||
public final void clearAnnotation(String key)
|
||||
{
|
||||
// TODO: ask the NotificationManager to clear the annotation.
|
||||
}
|
||||
|
||||
private class NotificationAssistantWrapper extends NotificationListenerWrapper {
|
||||
@Override
|
||||
public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
|
||||
int importance, boolean user) throws RemoteException {
|
||||
StatusBarNotification sbn;
|
||||
try {
|
||||
sbn = sbnHolder.get();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Adjustment adjustment =
|
||||
NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
|
||||
if (adjustment != null) {
|
||||
adjustImportance(sbn.getKey(), adjustment);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onNotificationEnqueued", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationVisibilityChanged(String key, long time, boolean visible)
|
||||
throws RemoteException {
|
||||
try {
|
||||
NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
|
||||
visible);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationClick(String key, long time) throws RemoteException {
|
||||
try {
|
||||
NotificationAssistantService.this.onNotificationClick(key, time);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onNotificationClick", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationActionClick(String key, long time, int actionIndex)
|
||||
throws RemoteException {
|
||||
try {
|
||||
NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onNotificationActionClick", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRemovedReason(String key, long time, int reason)
|
||||
throws RemoteException {
|
||||
try {
|
||||
NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, "Error running onNotificationRemoved", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
package android.service.notification;
|
||||
import android.service.notification.IStatusBarNotificationHolder;
|
||||
|
||||
import android.annotation.SystemApi;
|
||||
import android.annotation.SdkConstant;
|
||||
@@ -151,7 +152,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
@SystemApi
|
||||
public static final int TRIM_LIGHT = 1;
|
||||
|
||||
private INotificationListenerWrapper mWrapper = null;
|
||||
/** @hide */
|
||||
protected NotificationListenerWrapper mWrapper = null;
|
||||
private RankingMap mRankingMap;
|
||||
|
||||
private INotificationManager mNoMan;
|
||||
@@ -291,7 +293,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
// optional
|
||||
}
|
||||
|
||||
private final INotificationManager getNotificationInterface() {
|
||||
/** @hide */
|
||||
protected final INotificationManager getNotificationInterface() {
|
||||
if (mNoMan == null) {
|
||||
mNoMan = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
@@ -634,12 +637,13 @@ public abstract class NotificationListenerService extends Service {
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new INotificationListenerWrapper();
|
||||
mWrapper = new NotificationListenerWrapper();
|
||||
}
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
private boolean isBound() {
|
||||
/** @hide */
|
||||
protected boolean isBound() {
|
||||
if (mWrapper == null) {
|
||||
Log.w(TAG, "Notification listener service not yet bound.");
|
||||
return false;
|
||||
@@ -664,7 +668,7 @@ public abstract class NotificationListenerService extends Service {
|
||||
int currentUser) throws RemoteException {
|
||||
mSystemContext = context;
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new INotificationListenerWrapper();
|
||||
mWrapper = new NotificationListenerWrapper();
|
||||
}
|
||||
INotificationManager noMan = getNotificationInterface();
|
||||
noMan.registerListener(mWrapper, componentName, currentUser);
|
||||
@@ -716,7 +720,8 @@ public abstract class NotificationListenerService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private class INotificationListenerWrapper extends INotificationListener.Stub {
|
||||
/** @hide */
|
||||
protected class NotificationListenerWrapper extends INotificationListener.Stub {
|
||||
@Override
|
||||
public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
|
||||
NotificationRankingUpdate update) {
|
||||
@@ -817,6 +822,35 @@ public abstract class NotificationListenerService extends Service {
|
||||
Log.w(TAG, "Error running onInterruptionFilterChanged", t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
|
||||
int importance, boolean user) throws RemoteException {
|
||||
// no-op in the listener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationVisibilityChanged(String key, long time, boolean visible)
|
||||
throws RemoteException {
|
||||
// no-op in the listener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationClick(String key, long time) throws RemoteException {
|
||||
// no-op in the listener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationActionClick(String key, long time, int actionIndex)
|
||||
throws RemoteException {
|
||||
// no-op in the listener
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNotificationRemovedReason(String key, long time, int reason)
|
||||
throws RemoteException {
|
||||
// no-op in the listener
|
||||
}
|
||||
}
|
||||
|
||||
private void applyUpdate(NotificationRankingUpdate update) {
|
||||
|
||||
@@ -120,6 +120,11 @@ public class ConditionProviders extends ManagedServices {
|
||||
return IConditionProvider.Stub.asInterface(binder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkType(IInterface service) {
|
||||
return service instanceof IConditionProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhaseAppsCanStart() {
|
||||
super.onBootPhaseAppsCanStart();
|
||||
|
||||
@@ -141,6 +141,8 @@ abstract public class ManagedServices {
|
||||
|
||||
abstract protected IInterface asInterface(IBinder binder);
|
||||
|
||||
abstract protected boolean checkType(IInterface service);
|
||||
|
||||
abstract protected void onServiceAdded(ManagedServiceInfo info);
|
||||
|
||||
protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
|
||||
@@ -169,7 +171,8 @@ abstract public class ManagedServices {
|
||||
if (filter != null && !filter.matches(info.component)) continue;
|
||||
pw.println(" " + info.component
|
||||
+ " (user " + info.userid + "): " + info.service
|
||||
+ (info.isSystem?" SYSTEM":""));
|
||||
+ (info.isSystem?" SYSTEM":"")
|
||||
+ (info.isGuest(this)?" GUEST":""));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,6 +269,18 @@ abstract public class ManagedServices {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a service to our callbacks. The lifecycle of this service is managed externally,
|
||||
* but unlike a system service, it should not be considered privledged.
|
||||
* */
|
||||
public void registerGuestService(ManagedServiceInfo guest) {
|
||||
checkNotNull(guest.service);
|
||||
checkType(guest.service);
|
||||
if (registerServiceImpl(guest) != null) {
|
||||
onServiceAdded(guest);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCategoryState(String category, boolean enabled) {
|
||||
synchronized (mMutex) {
|
||||
final Boolean previous = mCategoryEnabled.put(category, enabled);
|
||||
@@ -484,7 +499,7 @@ abstract public class ManagedServices {
|
||||
synchronized (mMutex) {
|
||||
// Unbind automatically bound services, retain system services.
|
||||
for (ManagedServiceInfo service : mServices) {
|
||||
if (!service.isSystem) {
|
||||
if (!service.isSystem && !service.isGuest(this)) {
|
||||
toRemove.add(service);
|
||||
}
|
||||
}
|
||||
@@ -709,11 +724,15 @@ abstract public class ManagedServices {
|
||||
|
||||
private ManagedServiceInfo registerServiceImpl(final IInterface service,
|
||||
final ComponentName component, final int userid) {
|
||||
ManagedServiceInfo info = newServiceInfo(service, component, userid,
|
||||
true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
|
||||
return registerServiceImpl(info);
|
||||
}
|
||||
|
||||
private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
|
||||
synchronized (mMutex) {
|
||||
try {
|
||||
ManagedServiceInfo info = newServiceInfo(service, component, userid,
|
||||
true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
|
||||
service.asBinder().linkToDeath(info, 0);
|
||||
info.service.asBinder().linkToDeath(info, 0);
|
||||
mServices.add(info);
|
||||
return info;
|
||||
} catch (RemoteException e) {
|
||||
@@ -728,7 +747,7 @@ abstract public class ManagedServices {
|
||||
*/
|
||||
private void unregisterServiceImpl(IInterface service, int userid) {
|
||||
ManagedServiceInfo info = removeServiceImpl(service, userid);
|
||||
if (info != null && info.connection != null) {
|
||||
if (info != null && info.connection != null && !info.isGuest(this)) {
|
||||
mContext.unbindService(info.connection);
|
||||
}
|
||||
}
|
||||
@@ -780,6 +799,10 @@ abstract public class ManagedServices {
|
||||
this.targetSdkVersion = targetSdkVersion;
|
||||
}
|
||||
|
||||
public boolean isGuest(ManagedServices host) {
|
||||
return ManagedServices.this != host;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("ManagedServiceInfo[")
|
||||
|
||||
@@ -39,6 +39,7 @@ import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
|
||||
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.AppGlobals;
|
||||
@@ -96,6 +97,7 @@ import android.service.notification.Condition;
|
||||
import android.service.notification.IConditionProvider;
|
||||
import android.service.notification.INotificationListener;
|
||||
import android.service.notification.IStatusBarNotificationHolder;
|
||||
import android.service.notification.NotificationAssistantService;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.NotificationRankingUpdate;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
@@ -154,6 +156,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** {@hide} */
|
||||
public class NotificationManagerService extends SystemService {
|
||||
@@ -167,11 +170,13 @@ public class NotificationManagerService extends SystemService {
|
||||
// message codes
|
||||
static final int MESSAGE_TIMEOUT = 2;
|
||||
static final int MESSAGE_SAVE_POLICY_FILE = 3;
|
||||
static final int MESSAGE_RECONSIDER_RANKING = 4;
|
||||
static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
|
||||
static final int MESSAGE_SEND_RANKING_UPDATE = 6;
|
||||
static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
|
||||
static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
|
||||
static final int MESSAGE_SEND_RANKING_UPDATE = 4;
|
||||
static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
|
||||
static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
|
||||
|
||||
// ranking thread messages
|
||||
private static final int MESSAGE_RECONSIDER_RANKING = 1000;
|
||||
private static final int MESSAGE_RANKING_SORT = 1001;
|
||||
|
||||
static final int LONG_DELAY = 3500; // 3.5 seconds
|
||||
static final int SHORT_DELAY = 2000; // 2 seconds
|
||||
@@ -281,11 +286,13 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
private final UserProfiles mUserProfiles = new UserProfiles();
|
||||
private NotificationListeners mListeners;
|
||||
private NotificationAssistant mAssistant;
|
||||
private ConditionProviders mConditionProviders;
|
||||
private NotificationUsageStats mUsageStats;
|
||||
|
||||
private static final int MY_UID = Process.myUid();
|
||||
private static final int MY_PID = Process.myPid();
|
||||
private RankingHandler mRankingHandler;
|
||||
|
||||
private static class Archive {
|
||||
final int mBufferSize;
|
||||
@@ -738,6 +745,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
mListeners.onPackagesChanged(queryReplace, pkgList);
|
||||
mAssistant.onPackagesChanged(queryReplace, pkgList);
|
||||
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
|
||||
mRankingHelper.onPackagesChanged(queryReplace, pkgList);
|
||||
}
|
||||
@@ -779,6 +787,7 @@ public class NotificationManagerService extends SystemService {
|
||||
// Refresh managed services
|
||||
mConditionProviders.onUserSwitched(user);
|
||||
mListeners.onUserSwitched(user);
|
||||
mAssistant.onUserSwitched(user);
|
||||
mZenModeHelper.onUserSwitched(user);
|
||||
} else if (action.equals(Intent.ACTION_USER_ADDED)) {
|
||||
mUserProfiles.updateCache(context);
|
||||
@@ -874,8 +883,9 @@ public class NotificationManagerService extends SystemService {
|
||||
extractorNames = new String[0];
|
||||
}
|
||||
mUsageStats = new NotificationUsageStats(getContext());
|
||||
mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
|
||||
mRankingHelper = new RankingHelper(getContext(),
|
||||
new RankingWorkerHandler(mRankingThread.getLooper()),
|
||||
mRankingHandler,
|
||||
mUsageStats,
|
||||
extractorNames);
|
||||
mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
|
||||
@@ -909,6 +919,7 @@ public class NotificationManagerService extends SystemService {
|
||||
importOldBlockDb();
|
||||
|
||||
mListeners = new NotificationListeners();
|
||||
mAssistant = new NotificationAssistant();
|
||||
mStatusBar = getLocalService(StatusBarManagerInternal.class);
|
||||
mStatusBar.setNotificationDelegate(mNotificationDelegate);
|
||||
|
||||
@@ -1025,6 +1036,7 @@ public class NotificationManagerService extends SystemService {
|
||||
// bind to listener services.
|
||||
mSettingsObserver.observe();
|
||||
mListeners.onBootPhaseAppsCanStart();
|
||||
mAssistant.onBootPhaseAppsCanStart();
|
||||
mConditionProviders.onBootPhaseAppsCanStart();
|
||||
}
|
||||
}
|
||||
@@ -1896,6 +1908,22 @@ public class NotificationManagerService extends SystemService {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImportanceFromAssistant(INotificationListener token, String key,
|
||||
int importance, CharSequence explanation) {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
synchronized (mNotificationList) {
|
||||
mAssistant.checkServiceTokenLocked(token);
|
||||
NotificationRecord n = mNotificationsByKey.get(key);
|
||||
n.setImportance(importance, explanation);
|
||||
mRankingHandler.requestSort();
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private String disableNotificationEffects(NotificationRecord record) {
|
||||
@@ -2037,6 +2065,8 @@ public class NotificationManagerService extends SystemService {
|
||||
pw.print(listener.component);
|
||||
}
|
||||
pw.println(')');
|
||||
pw.println("\n Notification assistant:");
|
||||
mAssistant.dump(pw, filter);
|
||||
}
|
||||
pw.println("\n Policy access:");
|
||||
pw.print(" mPolicyAccess: "); pw.println(mPolicyAccess);
|
||||
@@ -2686,7 +2716,7 @@ public class NotificationManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRankingConfigChange() {
|
||||
private void handleRankingSort() {
|
||||
synchronized (mNotificationList) {
|
||||
final int N = mNotificationList.size();
|
||||
ArrayList<String> orderBefore = new ArrayList<String>(N);
|
||||
@@ -2788,9 +2818,9 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
}
|
||||
|
||||
private final class RankingWorkerHandler extends Handler
|
||||
private final class RankingHandlerWorker extends Handler implements RankingHandler
|
||||
{
|
||||
public RankingWorkerHandler(Looper looper) {
|
||||
public RankingHandlerWorker(Looper looper) {
|
||||
super(looper);
|
||||
}
|
||||
|
||||
@@ -2800,11 +2830,23 @@ public class NotificationManagerService extends SystemService {
|
||||
case MESSAGE_RECONSIDER_RANKING:
|
||||
handleRankingReconsideration(msg);
|
||||
break;
|
||||
case MESSAGE_RANKING_CONFIG_CHANGE:
|
||||
handleRankingConfigChange();
|
||||
case MESSAGE_RANKING_SORT:
|
||||
handleRankingSort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void requestSort() {
|
||||
removeMessages(MESSAGE_RANKING_SORT);
|
||||
sendEmptyMessage(MESSAGE_RANKING_SORT);
|
||||
}
|
||||
|
||||
public void requestReconsideration(RankingReconsideration recon) {
|
||||
Message m = Message.obtain(this,
|
||||
NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
|
||||
long delay = recon.getDelay(TimeUnit.MILLISECONDS);
|
||||
sendMessageDelayed(m, delay);
|
||||
}
|
||||
}
|
||||
|
||||
// Notifications
|
||||
@@ -3305,6 +3347,45 @@ public class NotificationManagerService extends SystemService {
|
||||
return true;
|
||||
}
|
||||
|
||||
public class NotificationAssistant extends ManagedServices {
|
||||
|
||||
public NotificationAssistant() {
|
||||
super(getContext(), mHandler, mNotificationList, mUserProfiles);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Config getConfig() {
|
||||
Config c = new Config();
|
||||
c.caption = "notification assistant";
|
||||
c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
|
||||
c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
|
||||
c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
|
||||
c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
|
||||
c.clientLabel = R.string.notification_assistant_binding_label;
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IInterface asInterface(IBinder binder) {
|
||||
return INotificationListener.Stub.asInterface(binder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkType(IInterface service) {
|
||||
return service instanceof INotificationListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceAdded(ManagedServiceInfo info) {
|
||||
mListeners.registerGuestService(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
|
||||
mListeners.unregisterService(removed.service, removed.userid);
|
||||
}
|
||||
}
|
||||
|
||||
public class NotificationListeners extends ManagedServices {
|
||||
|
||||
private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
|
||||
@@ -3331,6 +3412,11 @@ public class NotificationManagerService extends SystemService {
|
||||
return INotificationListener.Stub.asInterface(binder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkType(IInterface service) {
|
||||
return service instanceof INotificationListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceAdded(ManagedServiceInfo info) {
|
||||
final INotificationListener listener = (INotificationListener) info.service;
|
||||
@@ -3366,7 +3452,6 @@ public class NotificationManagerService extends SystemService {
|
||||
|
||||
public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
|
||||
return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.notification;
|
||||
|
||||
package android.service.notification;
|
||||
|
||||
parcelable NotificationAdjustment;
|
||||
public interface RankingHandler {
|
||||
public void requestSort();
|
||||
public void requestReconsideration(RankingReconsideration recon);
|
||||
}
|
||||
@@ -19,10 +19,7 @@ import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
@@ -40,7 +37,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class RankingHelper implements RankingConfig {
|
||||
private static final String TAG = "RankingHelper";
|
||||
@@ -73,10 +69,10 @@ public class RankingHelper implements RankingConfig {
|
||||
private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mRankingHandler;
|
||||
private final RankingHandler mRankingHandler;
|
||||
|
||||
public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
|
||||
String[] extractorNames) {
|
||||
public RankingHelper(Context context, RankingHandler rankingHandler,
|
||||
NotificationUsageStats usageStats, String[] extractorNames) {
|
||||
mContext = context;
|
||||
mRankingHandler = rankingHandler;
|
||||
|
||||
@@ -119,10 +115,7 @@ public class RankingHelper implements RankingConfig {
|
||||
try {
|
||||
RankingReconsideration recon = extractor.process(r);
|
||||
if (recon != null) {
|
||||
Message m = Message.obtain(mRankingHandler,
|
||||
NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
|
||||
long delay = recon.getDelay(TimeUnit.MILLISECONDS);
|
||||
mRankingHandler.sendMessageDelayed(m, delay);
|
||||
mRankingHandler.requestReconsideration(recon);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
Slog.w(TAG, "NotificationSignalExtractor failed.", t);
|
||||
@@ -287,7 +280,7 @@ public class RankingHelper implements RankingConfig {
|
||||
for (int i = 0; i < N; i++) {
|
||||
mSignalExtractors[i].setConfig(this);
|
||||
}
|
||||
mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
|
||||
mRankingHandler.requestSort();
|
||||
}
|
||||
|
||||
public void sort(ArrayList<NotificationRecord> notificationList) {
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.ArrayList;
|
||||
|
||||
public class RankingHelperTest extends AndroidTestCase {
|
||||
@Mock NotificationUsageStats mUsageStats;
|
||||
@Mock Handler handler;
|
||||
@Mock RankingHandler handler;
|
||||
|
||||
private Notification mNotiGroupGSortA;
|
||||
private Notification mNotiGroupGSortB;
|
||||
|
||||
Reference in New Issue
Block a user