summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--CleanSpec.mk1
-rw-r--r--api/current.txt33
-rw-r--r--core/java/android/app/INotificationManager.aidl12
-rw-r--r--core/java/android/os/Binder.java10
-rw-r--r--core/java/android/provider/Settings.java30
-rw-r--r--core/java/android/service/notification/INotificationListener.aidl (renamed from core/java/android/app/INotificationListener.aidl)4
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java138
-rw-r--r--core/java/android/service/notification/StatusBarNotification.aidl (renamed from core/java/com/android/internal/statusbar/StatusBarNotification.aidl)2
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java (renamed from core/java/com/android/internal/statusbar/StatusBarNotification.java)37
-rw-r--r--core/java/android/view/InputChannel.java12
-rw-r--r--core/java/android/webkit/WebViewFactory.java30
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl2
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl2
-rw-r--r--core/java/com/android/internal/view/InputBindResult.java2
-rw-r--r--core/jni/android_view_InputChannel.cpp11
-rw-r--r--core/res/AndroidManifest.xml14
-rw-r--r--core/res/res/layout/select_dialog.xml3
-rw-r--r--core/res/res/layout/select_dialog_holo.xml3
-rw-r--r--core/res/res/values-af/strings.xml9
-rw-r--r--core/res/res/values-am/strings.xml9
-rw-r--r--core/res/res/values-ar/strings.xml9
-rw-r--r--core/res/res/values-da/strings.xml9
-rw-r--r--core/res/res/values-es-rUS/strings.xml9
-rw-r--r--core/res/res/values-es/strings.xml9
-rw-r--r--core/res/res/values-et/strings.xml2
-rw-r--r--core/res/res/values-fa/strings.xml9
-rw-r--r--core/res/res/values-hi/strings.xml9
-rw-r--r--core/res/res/values-pl/strings.xml2
-rw-r--r--core/res/res/values-sw/strings.xml11
-rw-r--r--core/res/res/values-th/strings.xml15
-rw-r--r--core/res/res/values-tr/strings.xml9
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-zu/strings.xml9
-rw-r--r--core/res/res/values/strings.xml8
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--include/androidfw/InputTransport.h3
-rw-r--r--libs/androidfw/InputTransport.cpp5
-rw-r--r--media/java/android/media/AudioTrack.java2
-rw-r--r--media/java/android/media/MediaDrm.java25
-rw-r--r--media/jni/android_media_MediaDrm.cpp145
-rw-r--r--media/jni/android_media_MediaDrm.h19
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java2
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java25
-rw-r--r--services/java/com/android/server/NotificationManagerService.java368
-rw-r--r--services/java/com/android/server/StatusBarManagerService.java2
-rw-r--r--services/java/com/android/server/firewall/IntentFirewall.java12
-rw-r--r--services/java/com/android/server/updates/IntentFirewallInstallReceiver.java27
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java37
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java3
58 files changed, 952 insertions, 227 deletions
diff --git a/Android.mk b/Android.mk
index 2ad7a72..e70f9f3 100644
--- a/Android.mk
+++ b/Android.mk
@@ -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 \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index fc63866..4debdc2 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -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
# ************************************************
diff --git a/api/current.txt b/api/current.txt
index 653e25a..6456ce9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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 {
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 3d9b2ae..92ec3ad 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -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);
+} \ No newline at end of file
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 16b4835..e9e7551 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -152,7 +152,15 @@ public class Binder implements IBinder {
* not return until the current process is exiting.
*/
public static final native void joinThreadPool();
-
+
+ /**
+ * Returns true if the specified interface is a proxy.
+ * @hide
+ */
+ public static final boolean isProxy(IInterface iface) {
+ return iface.asBinder() != iface;
+ }
+
/**
* Default constructor initializes the object.
*/
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 03ee9eb..88ee414 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -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
/**
@@ -5398,6 +5414,20 @@ public final class Settings {
public static final String CERT_PIN_UPDATE_METADATA_URL = "cert_pin_metadata_url";
/**
+ * URL for intent firewall updates
+ * @hide
+ */
+ public static final String INTENT_FIREWALL_UPDATE_CONTENT_URL =
+ "intent_firewall_content_url";
+
+ /**
+ * URL for intent firewall update metadata
+ * @hide
+ */
+ public static final String INTENT_FIREWALL_UPDATE_METADATA_URL =
+ "intent_firewall_metadata_url";
+
+ /**
* SELinux enforcement status. If 0, permissive; if 1, enforcing.
* @hide
*/
diff --git a/core/java/android/app/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index f010a2a..425fdc1 100644
--- a/core/java/android/app/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -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
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
new file mode 100644
index 0000000..86bab2a
--- /dev/null
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -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);
+ }
+ }
+}
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl b/core/java/android/service/notification/StatusBarNotification.aidl
index bd9e89c..ba81972 100644
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.aidl
+++ b/core/java/android/service/notification/StatusBarNotification.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.statusbar;
+package android.service.notification;
parcelable StatusBarNotification;
diff --git a/core/java/com/android/internal/statusbar/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 23e87fc..ef5f8c4 100644
--- a/core/java/com/android/internal/statusbar/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -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);
diff --git a/core/java/android/view/InputChannel.java b/core/java/android/view/InputChannel.java
index a797176..40ee1ad 100644
--- a/core/java/android/view/InputChannel.java
+++ b/core/java/android/view/InputChannel.java
@@ -54,6 +54,7 @@ public final class InputChannel implements Parcelable {
private native void nativeTransferTo(InputChannel other);
private native void nativeReadFromParcel(Parcel parcel);
private native void nativeWriteToParcel(Parcel parcel);
+ private native void nativeDup(InputChannel target);
private native String nativeGetName();
@@ -64,7 +65,7 @@ public final class InputChannel implements Parcelable {
*/
public InputChannel() {
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -125,6 +126,15 @@ public final class InputChannel implements Parcelable {
nativeTransferTo(outParameter);
}
+ /**
+ * Duplicates the input channel.
+ */
+ public InputChannel dup() {
+ InputChannel target = new InputChannel();
+ nativeDup(target);
+ return target;
+ }
+
@Override
public int describeContents() {
return Parcelable.CONTENTS_FILE_DESCRIPTOR;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 18df0b1..00d87bd 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -25,8 +25,13 @@ import dalvik.system.PathClassLoader;
/**
* Top level factory, used creating all the main WebView implementation classes.
+ *
+ * @hide
*/
-class WebViewFactory {
+public final class WebViewFactory {
+ public static final String WEBVIEW_EXPERIMENTAL_PROPERTY = "persist.sys.webview.exp";
+ private static final String DEPRECATED_CHROMIUM_PROPERTY = "webview.use_chromium";
+
// Default Provider factory class name.
// TODO: When the Chromium powered WebView is ready, it should be the default factory class.
private static final String DEFAULT_WEBVIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
@@ -43,16 +48,17 @@ class WebViewFactory {
private static WebViewFactoryProvider sProviderInstance;
private static final Object sProviderLock = new Object();
+ public static boolean isExperimentalWebViewAvailable() {
+ return Build.IS_DEBUGGABLE && (new java.io.File(CHROMIUM_WEBVIEW_JAR).exists());
+ }
+
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
- // For debug builds, we allow a system property to specify that we should use the
- // Chromium powered WebView. This enables us to switch between implementations
- // at runtime. For user (release) builds, don't allow this.
- if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("webview.use_chromium", false)) {
+ if (isExperimentalWebViewEnabled()) {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
sProviderInstance = loadChromiumProvider();
@@ -76,6 +82,20 @@ class WebViewFactory {
}
}
+ // For debug builds, we allow a system property to specify that we should use the
+ // experimtanl Chromium powered WebView. This enables us to switch between
+ // implementations at runtime. For user (release) builds, don't allow this.
+ private static boolean isExperimentalWebViewEnabled() {
+ if (!isExperimentalWebViewAvailable())
+ return false;
+ if (SystemProperties.getBoolean(DEPRECATED_CHROMIUM_PROPERTY, false)) {
+ Log.w(LOGTAG, String.format("The property %s has been deprecated. Please use %s.",
+ DEPRECATED_CHROMIUM_PROPERTY, WEBVIEW_EXPERIMENTAL_PROPERTY));
+ return true;
+ }
+ return SystemProperties.getBoolean(WEBVIEW_EXPERIMENTAL_PROPERTY, false);
+ }
+
// TODO: This allows us to have the legacy and Chromium WebView coexist for development
// and side-by-side testing. After transition, remove this when no longer required.
private static WebViewFactoryProvider loadChromiumProvider() {
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 780f5b3..58b15e2 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -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
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 04e5bc9..c98ba8d 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -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
diff --git a/core/java/com/android/internal/view/InputBindResult.java b/core/java/com/android/internal/view/InputBindResult.java
index 9143c61..14afe21 100644
--- a/core/java/com/android/internal/view/InputBindResult.java
+++ b/core/java/com/android/internal/view/InputBindResult.java
@@ -84,7 +84,7 @@ public final class InputBindResult implements Parcelable {
dest.writeStrongInterface(method);
if (channel != null) {
dest.writeInt(1);
- channel.writeToParcel(dest, 0);
+ channel.writeToParcel(dest, flags);
} else {
dest.writeInt(0);
}
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 9c44a59..9fa9fe4 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -246,6 +246,15 @@ static jstring android_view_InputChannel_nativeGetName(JNIEnv* env, jobject obj)
return name;
}
+static void android_view_InputChannel_nativeDup(JNIEnv* env, jobject obj, jobject otherObj) {
+ NativeInputChannel* nativeInputChannel =
+ android_view_InputChannel_getNativeInputChannel(env, obj);
+ if (nativeInputChannel) {
+ android_view_InputChannel_setNativeInputChannel(env, otherObj,
+ new NativeInputChannel(nativeInputChannel->getInputChannel()->dup()));
+ }
+}
+
// ----------------------------------------------------------------------------
static JNINativeMethod gInputChannelMethods[] = {
@@ -262,6 +271,8 @@ static JNINativeMethod gInputChannelMethods[] = {
(void*)android_view_InputChannel_nativeWriteToParcel },
{ "nativeGetName", "()Ljava/lang/String;",
(void*)android_view_InputChannel_nativeGetName },
+ { "nativeDup", "(Landroid/view/InputChannel;)V",
+ (void*)android_view_InputChannel_nativeDup },
};
#define FIND_CLASS(var, className) \
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 666d1c6..90e3b8d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -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"/>
@@ -2301,6 +2309,12 @@
</intent-filter>
</receiver>
+ <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver" >
+ <intent-filter>
+ <action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver" >
<intent-filter>
<action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
diff --git a/core/res/res/layout/select_dialog.xml b/core/res/res/layout/select_dialog.xml
index 80d22f6..eb4d8d9 100644
--- a/core/res/res/layout/select_dialog.xml
+++ b/core/res/res/layout/select_dialog.xml
@@ -32,4 +32,5 @@
android:cacheColorHint="@null"
android:divider="?android:attr/listDividerAlertDialog"
android:scrollbars="vertical"
- android:overScrollMode="ifContentScrolls" />
+ android:overScrollMode="ifContentScrolls"
+ android:textAlignment="viewStart" />
diff --git a/core/res/res/layout/select_dialog_holo.xml b/core/res/res/layout/select_dialog_holo.xml
index 06a5d96..8a92283 100644
--- a/core/res/res/layout/select_dialog_holo.xml
+++ b/core/res/res/layout/select_dialog_holo.xml
@@ -30,4 +30,5 @@
android:cacheColorHint="@null"
android:divider="?android:attr/listDividerAlertDialog"
android:scrollbars="vertical"
- android:overScrollMode="ifContentScrolls" />
+ android:overScrollMode="ifContentScrolls"
+ android:textAlignment="viewStart" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index f72fddb..1e266ed 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string>
<string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
<string name="owner_name" msgid="2716755460376028154">"Eienaar"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Fout"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Hierdie program werk nie met rekeninge vir beperkte gebruikers nie"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Geen program gevind om hierdie handeling te hanteer nie"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 73c323c..54dfd50 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"ተደራሽነት ተሰርዟል።"</string>
<string name="user_switched" msgid="3768006783166984410">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
<string name="owner_name" msgid="2716755460376028154">"ባለቤት"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"ስህተት"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"ይህ መተግበሪያ የተገደቡ ተጠቃሚዎች መለያዎችን አይደግፍም"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"ይህን እርምጃ የሚያከናውን ምንም መተግበሪያ አልተገኘም"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 942968b..0c6cd78 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"تم إلغاء تسهيل الدخول."</string>
<string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"المالك"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"خطأ"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"لا يوفر هذا التطبيق حسابات للمستخدمين المقيّدين"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"لم يتم العثور على تطبيق يمكنه التعامل مع هذا الإجراء."</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index bb4eb72..d2676c9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Tilgængelighed er annulleret."</string>
<string name="user_switched" msgid="3768006783166984410">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"Ejer"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Fejl"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Denne applikation understøtter ikke konti for brugere med begrænsede rettigheder"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Der blev ikke fundet nogen applikation, der kan håndtere denne handling"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 61d768d..f3f0afc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
<string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas para usuarios restringidos."</string>
+ <string name="app_not_found" msgid="3429141853498927379">"No se encontró una aplicación para manejar esta acción."</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index bdeed44..d3e63af 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilidad cancelada"</string>
<string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="owner_name" msgid="2716755460376028154">"Propietario"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Error"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Esta aplicación no admite cuentas de usuarios limitados."</string>
+ <string name="app_not_found" msgid="3429141853498927379">"No se ha encontrado ninguna aplicación que pueda realizar esta acción."</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 9c7a28f..bb00bfc 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1477,6 +1477,6 @@
<string name="user_switched" msgid="3768006783166984410">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"Omanik"</string>
<string name="error_message_title" msgid="4510373083082500195">"Viga"</string>
- <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Rakendus ei toeta piiratud arvu kasutajate kontot"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Rakendus ei toeta piiratud õigustega kasutajate kontosid"</string>
<string name="app_not_found" msgid="3429141853498927379">"Selle toimingu käsitlemiseks ei leitud ühtegi rakendust"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 4a09361..322cbee 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"قابلیت دسترسی لغو شد."</string>
<string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"دارنده"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"خطا"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"این برنامه حساب‌های تعداد محدودی از کاربران را پشتیبانی نمی‌کند"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"برنامه‌ای برای انجام این عملکرد موجود نیست"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index b70bbc0..1b3e6d7 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुंच-योग्यता रद्द की गई."</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"स्वामी"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"त्रुटि"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"यह एप्लिकेशन सीमित उपयोगकर्ताओं के खातों का समर्थन नहीं करता है"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"इस कार्यवाही को प्रबंधित करने के लिए कोई एप्लिकेशन नहीं मिला"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 8d3122f..0414be8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -744,7 +744,7 @@
<string name="relationTypeDomesticPartner" msgid="6904807112121122133">"Partner życiowy"</string>
<string name="relationTypeFather" msgid="5228034687082050725">"Ojciec"</string>
<string name="relationTypeFriend" msgid="7313106762483391262">"Znajomy"</string>
- <string name="relationTypeManager" msgid="6365677861610137895">"Kierownik"</string>
+ <string name="relationTypeManager" msgid="6365677861610137895">"Menedżer"</string>
<string name="relationTypeMother" msgid="4578571352962758304">"Matka"</string>
<string name="relationTypeParent" msgid="4755635567562925226">"Rodzic"</string>
<string name="relationTypePartner" msgid="7266490285120262781">"Partner"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 96b013f..67b4608 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1350,7 +1350,7 @@
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"Imefanyika"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Modi ya mabadiliko"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Songa"</string>
- <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Ingiza"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"Chagua programu"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Shiriki na"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Shiriki na <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ufikivu umeghairiwa."</string>
<string name="user_switched" msgid="3768006783166984410">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"Mmiliki"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Hitilafu"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Programu hii haiwezi kutumiwa na akaunti za watumiaji waliowekewa vizuizi"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Hakuna programu iliyopatikana ili kushughulikia kitendo hiki"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 43fdeac..2d56e38 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -154,9 +154,9 @@
<string name="global_actions" product="default" msgid="2406416831541615258">"ตัวเลือกโทรศัพท์"</string>
<string name="global_action_lock" msgid="2844945191792119712">"ล็อกหน้าจอ"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"ปิดเครื่อง"</string>
- <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานข้อบกพร่อง"</string>
- <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานข้อบกพร่อง"</string>
- <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานข้อบกพร่องจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
+ <string name="global_action_bug_report" msgid="7934010578922304799">"รายงานบั๊ก"</string>
+ <string name="bugreport_title" msgid="2667494803742548533">"ใช้รายงานบั๊ก"</string>
+ <string name="bugreport_message" msgid="398447048750350456">"การดำเนินการนี้จะรวบรวมข้อมูลเกี่ยวกับสถานะปัจจุบันของอุปกรณ์ของคุณ โดยจะส่งไปในรูปแบบข้อความอีเมล อาจใช้เวลาสักครู่ตั้งแต่เริ่มการสร้างรายงานบั๊กจนกระทั่งเสร็จสมบูรณ์ โปรดอดทนรอ"</string>
<string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"โหมดปิดเสียง"</string>
<string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"ปิดเสียงไว้"</string>
<string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"เปิดเสียงแล้ว"</string>
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"ยกเลิกการเข้าถึงแล้ว"</string>
<string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="owner_name" msgid="2716755460376028154">"เจ้าของ"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"ข้อผิดพลาด"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"แอปพลิเคชันนี้ไม่สนับสนุนบัญชีของผู้ใช้บางรายที่ถูกจำกัด"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"ไม่พบแอปพลิเคชันสำหรับการทำงานนี้"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 2fddf7d..c8d3ae4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
<string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"Sahibi"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Hata"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Bu uygulama, kısıtlı kullanıcı hesaplarını desteklemiyor"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Bu eylemi gerçekleştirecek bir uygulama bulunamadı"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ed2551d..cea9369 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1478,5 +1478,5 @@
<string name="owner_name" msgid="2716755460376028154">"擁有者"</string>
<string name="error_message_title" msgid="4510373083082500195">"錯誤"</string>
<string name="app_no_restricted_accounts" msgid="5322164210667258876">"這個應用程式不支援受限的使用者帳戶。"</string>
- <string name="app_not_found" msgid="3429141853498927379">"找不到可以處理這個動作的應用程式"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"找不到支援此操作的應用程式"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a104729..8bf3aae 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1476,10 +1476,7 @@
<string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ukufinyelela kukhanseliwe."</string>
<string name="user_switched" msgid="3768006783166984410">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="owner_name" msgid="2716755460376028154">"Umnikazi"</string>
- <!-- no translation found for error_message_title (4510373083082500195) -->
- <skip />
- <!-- no translation found for app_no_restricted_accounts (5322164210667258876) -->
- <skip />
- <!-- no translation found for app_not_found (3429141853498927379) -->
- <skip />
+ <string name="error_message_title" msgid="4510373083082500195">"Iphutha"</string>
+ <string name="app_no_restricted_accounts" msgid="5322164210667258876">"Lolu hlelo lokusebenza alusekeli ama-akhawunti wabasebenzisi abakhawulelwe"</string>
+ <string name="app_not_found" msgid="3429141853498927379">"Alukho uhlelo lokusebenza olutholakele lokuphatha lesi senzo"</string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 4a15967..6bf6403 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -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>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ced0851..bb35bab 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -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" />
diff --git a/include/androidfw/InputTransport.h b/include/androidfw/InputTransport.h
index 5706bce..8712995 100644
--- a/include/androidfw/InputTransport.h
+++ b/include/androidfw/InputTransport.h
@@ -168,6 +168,9 @@ public:
*/
status_t receiveMessage(InputMessage* msg);
+ /* Returns a new object that has a duplicate of this channel's fd. */
+ sp<InputChannel> dup() const;
+
private:
String8 mName;
int mFd;
diff --git a/libs/androidfw/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
index 351c666..498389e 100644
--- a/libs/androidfw/InputTransport.cpp
+++ b/libs/androidfw/InputTransport.cpp
@@ -219,6 +219,11 @@ status_t InputChannel::receiveMessage(InputMessage* msg) {
return OK;
}
+sp<InputChannel> InputChannel::dup() const {
+ int fd = ::dup(getFd());
+ return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
+}
+
// --- InputPublisher ---
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index cd50de4..399eb7b 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -791,7 +791,7 @@ public class AudioTrack
* {@link #ERROR_INVALID_OPERATION}
*/
public int setPlaybackRate(int sampleRateInHz) {
- if (mState == STATE_UNINITIALIZED) {
+ if (mState != STATE_INITIALIZED) {
return ERROR_INVALID_OPERATION;
}
if (sampleRateInHz <= 0) {
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 3cdf261..4eb0c56 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Bundle;
+import android.os.Parcel;
import android.util.Log;
/**
@@ -136,10 +137,8 @@ public final class MediaDrm {
public static final int MEDIA_DRM_EVENT_KEY_EXPIRED = 3;
public static final int MEDIA_DRM_EVENT_VENDOR_DEFINED = 4;
- /* Do not change these values without updating their counterparts
- * in include/media/mediadrm.h!
- */
private static final int DRM_EVENT = 200;
+
private class EventHandler extends Handler
{
private MediaDrm mMediaDrm;
@@ -161,10 +160,18 @@ public final class MediaDrm {
Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
if (mOnEventListener != null) {
- Bundle bundle = msg.getData();
- byte[] sessionId = bundle.getByteArray("sessionId");
- byte[] data = bundle.getByteArray("data");
- mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+ if (msg.obj != null && msg.obj instanceof Parcel) {
+ Parcel parcel = (Parcel)msg.obj;
+ byte[] sessionId = parcel.createByteArray();
+ if (sessionId.length == 0) {
+ sessionId = null;
+ }
+ byte[] data = parcel.createByteArray();
+ if (data.length == 0) {
+ data = null;
+ }
+ mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+ }
}
return;
@@ -183,14 +190,14 @@ public final class MediaDrm {
* the cookie passed to native_setup().)
*/
private static void postEventFromNative(Object mediadrm_ref,
- int what, int arg1, int arg2, Object obj)
+ int eventType, int extra, Object obj)
{
MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
if (md == null) {
return;
}
if (md.mEventHandler != null) {
- Message m = md.mEventHandler.obtainMessage(what, arg1, arg2, obj);
+ Message m = md.mEventHandler.obtainMessage(DRM_EVENT, eventType, extra, obj);
md.mEventHandler.sendMessage(m);
}
}
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 1618edf..c32ba9d 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -21,10 +21,12 @@
#include "android_media_MediaDrm.h"
#include "android_runtime/AndroidRuntime.h"
+#include "android_os_Parcel.h"
#include "jni.h"
#include "JNIHelp.h"
#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
#include <media/IDrm.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -43,6 +45,15 @@ namespace android {
var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method " fieldName);
+#define GET_STATIC_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetStaticFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_STATIC_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method " fieldName);
+
+
struct RequestFields {
jfieldID data;
jfieldID defaultUrl;
@@ -74,8 +85,16 @@ struct EntryFields {
jmethodID getValue;
};
+struct EventTypes {
+ int kEventProvisionRequired;
+ int kEventKeyRequired;
+ int kEventKeyExpired;
+ int kEventVendorDefined;
+} gEventTypes;
+
struct fields_t {
jfieldID context;
+ jmethodID post_event;
RequestFields keyRequest;
RequestFields provisionRequest;
ArrayListFields arraylist;
@@ -87,6 +106,88 @@ struct fields_t {
static fields_t gFields;
+// ----------------------------------------------------------------------------
+// ref-counted object for callbacks
+class JNIDrmListener: public DrmListener
+{
+public:
+ JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
+ ~JNIDrmListener();
+ virtual void notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj = NULL);
+private:
+ JNIDrmListener();
+ jclass mClass; // Reference to MediaDrm class
+ jobject mObject; // Weak ref to MediaDrm Java object to call on
+};
+
+JNIDrmListener::JNIDrmListener(JNIEnv* env, jobject thiz, jobject weak_thiz)
+{
+ // Hold onto the MediaDrm class for use in calling the static method
+ // that posts events to the application thread.
+ jclass clazz = env->GetObjectClass(thiz);
+ if (clazz == NULL) {
+ ALOGE("Can't find android/media/MediaDrm");
+ jniThrowException(env, "java/lang/Exception", NULL);
+ return;
+ }
+ mClass = (jclass)env->NewGlobalRef(clazz);
+
+ // We use a weak reference so the MediaDrm object can be garbage collected.
+ // The reference is only used as a proxy for callbacks.
+ mObject = env->NewGlobalRef(weak_thiz);
+}
+
+JNIDrmListener::~JNIDrmListener()
+{
+ // remove global references
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mObject);
+ env->DeleteGlobalRef(mClass);
+}
+
+void JNIDrmListener::notify(DrmPlugin::EventType eventType, int extra,
+ const Parcel *obj)
+{
+ jint jeventType;
+
+ // translate DrmPlugin event types into their java equivalents
+ switch(eventType) {
+ case DrmPlugin::kDrmPluginEventProvisionRequired:
+ jeventType = gEventTypes.kEventProvisionRequired;
+ break;
+ case DrmPlugin::kDrmPluginEventKeyNeeded:
+ jeventType = gEventTypes.kEventKeyRequired;
+ break;
+ case DrmPlugin::kDrmPluginEventKeyExpired:
+ jeventType = gEventTypes.kEventKeyExpired;
+ break;
+ case DrmPlugin::kDrmPluginEventVendorDefined:
+ jeventType = gEventTypes.kEventVendorDefined;
+ break;
+ default:
+ ALOGE("Invalid event DrmPlugin::EventType %d, ignored", (int)eventType);
+ return;
+ }
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ if (obj && obj->dataSize() > 0) {
+ jobject jParcel = createJavaParcelObject(env);
+ if (jParcel != NULL) {
+ Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
+ nativeParcel->setData(obj->data(), obj->dataSize());
+ env->CallStaticVoidMethod(mClass, gFields.post_event, mObject,
+ jeventType, extra, jParcel);
+ }
+ }
+
+ if (env->ExceptionCheck()) {
+ ALOGW("An exception occurred while notifying an event.");
+ LOGW_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+
static bool throwExceptionAsNecessary(
JNIEnv *env, status_t err, const char *msg = NULL) {
@@ -109,6 +210,9 @@ JDrm::JDrm(
JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
mObject = env->NewWeakGlobalRef(thiz);
mDrm = MakeDrm(uuid);
+ if (mDrm != NULL) {
+ mDrm->setListener(this);
+ }
}
JDrm::~JDrm() {
@@ -160,6 +264,25 @@ sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
return drm;
}
+status_t JDrm::setListener(const sp<DrmListener>& listener) {
+ Mutex::Autolock lock(mLock);
+ mListener = listener;
+ return OK;
+}
+
+void JDrm::notify(DrmPlugin::EventType eventType, int extra, const Parcel *obj) {
+ sp<DrmListener> listener;
+ mLock.lock();
+ listener = mListener;
+ mLock.unlock();
+
+ if (listener != NULL) {
+ Mutex::Autolock lock(mNotifyLock);
+ listener->notify(eventType, extra, obj);
+ }
+}
+
+
// static
bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
sp<IDrm> drm = MakeDrm();
@@ -194,10 +317,9 @@ static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector)
}
static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
- jboolean isCopy;
String8 result;
- const char *s = env->GetStringUTFChars(jstr, &isCopy);
+ const char *s = env->GetStringUTFChars(jstr, NULL);
if (s) {
result = s;
env->ReleaseStringUTFChars(jstr, s);
@@ -322,13 +444,28 @@ static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jse
}
static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
- setDrm(env, thiz, NULL);
+ sp<JDrm> drm = setDrm(env, thiz, NULL);
+ if (drm != NULL) {
+ drm->setListener(NULL);
+ }
}
static void android_media_MediaDrm_native_init(JNIEnv *env) {
jclass clazz;
FIND_CLASS(clazz, "android/media/MediaDrm");
GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
+ GET_STATIC_METHOD_ID(gFields.post_event, clazz, "postEventFromNative",
+ "(Ljava/lang/Object;IILjava/lang/Object;)V");
+
+ jfieldID field;
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_PROVISION_REQUIRED", "I");
+ gEventTypes.kEventProvisionRequired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_REQUIRED", "I");
+ gEventTypes.kEventKeyRequired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_KEY_EXPIRED", "I");
+ gEventTypes.kEventKeyExpired = env->GetStaticIntField(clazz, field);
+ GET_STATIC_FIELD_ID(field, clazz, "MEDIA_DRM_EVENT_VENDOR_DEFINED", "I");
+ gEventTypes.kEventVendorDefined = env->GetStaticIntField(clazz, field);
FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
GET_FIELD_ID(gFields.keyRequest.data, clazz, "data", "[B");
@@ -389,6 +526,8 @@ static void android_media_MediaDrm_native_setup(
return;
}
+ sp<JNIDrmListener> listener = new JNIDrmListener(env, thiz, weak_this);
+ drm->setListener(listener);
setDrm(env, thiz, drm);
}
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
index 01067c4..9b3917f 100644
--- a/media/jni/android_media_MediaDrm.h
+++ b/media/jni/android_media_MediaDrm.h
@@ -20,6 +20,8 @@
#include "jni.h"
#include <media/stagefright/foundation/ABase.h>
+#include <media/IDrm.h>
+#include <media/IDrmClient.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -27,15 +29,24 @@ namespace android {
struct IDrm;
-struct JDrm : public RefBase {
+class DrmListener: virtual public RefBase
+{
+public:
+ virtual void notify(DrmPlugin::EventType eventType, int extra,
+ const Parcel *obj) = 0;
+};
+
+struct JDrm : public BnDrmClient {
static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);
JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
status_t initCheck() const;
-
sp<IDrm> getDrm() { return mDrm; }
+ void notify(DrmPlugin::EventType, int extra, const Parcel *obj);
+ status_t setListener(const sp<DrmListener>& listener);
+
protected:
virtual ~JDrm();
@@ -43,6 +54,10 @@ private:
jweak mObject;
sp<IDrm> mDrm;
+ sp<DrmListener> mListener;
+ Mutex mNotifyLock;
+ Mutex mLock;
+
static sp<IDrm> MakeDrm();
static sp<IDrm> MakeDrm(const uint8_t uuid[16]);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 7bdcf6e..5b911c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 752bb0c..cbbaab3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -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
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index c82f250..886ed77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9f54573..52f552b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
index ecc70d6..976dd01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/Ticker.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 0944b40..68d048d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -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";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 3d6bfe7..05bba89 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 0859874..725d9e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -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;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 413cc78..dc5de02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -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;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 3b541ec..a28c387 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1070,7 +1070,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Attach new input asks to show input");
showCurrentInputLocked(getAppShowFlags(), null);
}
- return new InputBindResult(session.session, session.channel, mCurId, mCurSeq);
+ return new InputBindResult(session.session,
+ session.channel != null ? session.channel.dup() : null, mCurId, mCurSeq);
}
InputBindResult startInputLocked(IInputMethodClient client,
@@ -2357,13 +2358,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return true;
case MSG_CREATE_SESSION: {
args = (SomeArgs)msg.obj;
+ IInputMethod method = (IInputMethod)args.arg1;
InputChannel channel = (InputChannel)args.arg2;
try {
- ((IInputMethod)args.arg1).createSession(channel,
- (IInputSessionCallback)args.arg3);
+ method.createSession(channel, (IInputSessionCallback)args.arg3);
} catch (RemoteException e) {
} finally {
- if (channel != null) {
+ // Dispose the channel if the input method is not local to this process
+ // because the remote proxy will get its own copy when unparceled.
+ if (channel != null && Binder.isProxy(method)) {
channel.dispose();
}
}
@@ -2404,16 +2407,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// There is nothing interesting about the last client dying.
}
return true;
- case MSG_BIND_METHOD:
+ case MSG_BIND_METHOD: {
args = (SomeArgs)msg.obj;
+ IInputMethodClient client = (IInputMethodClient)args.arg1;
+ InputBindResult res = (InputBindResult)args.arg2;
try {
- ((IInputMethodClient)args.arg1).onBindMethod(
- (InputBindResult)args.arg2);
+ client.onBindMethod(res);
} catch (RemoteException e) {
Slog.w(TAG, "Client died receiving input method " + args.arg2);
+ } finally {
+ // Dispose the channel if the input method is not local to this process
+ // because the remote proxy will get its own copy when unparceled.
+ if (res.channel != null && Binder.isProxy(client)) {
+ res.channel.dispose();
+ }
}
args.recycle();
return true;
+ }
case MSG_SET_ACTIVE:
try {
((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 44d730c..cfb892f 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -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;
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 1fe98af..c21d8c6 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -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;
diff --git a/services/java/com/android/server/firewall/IntentFirewall.java b/services/java/com/android/server/firewall/IntentFirewall.java
index ebbbd86..062183b 100644
--- a/services/java/com/android/server/firewall/IntentFirewall.java
+++ b/services/java/com/android/server/firewall/IntentFirewall.java
@@ -42,7 +42,9 @@ import java.util.List;
public class IntentFirewall {
private static final String TAG = "IntentFirewall";
- private static final String RULES_FILENAME = "ifw.xml";
+ // e.g. /data/system/ifw/ifw.xml or /data/secure/system/ifw/ifw.xml
+ private static final File RULES_FILE =
+ new File(Environment.getSystemSecureDirectory(), "ifw/ifw.xml");
private static final String TAG_RULES = "rules";
private static final String TAG_ACTIVITY = "activity";
@@ -93,9 +95,7 @@ public class IntentFirewall {
public IntentFirewall(AMSInterface ams) {
mAms = ams;
- File dataSystemDir = new File(Environment.getDataDirectory(), "system");
- File rulesFile = new File(dataSystemDir, RULES_FILENAME);
- readRules(rulesFile);
+ readRules(getRulesFile());
}
public boolean checkStartActivity(Intent intent, ApplicationInfo callerApp,
@@ -127,6 +127,10 @@ public class IntentFirewall {
return !block;
}
+ public static File getRulesFile() {
+ return RULES_FILE;
+ }
+
private void readRules(File rulesFile) {
FileInputStream fis;
try {
diff --git a/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
new file mode 100644
index 0000000..9185903
--- /dev/null
+++ b/services/java/com/android/server/updates/IntentFirewallInstallReceiver.java
@@ -0,0 +1,27 @@
+/*
+ * 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 com.android.server.updates;
+
+import com.android.server.firewall.IntentFirewall;
+
+public class IntentFirewallInstallReceiver extends ConfigUpdateInstallReceiver {
+
+ public IntentFirewallInstallReceiver() {
+ super(IntentFirewall.getRulesFile().getParent(), IntentFirewall.getRulesFile().getName(),
+ "metadata/", "version");
+ }
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index cbc42eb..af603fd 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5365,6 +5365,9 @@ public class WindowManagerService extends IWindowManager.Stub
if (maxLayer < winAnim.mSurfaceLayer) {
maxLayer = winAnim.mSurfaceLayer;
}
+ if (minLayer > winAnim.mSurfaceLayer) {
+ minLayer = winAnim.mSurfaceLayer;
+ }
// Don't include wallpaper in bounds calculation
if (!ws.mIsWallpaper) {
@@ -5377,17 +5380,14 @@ public class WindowManagerService extends IWindowManager.Stub
frame.union(left, top, right, bottom);
}
- if (ws.mAppToken != null && ws.mAppToken.token == appToken) {
- if (minLayer > ws.mWinAnimator.mSurfaceLayer) {
- minLayer = ws.mWinAnimator.mSurfaceLayer;
- }
- if (ws.isDisplayedLw()) {
- screenshotReady = true;
- }
- if (fullscreen) {
- // No point in continuing down through windows.
- break;
- }
+ if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
+ ws.isDisplayedLw()) {
+ screenshotReady = true;
+ }
+
+ if (fullscreen) {
+ // No point in continuing down through windows.
+ break;
}
}
@@ -5461,14 +5461,12 @@ public class WindowManagerService extends IWindowManager.Stub
rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
}
} while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
- if (DEBUG_SCREENSHOT && retryCount > MAX_SCREENSHOT_RETRIES) {
- Slog.i(TAG, "Screenshot max retries " + retryCount + " of " + appToken + " appWin="
- + (appWin == null ? "null" : (appWin + " drawState="
- + appWin.mWinAnimator.mDrawState)));
- }
+ if (retryCount > MAX_SCREENSHOT_RETRIES) Slog.i(TAG, "Screenshot max retries " +
+ retryCount + " of " + appToken + " appWin=" + (appWin == null ?
+ "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
if (rawss == null) {
- Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
+ Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
+ ") to layer " + maxLayer);
return null;
}
@@ -5481,7 +5479,7 @@ public class WindowManagerService extends IWindowManager.Stub
canvas.drawBitmap(rawss, matrix, null);
canvas.setBitmap(null);
- if (DEBUG_SCREENSHOT) {
+ if (true || DEBUG_SCREENSHOT) {
// TEST IF IT's ALL BLACK
int[] buffer = new int[bm.getWidth() * bm.getHeight()];
bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
@@ -5494,7 +5492,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (allBlack) {
Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
- (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null"));
+ (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
+ " minLayer=" + minLayer + " maxLayer=" + maxLayer);
}
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 4345098..ba160b1 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -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
{