am 5feceebb
: New NotificationListenerService.
* commit '5feceebb892d4cb5777cea3c6174b206705d456b': New NotificationListenerService.
This commit is contained in:
@ -69,7 +69,6 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/app/IAlarmManager.aidl \
|
||||
core/java/android/app/IBackupAgent.aidl \
|
||||
core/java/android/app/IInstrumentationWatcher.aidl \
|
||||
core/java/android/app/INotificationListener.aidl \
|
||||
core/java/android/app/INotificationManager.aidl \
|
||||
core/java/android/app/IProcessObserver.aidl \
|
||||
core/java/android/app/ISearchManager.aidl \
|
||||
@ -148,6 +147,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/os/IUpdateLock.aidl \
|
||||
core/java/android/os/IUserManager.aidl \
|
||||
core/java/android/os/IVibratorService.aidl \
|
||||
core/java/android/service/notification/INotificationListener.aidl \
|
||||
core/java/android/service/dreams/IDreamManager.aidl \
|
||||
core/java/android/service/dreams/IDreamService.aidl \
|
||||
core/java/android/service/wallpaper/IWallpaperConnection.aidl \
|
||||
|
@ -159,6 +159,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodCallback.*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodSession.*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/android/internal/view/IInputMethodCallback.*)
|
||||
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
|
@ -22,6 +22,7 @@ package android {
|
||||
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
|
||||
field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
|
||||
field public static final java.lang.String BIND_INPUT_METHOD = "android.permission.BIND_INPUT_METHOD";
|
||||
field public static final java.lang.String BIND_NOTIFICATION_LISTENER_SERVICE = "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE";
|
||||
field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
|
||||
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
|
||||
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
|
||||
@ -20839,6 +20840,38 @@ package android.service.dreams {
|
||||
|
||||
}
|
||||
|
||||
package android.service.notification {
|
||||
|
||||
public abstract class NotificationListenerService extends android.app.Service {
|
||||
ctor public NotificationListenerService();
|
||||
method public final void clearAllNotifications();
|
||||
method public final void clearNotification(java.lang.String, java.lang.String, int);
|
||||
method public android.os.IBinder onBind(android.content.Intent);
|
||||
method public abstract void onNotificationPosted(android.service.notification.StatusBarNotification);
|
||||
method public abstract void onNotificationRemoved(android.service.notification.StatusBarNotification);
|
||||
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
|
||||
}
|
||||
|
||||
public class StatusBarNotification implements android.os.Parcelable {
|
||||
ctor public StatusBarNotification(java.lang.String, java.lang.String, int, java.lang.String, int, int, int, android.app.Notification, android.os.UserHandle, long);
|
||||
ctor public StatusBarNotification(android.os.Parcel);
|
||||
method public android.service.notification.StatusBarNotification clone();
|
||||
method public int describeContents();
|
||||
method public int getUserId();
|
||||
method public boolean isClearable();
|
||||
method public boolean isOngoing();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public final int id;
|
||||
field public final android.app.Notification notification;
|
||||
field public final java.lang.String pkg;
|
||||
field public final long postTime;
|
||||
field public final java.lang.String tag;
|
||||
field public final android.os.UserHandle user;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.textservice {
|
||||
|
||||
public abstract class SpellCheckerService extends android.app.Service {
|
||||
|
@ -17,12 +17,12 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.app.INotificationListener;
|
||||
import android.app.ITransientNotification;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.app.Notification;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import android.service.notification.INotificationListener;
|
||||
|
||||
/** {@hide} */
|
||||
interface INotificationManager
|
||||
@ -41,7 +41,9 @@ interface INotificationManager
|
||||
StatusBarNotification[] getActiveNotifications(String callingPkg);
|
||||
StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count);
|
||||
|
||||
void registerListener(in INotificationListener listener, String pkg, int userid);
|
||||
void registerListener(in INotificationListener listener, in ComponentName component, int userid);
|
||||
void unregisterListener(in INotificationListener listener, int userid);
|
||||
}
|
||||
|
||||
void clearNotificationFromListener(in INotificationListener token, String pkg, String tag, int id);
|
||||
void clearAllNotificationsFromListener(in INotificationListener token);
|
||||
}
|
@ -655,6 +655,22 @@ public final class Settings {
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
|
||||
|
||||
/**
|
||||
* Activity Action: Show Notification listener settings.
|
||||
* <p>
|
||||
* In some cases, a matching Activity may not exist, so ensure you
|
||||
* safeguard against this.
|
||||
* <p>
|
||||
* Input: Nothing.
|
||||
* <p>
|
||||
* Output: Nothing.
|
||||
* @see android.service.notification.NotificationListenerService
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_NOTIFICATION_LISTENER_SETTINGS
|
||||
= "android.settings.NOTIFICATION_LISTENER_SETTINGS";
|
||||
|
||||
// End of Intent actions for Settings
|
||||
|
||||
/**
|
||||
|
@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app;
|
||||
package android.service.notification;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
/** @hide */
|
||||
oneway interface INotificationListener
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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.annotation.SdkConstant;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
public abstract class NotificationListenerService extends Service {
|
||||
// TAG = "NotificationListenerService[MySubclass]"
|
||||
private final String TAG = NotificationListenerService.class.getSimpleName()
|
||||
+ "[" + getClass().getSimpleName() + "]";
|
||||
|
||||
private INotificationListenerWrapper mWrapper = null;
|
||||
|
||||
private INotificationManager mNoMan;
|
||||
|
||||
/**
|
||||
* The {@link Intent} that must be declared as handled by the service.
|
||||
*/
|
||||
@SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
|
||||
public static final String SERVICE_INTERFACE
|
||||
= "android.service.notification.NotificationListenerService";
|
||||
|
||||
/**
|
||||
* Implement this method to learn about new notifications as they are posted by apps.
|
||||
*
|
||||
* @param sbn A data structure encapsulating the original {@link android.app.Notification}
|
||||
* object as well as its identifying information (tag and id) and source
|
||||
* (package name).
|
||||
*/
|
||||
public abstract void onNotificationPosted(StatusBarNotification sbn);
|
||||
|
||||
/**
|
||||
* Implement this method to learn when notifications are removed.
|
||||
* <P>
|
||||
* This might occur because the user has dismissed the notification using system UI (or another
|
||||
* notification listener) or because the app has withdrawn the notification.
|
||||
*
|
||||
* @param sbn A data structure encapsulating the original {@link android.app.Notification}
|
||||
* object as well as its identifying information (tag and id) and source
|
||||
* (package name).
|
||||
*/
|
||||
public abstract void onNotificationRemoved(StatusBarNotification sbn);
|
||||
|
||||
private final INotificationManager getNotificationInterface() {
|
||||
if (mNoMan == null) {
|
||||
mNoMan = INotificationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||
}
|
||||
return mNoMan;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the notification manager about dismissal of a single notification.
|
||||
* <p>
|
||||
* Use this if your listener has a user interface that allows the user to dismiss individual
|
||||
* notifications, similar to the behavior of Android's status bar and notification panel.
|
||||
* It should be called after the user dismisses a single notification using your UI;
|
||||
* upon being informed, the notification manager will actually remove the notification
|
||||
* and you will get an {@link #onNotificationRemoved(StatusBarNotification)} callback.
|
||||
* <P>
|
||||
* <b>Note:</b> If your listener allows the user to fire a notification's
|
||||
* {@link android.app.Notification#contentIntent} by tapping/clicking/etc., you should call
|
||||
* this method at that time <i>if</i> the Notification in question has the
|
||||
* {@link android.app.Notification#FLAG_AUTO_CANCEL} flag set.
|
||||
*
|
||||
* @param pkg Package of the notifying app.
|
||||
* @param tag Tag of the notification as specified by the notifying app in
|
||||
* {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
|
||||
* @param id ID of the notification as specified by the notifying app in
|
||||
* {@link android.app.NotificationManager#notify(String, int, android.app.Notification)}.
|
||||
*/
|
||||
public final void clearNotification(String pkg, String tag, int id) {
|
||||
try {
|
||||
getNotificationInterface().clearNotificationFromListener(mWrapper, pkg, tag, id);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the notification manager about dismissal of all notifications.
|
||||
* <p>
|
||||
* Use this if your listener has a user interface that allows the user to dismiss all
|
||||
* notifications, similar to the behavior of Android's status bar and notification panel.
|
||||
* It should be called after the user invokes the "dismiss all" function of your UI;
|
||||
* upon being informed, the notification manager will actually remove all active notifications
|
||||
* and you will get multiple {@link #onNotificationRemoved(StatusBarNotification)} callbacks.
|
||||
*
|
||||
* {@see #clearNotification(String, String, int)}
|
||||
*/
|
||||
public final void clearAllNotifications() {
|
||||
try {
|
||||
getNotificationInterface().clearAllNotificationsFromListener(mWrapper);
|
||||
} catch (android.os.RemoteException ex) {
|
||||
Log.v(TAG, "Unable to contact notification manager", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mWrapper == null) {
|
||||
mWrapper = new INotificationListenerWrapper();
|
||||
}
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
private class INotificationListenerWrapper extends INotificationListener.Stub {
|
||||
@Override
|
||||
public void onNotificationPosted(StatusBarNotification sbn) {
|
||||
NotificationListenerService.this.onNotificationPosted(sbn);
|
||||
}
|
||||
@Override
|
||||
public void onNotificationRemoved(StatusBarNotification sbn) {
|
||||
NotificationListenerService.this.onNotificationRemoved(sbn);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.statusbar;
|
||||
package android.service.notification;
|
||||
|
||||
parcelable StatusBarNotification;
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.statusbar;
|
||||
package android.service.notification;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.os.Parcel;
|
||||
@ -23,34 +23,54 @@ import android.os.UserHandle;
|
||||
|
||||
/**
|
||||
* Class encapsulating a Notification. Sent by the NotificationManagerService to clients including
|
||||
* the IStatusBar (in System UI).
|
||||
* the status bar and any {@link android.service.notification.NotificationListenerService}s.
|
||||
*/
|
||||
public class StatusBarNotification implements Parcelable {
|
||||
/** The package of the app that posted the notification. */
|
||||
public final String pkg;
|
||||
public final String basePkg;
|
||||
/** The id supplied to {@link android.app.NotificationManager#notify}. */
|
||||
public final int id;
|
||||
/** The tag supplied to {@link android.app.NotificationManager#notify}, or null if no tag
|
||||
* was specified. */
|
||||
public final String tag;
|
||||
|
||||
/** The notifying app's calling uid. @hide */
|
||||
public final int uid;
|
||||
/** The notifying app's base package. @hide */
|
||||
public final String basePkg;
|
||||
/** @hide */
|
||||
public final int initialPid;
|
||||
// TODO: make this field private and move callers to an accessor that
|
||||
// ensures sourceUser is applied.
|
||||
|
||||
/** The {@link android.app.Notification} supplied to
|
||||
* {@link android.app.NotificationManager#notify}. */
|
||||
public final Notification notification;
|
||||
public final int score;
|
||||
/** The {@link android.os.UserHandle} for whom this notification is intended. */
|
||||
public final UserHandle user;
|
||||
/** The time (in {@link System#currentTimeMillis} time) the notification was posted,
|
||||
* which may be different than {@link android.app.Notification#when}.
|
||||
*/
|
||||
public final long postTime;
|
||||
|
||||
/** This is temporarily needed for the JB MR1 PDK. */
|
||||
/** @hide */
|
||||
public final int score;
|
||||
|
||||
/** This is temporarily needed for the JB MR1 PDK.
|
||||
* @hide */
|
||||
@Deprecated
|
||||
public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
|
||||
Notification notification) {
|
||||
this(pkg, id, tag, uid, initialPid, score, notification, UserHandle.OWNER);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public StatusBarNotification(String pkg, int id, String tag, int uid, int initialPid, int score,
|
||||
Notification notification, UserHandle user) {
|
||||
this(pkg, null, id, tag, uid, initialPid, score, notification, user);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public StatusBarNotification(String pkg, String basePkg, int id, String tag, int uid,
|
||||
int initialPid, int score, Notification notification, UserHandle user) {
|
||||
this(pkg, basePkg, id, tag, uid, initialPid, score, notification, user,
|
||||
@ -147,10 +167,17 @@ public class StatusBarNotification implements Parcelable {
|
||||
this.score, this.notification);
|
||||
}
|
||||
|
||||
/** Convenience method to check the notification's flags for
|
||||
* {@link Notification#FLAG_ONGOING_EVENT}.
|
||||
*/
|
||||
public boolean isOngoing() {
|
||||
return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0;
|
||||
}
|
||||
|
||||
/** Convenience method to check the notification's flags for
|
||||
* either {@link Notification#FLAG_ONGOING_EVENT} or
|
||||
* {@link Notification#FLAG_NO_CLEAR}.
|
||||
*/
|
||||
public boolean isClearable() {
|
||||
return ((notification.flags & Notification.FLAG_ONGOING_EVENT) == 0)
|
||||
&& ((notification.flags & Notification.FLAG_NO_CLEAR) == 0);
|
@ -17,7 +17,7 @@
|
||||
package com.android.internal.statusbar;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
/** @hide */
|
||||
oneway interface IStatusBar
|
||||
|
@ -19,7 +19,7 @@ package com.android.internal.statusbar;
|
||||
import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarIconList;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
/** @hide */
|
||||
interface IStatusBarService
|
||||
|
@ -2193,6 +2193,14 @@
|
||||
android:description="@string/permdesc_accessNotifications"
|
||||
android:protectionLevel="signature|system" />
|
||||
|
||||
<!-- Must be required by an {@link
|
||||
android.service.notification.NotificationListenerService},
|
||||
to ensure that only the system can bind to it. -->
|
||||
<permission android:name="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
|
||||
android:label="@string/permlab_bindNotificationListenerService"
|
||||
android:description="@string/permdesc_bindNotificationListenerService"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- The system process is explicitly the only one allowed to launch the
|
||||
confirmation UI for full backup/restore -->
|
||||
<uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
|
||||
|
@ -1816,6 +1816,11 @@
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_accessNotifications">Allows the app to retrieve, examine, and clear notifications, including those posted by other apps.</string>
|
||||
|
||||
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permlab_bindNotificationListenerService">bind to a notification listener service</string>
|
||||
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
|
||||
<string name="permdesc_bindNotificationListenerService">Allows the holder to bind to the top-level interface of a notification listener service. Should never be needed for normal apps.</string>
|
||||
|
||||
<!-- Policy administration -->
|
||||
|
||||
<!-- Title of policy access to limiting the user's password choices -->
|
||||
@ -3508,6 +3513,9 @@
|
||||
<string name="wallpaper_binding_label">Wallpaper</string>
|
||||
<!-- Dialog title for user to select a different wallpaper from service list -->
|
||||
<string name="chooser_wallpaper">Change wallpaper</string>
|
||||
<!-- Label to show for a service that is running because it is observing
|
||||
the user's notifications. -->
|
||||
<string name="notification_listener_binding_label">Notification listener</string>
|
||||
|
||||
<!-- Do Not Translate: Alternate eri.xml -->
|
||||
<string name="alternate_eri_file">/data/eri.xml</string>
|
||||
|
@ -1638,6 +1638,7 @@
|
||||
<java-symbol type="string" name="launch_warning_title" />
|
||||
<java-symbol type="string" name="low_internal_storage_view_text" />
|
||||
<java-symbol type="string" name="low_internal_storage_view_title" />
|
||||
<java-symbol type="string" name="notification_listener_binding_label" />
|
||||
<java-symbol type="string" name="report" />
|
||||
<java-symbol type="string" name="select_input_method" />
|
||||
<java-symbol type="string" name="select_keyboard_layout_notification_title" />
|
||||
|
@ -17,11 +17,11 @@
|
||||
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.res.Configuration;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarIconList;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.internal.widget.SizeAdaptiveLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SearchPanelView;
|
||||
|
@ -20,10 +20,10 @@ import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarIconList;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
|
||||
/**
|
||||
* This class takes the functions from IStatusBar that come in on
|
||||
|
@ -16,12 +16,11 @@
|
||||
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.os.IBinder;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.systemui.R;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
@ -26,6 +26,7 @@ import android.app.ActivityManagerNative;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -76,7 +77,6 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.systemui.EventLogTags;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@ -23,10 +24,7 @@ import android.os.Handler;
|
||||
import android.text.StaticLayout;
|
||||
import android.text.Layout.Alignment;
|
||||
import android.text.TextPaint;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.TextSwitcher;
|
||||
import android.widget.TextView;
|
||||
@ -35,7 +33,6 @@ import android.widget.ImageSwitcher;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.internal.util.CharSequences;
|
||||
|
||||
import com.android.systemui.R;
|
||||
|
@ -28,16 +28,11 @@ import android.content.IntentFilter;
|
||||
import android.location.LocationManager;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.util.Slog;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
// private NM API
|
||||
import android.app.INotificationManager;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback;
|
||||
|
||||
public class LocationController extends BroadcastReceiver {
|
||||
private static final String TAG = "StatusBar.LocationController";
|
||||
|
@ -23,6 +23,7 @@ import android.app.ActivityManagerNative;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -58,7 +59,6 @@ import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
|
@ -21,9 +21,9 @@ import java.util.Arrays;
|
||||
import android.animation.LayoutTransition;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
@ -37,11 +37,9 @@ import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.StatusBarIconView;
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package com.android.systemui.statusbar.tv;
|
||||
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
@ -26,16 +26,17 @@ import android.app.AppGlobals;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.IActivityManager;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.INotificationListener;
|
||||
import android.app.ITransientNotification;
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.StatusBarManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -57,6 +58,9 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.Vibrator;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.INotificationListener;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AtomicFile;
|
||||
@ -68,8 +72,6 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityManager;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
@ -121,6 +123,8 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
private static final boolean ENABLE_BLOCKED_NOTIFICATIONS = true;
|
||||
private static final boolean ENABLE_BLOCKED_TOASTS = true;
|
||||
|
||||
private static final String ENABLED_NOTIFICATION_LISTENERS_SEPARATOR = ":";
|
||||
|
||||
final Context mContext;
|
||||
final IActivityManager mAm;
|
||||
final UserManager mUserManager;
|
||||
@ -163,8 +167,18 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
|
||||
private final AppOpsManager mAppOps;
|
||||
|
||||
private ArrayList<NotificationListenerInfo> mListeners = new ArrayList<NotificationListenerInfo>();
|
||||
private ArrayList<String> mEnabledListenersForCurrentUser = new ArrayList<String>();
|
||||
// contains connections to all connected listeners, including app services
|
||||
// and system listeners
|
||||
private ArrayList<NotificationListenerInfo> mListeners
|
||||
= new ArrayList<NotificationListenerInfo>();
|
||||
// things that will be put into mListeners as soon as they're ready
|
||||
private ArrayList<String> mServicesBinding = new ArrayList<String>();
|
||||
// lists the component names of all enabled (and therefore connected) listener
|
||||
// app services for the current user only
|
||||
private HashSet<ComponentName> mEnabledListenersForCurrentUser
|
||||
= new HashSet<ComponentName>();
|
||||
// Just the packages from mEnabledListenersForCurrentUser
|
||||
private HashSet<String> mEnabledListenerPackageNames = new HashSet<String>();
|
||||
|
||||
// Notification control database. For now just contains disabled packages.
|
||||
private AtomicFile mPolicyFile;
|
||||
@ -181,27 +195,42 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
|
||||
private class NotificationListenerInfo implements DeathRecipient {
|
||||
INotificationListener listener;
|
||||
String pkg;
|
||||
ComponentName component;
|
||||
int userid;
|
||||
boolean isSystem;
|
||||
ServiceConnection connection;
|
||||
|
||||
public NotificationListenerInfo(INotificationListener listener, String pkg, int userid,
|
||||
boolean isSystem) {
|
||||
public NotificationListenerInfo(INotificationListener listener, ComponentName component,
|
||||
int userid, boolean isSystem) {
|
||||
this.listener = listener;
|
||||
this.pkg = pkg;
|
||||
this.component = component;
|
||||
this.userid = userid;
|
||||
this.isSystem = isSystem;
|
||||
this.connection = null;
|
||||
}
|
||||
|
||||
public NotificationListenerInfo(INotificationListener listener, ComponentName component,
|
||||
int userid, ServiceConnection connection) {
|
||||
this.listener = listener;
|
||||
this.component = component;
|
||||
this.userid = userid;
|
||||
this.isSystem = false;
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
boolean enabledAndUserMatches(StatusBarNotification sbn) {
|
||||
final int nid = sbn.getUserId();
|
||||
if (!(isSystem || isEnabledForUser(nid))) return false;
|
||||
if (!isEnabledForCurrentUser()) {
|
||||
return false;
|
||||
}
|
||||
if (this.userid == UserHandle.USER_ALL) return true;
|
||||
return (nid == UserHandle.USER_ALL || nid == this.userid);
|
||||
}
|
||||
|
||||
public void notifyPostedIfUserMatch(StatusBarNotification sbn) {
|
||||
if (!enabledAndUserMatches(sbn)) return;
|
||||
if (!enabledAndUserMatches(sbn)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
listener.onNotificationPosted(sbn);
|
||||
} catch (RemoteException ex) {
|
||||
@ -220,15 +249,17 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
unregisterListener(this.listener, this.userid);
|
||||
if (connection == null) {
|
||||
// This is not a service; it won't be recreated. We can give up this connection.
|
||||
unregisterListener(this.listener, this.userid);
|
||||
}
|
||||
}
|
||||
|
||||
/** convenience method for looking in mEnabledListenersForCurrentUser */
|
||||
public boolean isEnabledForUser(int userid) {
|
||||
for (int i=0; i<mEnabledListenersForCurrentUser.size(); i++) {
|
||||
if (this.pkg.equals(mEnabledListenersForCurrentUser.get(i))) return true;
|
||||
}
|
||||
return false;
|
||||
public boolean isEnabledForCurrentUser() {
|
||||
if (this.isSystem) return true;
|
||||
if (this.connection == null) return false;
|
||||
return mEnabledListenersForCurrentUser.contains(this.component);
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,6 +465,12 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* System-only API for getting a list of current (i.e. not cleared) notifications.
|
||||
*
|
||||
* Requires ACCESS_NOTIFICATIONS which is signature|system.
|
||||
*/
|
||||
@Override
|
||||
public StatusBarNotification[] getActiveNotifications(String callingPkg) {
|
||||
// enforce() will ensure the calling uid has the correct permission
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
|
||||
@ -456,6 +493,12 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* System-only API for getting a list of recent (cleared, no longer shown) notifications.
|
||||
*
|
||||
* Requires ACCESS_NOTIFICATIONS which is signature|system.
|
||||
*/
|
||||
@Override
|
||||
public StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count) {
|
||||
// enforce() will ensure the calling uid has the correct permission
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NOTIFICATIONS,
|
||||
@ -474,27 +517,76 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
return tmp;
|
||||
}
|
||||
|
||||
boolean packageCanTapNotificationsForUser(final int uid, final String pkg) {
|
||||
// Make sure the package and uid match, and that the package is allowed access
|
||||
return (AppOpsManager.MODE_ALLOWED
|
||||
== mAppOps.checkOpNoThrow(AppOpsManager.OP_ACCESS_NOTIFICATIONS, uid, pkg));
|
||||
/**
|
||||
* Called whenever packages change, the user switches, or ENABLED_NOTIFICATION_LISTENERS
|
||||
* is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
|
||||
*/
|
||||
void rebindListenerServices() {
|
||||
String flat = Settings.Secure.getString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
|
||||
|
||||
NotificationListenerInfo[] toRemove = new NotificationListenerInfo[mListeners.size()];
|
||||
final ArrayList<ComponentName> toAdd;
|
||||
final int currentUser = ActivityManager.getCurrentUser();
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
// unbind and remove all existing listeners
|
||||
toRemove = mListeners.toArray(toRemove);
|
||||
|
||||
toAdd = new ArrayList<ComponentName>();
|
||||
final HashSet<ComponentName> newEnabled = new HashSet<ComponentName>();
|
||||
final HashSet<String> newPackages = new HashSet<String>();
|
||||
|
||||
// decode the list of components
|
||||
if (flat != null) {
|
||||
String[] components = flat.split(ENABLED_NOTIFICATION_LISTENERS_SEPARATOR);
|
||||
for (int i=0; i<components.length; i++) {
|
||||
final ComponentName component
|
||||
= ComponentName.unflattenFromString(components[i]);
|
||||
if (component != null) {
|
||||
newEnabled.add(component);
|
||||
toAdd.add(component);
|
||||
newPackages.add(component.getPackageName());
|
||||
}
|
||||
}
|
||||
|
||||
mEnabledListenersForCurrentUser = newEnabled;
|
||||
mEnabledListenerPackageNames = newPackages;
|
||||
}
|
||||
}
|
||||
|
||||
for (NotificationListenerInfo info : toRemove) {
|
||||
final ComponentName component = info.component;
|
||||
final int oldUser = info.userid;
|
||||
Slog.v(TAG, "disabling notification listener for user " + oldUser + ": " + component);
|
||||
unregisterListenerService(component, info.userid);
|
||||
}
|
||||
|
||||
final int N = toAdd.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
final ComponentName component = toAdd.get(i);
|
||||
Slog.v(TAG, "enabling notification listener for user " + currentUser + ": "
|
||||
+ component);
|
||||
registerListenerService(component, currentUser);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a listener binder directly with the notification manager.
|
||||
*
|
||||
* Only works with system callers. Apps should extend
|
||||
* {@link android.service.notification.NotificationListenerService}.
|
||||
*/
|
||||
@Override
|
||||
public void registerListener(final INotificationListener listener,
|
||||
final String pkg, final int userid) {
|
||||
// ensure system or allowed pkg
|
||||
int uid = Binder.getCallingUid();
|
||||
boolean isSystem = (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0);
|
||||
if (!(isSystem || packageCanTapNotificationsForUser(uid, pkg))) {
|
||||
throw new SecurityException("Package " + pkg
|
||||
+ " may not listen for notifications");
|
||||
}
|
||||
final ComponentName component, final int userid) {
|
||||
checkCallerIsSystem();
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
try {
|
||||
NotificationListenerInfo info
|
||||
= new NotificationListenerInfo(listener, pkg, userid, isSystem);
|
||||
= new NotificationListenerInfo(listener, component, userid, true);
|
||||
listener.asBinder().linkToDeath(info, 0);
|
||||
mListeners.add(info);
|
||||
} catch (RemoteException e) {
|
||||
@ -503,6 +595,90 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Version of registerListener that takes the name of a
|
||||
* {@link android.service.notification.NotificationListenerService} to bind to.
|
||||
*
|
||||
* This is the mechanism by which third parties may subscribe to notifications.
|
||||
*/
|
||||
private void registerListenerService(final ComponentName name, final int userid) {
|
||||
checkCallerIsSystem();
|
||||
|
||||
if (DBG) Slog.v(TAG, "registerListenerService: " + name + " u=" + userid);
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
final String servicesBindingTag = name.toString() + "/" + userid;
|
||||
if (mServicesBinding.contains(servicesBindingTag)) {
|
||||
// stop registering this thing already! we're working on it
|
||||
return;
|
||||
}
|
||||
mServicesBinding.add(servicesBindingTag);
|
||||
|
||||
final int N = mListeners.size();
|
||||
for (int i=N-1; i>=0; i--) {
|
||||
final NotificationListenerInfo info = mListeners.get(i);
|
||||
if (name.equals(info.component)
|
||||
&& info.userid == userid) {
|
||||
// cut old connections
|
||||
if (DBG) Slog.v(TAG, " disconnecting old listener: " + info.listener);
|
||||
mListeners.remove(i);
|
||||
if (info.connection != null) {
|
||||
mContext.unbindService(info.connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Intent intent = new Intent(NotificationListenerService.SERVICE_INTERFACE);
|
||||
intent.setComponent(name);
|
||||
|
||||
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
|
||||
com.android.internal.R.string.notification_listener_binding_label);
|
||||
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
|
||||
mContext, 0, new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS), 0));
|
||||
|
||||
try {
|
||||
if (DBG) Slog.v(TAG, "binding: " + intent);
|
||||
if (!mContext.bindServiceAsUser(intent,
|
||||
new ServiceConnection() {
|
||||
INotificationListener mListener;
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
synchronized (mNotificationList) {
|
||||
mServicesBinding.remove(servicesBindingTag);
|
||||
try {
|
||||
mListener = INotificationListener.Stub.asInterface(service);
|
||||
NotificationListenerInfo info = new NotificationListenerInfo(
|
||||
mListener, name, userid, this);
|
||||
service.linkToDeath(info, 0);
|
||||
mListeners.add(info);
|
||||
} catch (RemoteException e) {
|
||||
// already dead
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
Slog.v(TAG, "notification listener connection lost: " + name);
|
||||
}
|
||||
},
|
||||
Context.BIND_AUTO_CREATE,
|
||||
new UserHandle(userid)))
|
||||
{
|
||||
mServicesBinding.remove(servicesBindingTag);
|
||||
Slog.w(TAG, "Unable to bind listener service: " + intent);
|
||||
return;
|
||||
}
|
||||
} catch (SecurityException ex) {
|
||||
Slog.e(TAG, "Unable to bind listener service: " + intent, ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener binder directly
|
||||
*/
|
||||
@Override
|
||||
public void unregisterListener(INotificationListener listener, int userid) {
|
||||
// no need to check permissions; if your listener binder is in the list,
|
||||
@ -513,12 +689,39 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
for (int i=N-1; i>=0; i--) {
|
||||
final NotificationListenerInfo info = mListeners.get(i);
|
||||
if (info.listener == listener && info.userid == userid) {
|
||||
mListeners.remove(listener);
|
||||
mListeners.remove(i);
|
||||
if (info.connection != null) {
|
||||
mContext.unbindService(info.connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener service for the given user by ComponentName
|
||||
*/
|
||||
private void unregisterListenerService(ComponentName name, int userid) {
|
||||
checkCallerIsSystem();
|
||||
|
||||
synchronized (mNotificationList) {
|
||||
final int N = mListeners.size();
|
||||
for (int i=N-1; i>=0; i--) {
|
||||
final NotificationListenerInfo info = mListeners.get(i);
|
||||
if (name.equals(info.component)
|
||||
&& info.userid == userid) {
|
||||
mListeners.remove(i);
|
||||
if (info.connection != null) {
|
||||
mContext.unbindService(info.connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* asynchronously notify all listeners about a new notification
|
||||
*/
|
||||
private void notifyPostedLocked(NotificationRecord n) {
|
||||
final StatusBarNotification sbn = n.sbn;
|
||||
for (final NotificationListenerInfo info : mListeners) {
|
||||
@ -530,6 +733,9 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* asynchronously notify all listeners about a removed notification
|
||||
*/
|
||||
private void notifyRemovedLocked(NotificationRecord n) {
|
||||
final StatusBarNotification sbn = n.sbn;
|
||||
for (final NotificationListenerInfo info : mListeners) {
|
||||
@ -541,6 +747,57 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// -- APIs to support listeners clicking/clearing notifications --
|
||||
|
||||
private NotificationListenerInfo checkListenerToken(INotificationListener listener) {
|
||||
final IBinder token = listener.asBinder();
|
||||
final int N = mListeners.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
final NotificationListenerInfo info = mListeners.get(i);
|
||||
if (info.listener.asBinder() == token) return info;
|
||||
}
|
||||
throw new SecurityException("Disallowed call from unknown listener: " + listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow an INotificationListener to simulate a "clear all" operation.
|
||||
*
|
||||
* {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onClearAllNotifications}
|
||||
*
|
||||
* @param token The binder for the listener, to check that the caller is allowed
|
||||
*/
|
||||
public void clearAllNotificationsFromListener(INotificationListener token) {
|
||||
NotificationListenerInfo info = checkListenerToken(token);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
cancelAll(info.userid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow an INotificationListener to simulate clearing (dismissing) a single notification.
|
||||
*
|
||||
* {@see com.android.server.StatusBarManagerService.NotificationCallbacks#onNotificationClear}
|
||||
*
|
||||
* @param token The binder for the listener, to check that the caller is allowed
|
||||
*/
|
||||
public void clearNotificationFromListener(INotificationListener token, String pkg, String tag, int id) {
|
||||
NotificationListenerInfo info = checkListenerToken(token);
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
cancelNotification(pkg, tag, id, 0,
|
||||
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
|
||||
true,
|
||||
info.userid);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
// -- end of listener APIs --
|
||||
|
||||
public static final class NotificationRecord
|
||||
{
|
||||
final StatusBarNotification sbn;
|
||||
@ -759,12 +1016,23 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
pkgList = new String[]{pkgName};
|
||||
}
|
||||
|
||||
boolean anyListenersInvolved = false;
|
||||
if (pkgList != null && (pkgList.length > 0)) {
|
||||
for (String pkgName : pkgList) {
|
||||
cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart,
|
||||
UserHandle.USER_ALL);
|
||||
if (mEnabledListenerPackageNames.contains(pkgName)) {
|
||||
anyListenersInvolved = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (anyListenersInvolved) {
|
||||
// make sure we're still bound to any of our
|
||||
// listeners who may have just upgraded
|
||||
rebindListenerServices();
|
||||
}
|
||||
} else if (action.equals(Intent.ACTION_SCREEN_ON)) {
|
||||
// Keep track of screen on/off state, but do not turn off the notification light
|
||||
// until user passes through the lock screen or views the notification.
|
||||
@ -795,7 +1063,7 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
|
||||
|
||||
private final Uri ENABLED_NOTIFICATION_LISTENERS_URI
|
||||
= Settings.System.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
|
||||
= Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
|
||||
|
||||
SettingsObserver(Handler handler) {
|
||||
super(handler);
|
||||
@ -804,9 +1072,9 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
void observe() {
|
||||
ContentResolver resolver = mContext.getContentResolver();
|
||||
resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI,
|
||||
false, this);
|
||||
false, this, UserHandle.USER_ALL);
|
||||
resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI,
|
||||
false, this);
|
||||
false, this, UserHandle.USER_ALL);
|
||||
update(null);
|
||||
}
|
||||
|
||||
@ -825,19 +1093,7 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
}
|
||||
}
|
||||
if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) {
|
||||
String pkglist = Settings.Secure.getString(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
|
||||
mEnabledListenersForCurrentUser.clear();
|
||||
if (pkglist != null) {
|
||||
String[] pkgs = pkglist.split(";");
|
||||
for (int i=0; i<pkgs.length; i++) {
|
||||
final String pkg = pkgs[i];
|
||||
if (pkg != null && ! "".equals(pkg)) {
|
||||
mEnabledListenersForCurrentUser.add(pkgs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
rebindListenerServices();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -956,6 +1212,9 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
|
||||
// no beeping until we're basically done booting
|
||||
mSystemReady = true;
|
||||
|
||||
// make sure our listener services are properly bound
|
||||
rebindListenerServices();
|
||||
}
|
||||
|
||||
// Toasts
|
||||
@ -1781,16 +2040,17 @@ public class NotificationManagerService extends INotificationManager.Stub
|
||||
|
||||
pw.println("Current Notification Manager state:");
|
||||
|
||||
pw.print(" Enabled listeners: [");
|
||||
for (String pkg : mEnabledListenersForCurrentUser) {
|
||||
pw.print(" " + pkg);
|
||||
pw.println(" Listeners (" + mEnabledListenersForCurrentUser.size()
|
||||
+ ") enabled for current user:");
|
||||
for (ComponentName cmpt : mEnabledListenersForCurrentUser) {
|
||||
pw.println(" " + cmpt);
|
||||
}
|
||||
pw.println(" ]");
|
||||
|
||||
pw.println(" Live listeners:");
|
||||
pw.println(" Live listeners (" + mListeners.size() + "):");
|
||||
for (NotificationListenerInfo info : mListeners) {
|
||||
pw.println(" " + info.pkg + " (user " + info.userid + "): " + info.listener
|
||||
+ (info.isSystem?" SYSTEM":""));
|
||||
pw.println(" " + info.component
|
||||
+ " (user " + info.userid + "): " + info.listener
|
||||
+ (info.isSystem?" SYSTEM":""));
|
||||
}
|
||||
|
||||
int N;
|
||||
|
@ -17,6 +17,7 @@
|
||||
package com.android.server;
|
||||
|
||||
import android.app.StatusBarManager;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@ -33,7 +34,6 @@ import com.android.internal.statusbar.IStatusBar;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.internal.statusbar.StatusBarIconList;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
import com.android.server.wm.WindowManagerService;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
@ -33,13 +33,10 @@ import android.util.Log;
|
||||
import android.net.Uri;
|
||||
import android.os.SystemClock;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.os.PowerManager;
|
||||
|
||||
// private NM API
|
||||
import android.app.INotificationManager;
|
||||
import com.android.internal.statusbar.StatusBarNotification;
|
||||
|
||||
public class NotificationTestList extends TestActivity
|
||||
{
|
||||
|
Reference in New Issue
Block a user