summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Spurlock <jspurlock@google.com>2014-04-26 10:24:59 -0400
committerJohn Spurlock <jspurlock@google.com>2014-04-27 11:36:32 -0400
commite77bb36d48b6b8b5c3bb6a1195aca469bb237919 (patch)
tree29f877996112bebd253e25a18a2b731a086abfb3
parent31dc634be3610b062fbcc4afa02607ce8f4125f5 (diff)
downloadframeworks_base-e77bb36d48b6b8b5c3bb6a1195aca469bb237919.zip
frameworks_base-e77bb36d48b6b8b5c3bb6a1195aca469bb237919.tar.gz
frameworks_base-e77bb36d48b6b8b5c3bb6a1195aca469bb237919.tar.bz2
Wire up condition providers to zen mode exit triggers.
Bug:13743109 Change-Id: I4e45d7050d1f9aaa379f46379a3203e61e216a3d
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/app/INotificationManager.aidl8
-rw-r--r--core/java/android/service/notification/Condition.java46
-rw-r--r--core/java/android/service/notification/ConditionProviderService.java41
-rw-r--r--core/java/android/service/notification/IConditionListener.aidl25
-rw-r--r--core/java/android/service/notification/IConditionProvider.aidl10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java56
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java186
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java45
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java45
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java11
12 files changed, 415 insertions, 68 deletions
diff --git a/Android.mk b/Android.mk
index df8fbd9..852247c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -180,6 +180,7 @@ LOCAL_SRC_FILES += \
core/java/android/os/IUserManager.aidl \
core/java/android/os/IVibratorService.aidl \
core/java/android/service/notification/INotificationListener.aidl \
+ core/java/android/service/notification/IConditionListener.aidl \
core/java/android/service/notification/IConditionProvider.aidl \
core/java/android/print/ILayoutResultCallback.aidl \
core/java/android/print/IPrinterDiscoveryObserver.aidl \
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 045fab1..ad4027d 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -18,13 +18,15 @@
package android.app;
import android.app.ITransientNotification;
-import android.service.notification.StatusBarNotification;
import android.app.Notification;
import android.content.ComponentName;
import android.content.Intent;
+import android.net.Uri;
import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.INotificationListener;
+import android.service.notification.StatusBarNotification;
import android.service.notification.ZenModeConfig;
/** {@hide} */
@@ -55,5 +57,7 @@ interface INotificationManager
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
- void notifyCondition(in IConditionProvider provider, in Condition condition);
+ oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
+ oneway void requestZenModeConditions(in IConditionListener callback, boolean requested);
+ oneway void setZenModeCondition(in Uri conditionId);
} \ No newline at end of file
diff --git a/core/java/android/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index cfd40f3..71e3166 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,6 +16,7 @@
package android.service.notification;
+import android.content.Context;
import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,18 +30,25 @@ import java.util.Objects;
*/
public class Condition implements Parcelable {
+ public static final String SCHEME = "condition";
+
+ public static final int STATE_FALSE = 0;
+ public static final int STATE_TRUE = 1;
+ public static final int STATE_UNKNOWN = 2;
+ public static final int STATE_ERROR = 3;
+
public static final int FLAG_RELEVANT_NOW = 1 << 0;
public static final int FLAG_RELEVANT_ALWAYS = 1 << 1;
public final Uri id;
public String caption;
- public boolean state;
+ public int state;
public int flags;
-
- public Condition(Uri id, String caption, boolean state, int flags) {
+ public Condition(Uri id, String caption, int state, int flags) {
if (id == null) throw new IllegalArgumentException("id is required");
if (caption == null) throw new IllegalArgumentException("caption is required");
+ if (!isValidState(state)) throw new IllegalArgumentException("state is invalid: " + state);
this.id = id;
this.caption = caption;
this.state = state;
@@ -48,17 +56,21 @@ public class Condition implements Parcelable {
}
private Condition(Parcel source) {
- id = Uri.CREATOR.createFromParcel(source);
- caption = source.readString();
- state = source.readInt() == 1;
- flags = source.readInt();
+ this((Uri)source.readParcelable(Condition.class.getClassLoader()),
+ source.readString(),
+ source.readInt(),
+ source.readInt());
+ }
+
+ private static boolean isValidState(int state) {
+ return state >= STATE_FALSE && state <= STATE_ERROR;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(id, 0);
dest.writeString(caption);
- dest.writeInt(state ? 1 : 0);
+ dest.writeInt(state);
dest.writeInt(flags);
}
@@ -67,11 +79,19 @@ public class Condition implements Parcelable {
return new StringBuilder(Condition.class.getSimpleName()).append('[')
.append("id=").append(id)
.append(",caption=").append(caption)
- .append(",state=").append(state)
+ .append(",state=").append(stateToString(state))
.append(",flags=").append(flags)
.append(']').toString();
}
+ public static String stateToString(int state) {
+ if (state == STATE_FALSE) return "STATE_FALSE";
+ if (state == STATE_TRUE) return "STATE_TRUE";
+ if (state == STATE_UNKNOWN) return "STATE_UNKNOWN";
+ if (state == STATE_ERROR) return "STATE_ERROR";
+ throw new IllegalArgumentException("state is invalid: " + state);
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof Condition)) return false;
@@ -104,6 +124,14 @@ public class Condition implements Parcelable {
}
}
+ public static Uri.Builder newId(Context context) {
+ return new Uri.Builder().scheme(SCHEME).authority(context.getPackageName());
+ }
+
+ public static boolean isValidId(Uri id, String pkg) {
+ return id != null && id.getScheme().equals(SCHEME) && id.getAuthority().equals(pkg);
+ }
+
public static final Parcelable.Creator<Condition> CREATOR
= new Parcelable.Creator<Condition>() {
@Override
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 8777e50..70d474e 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -56,11 +56,10 @@ public abstract class ConditionProviderService extends Service {
public static final String SERVICE_INTERFACE
= "android.service.notification.ConditionProviderService";
-
- abstract public Condition[] queryConditions(int relevance);
- abstract public Condition[] getConditions(Uri[] conditionIds);
- abstract public boolean subscribe(Uri conditionId);
- abstract public boolean unsubscribe(Uri conditionId);
+ abstract public void onConnected();
+ abstract public void onRequestConditions(int relevance);
+ abstract public void onSubscribe(Uri conditionId);
+ abstract public void onUnsubscribe(Uri conditionId);
private final INotificationManager getNotificationInterface() {
if (mNoMan == null) {
@@ -70,10 +69,10 @@ public abstract class ConditionProviderService extends Service {
return mNoMan;
}
- public final void notifyCondition(Condition condition) {
+ public final void notifyConditions(Condition[] conditions) {
if (!isBound()) return;
try {
- getNotificationInterface().notifyCondition(mProvider, condition);
+ getNotificationInterface().notifyConditions(getPackageName(), mProvider, conditions);
} catch (android.os.RemoteException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
@@ -99,42 +98,38 @@ public abstract class ConditionProviderService extends Service {
private final ConditionProviderService mService = ConditionProviderService.this;
@Override
- public Condition[] queryConditions(int relevance) {
+ public void onConnected() {
try {
- return mService.queryConditions(relevance);
+ mService.onConnected();
} catch (Throwable t) {
- Log.w(TAG, "Error running queryConditions", t);
- return null;
+ Log.w(TAG, "Error running onConnected", t);
}
}
@Override
- public Condition[] getConditions(Uri[] conditionIds) {
+ public void onRequestConditions(int relevance) {
try {
- return mService.getConditions(conditionIds);
+ mService.onRequestConditions(relevance);
} catch (Throwable t) {
- Log.w(TAG, "Error running getConditions", t);
- return null;
+ Log.w(TAG, "Error running onRequestConditions", t);
}
}
@Override
- public boolean subscribe(Uri conditionId) {
+ public void onSubscribe(Uri conditionId) {
try {
- return mService.subscribe(conditionId);
+ mService.onSubscribe(conditionId);
} catch (Throwable t) {
- Log.w(TAG, "Error running subscribe", t);
- return false;
+ Log.w(TAG, "Error running onSubscribe", t);
}
}
@Override
- public boolean unsubscribe(Uri conditionId) {
+ public void onUnsubscribe(Uri conditionId) {
try {
- return mService.unsubscribe(conditionId);
+ mService.onUnsubscribe(conditionId);
} catch (Throwable t) {
- Log.w(TAG, "Error running unsubscribe", t);
- return false;
+ Log.w(TAG, "Error running onUnsubscribe", t);
}
}
}
diff --git a/core/java/android/service/notification/IConditionListener.aidl b/core/java/android/service/notification/IConditionListener.aidl
new file mode 100644
index 0000000..01f874f
--- /dev/null
+++ b/core/java/android/service/notification/IConditionListener.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2014, 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.net.Uri;
+import android.service.notification.Condition;
+
+/** @hide */
+oneway interface IConditionListener {
+ void onConditionsReceived(in Condition[] conditions);
+} \ No newline at end of file
diff --git a/core/java/android/service/notification/IConditionProvider.aidl b/core/java/android/service/notification/IConditionProvider.aidl
index cb582da..ada8939 100644
--- a/core/java/android/service/notification/IConditionProvider.aidl
+++ b/core/java/android/service/notification/IConditionProvider.aidl
@@ -20,9 +20,9 @@ import android.net.Uri;
import android.service.notification.Condition;
/** @hide */
-interface IConditionProvider {
- Condition[] queryConditions(int relevance);
- Condition[] getConditions(in Uri[] conditionIds);
- boolean subscribe(in Uri conditionId);
- boolean unsubscribe(in Uri conditionId);
+oneway interface IConditionProvider {
+ void onConnected();
+ void onRequestConditions(int relevance);
+ void onSubscribe(in Uri conditionId);
+ void onUnsubscribe(in Uri conditionId);
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
index c1662ba..20011ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeView.java
@@ -212,6 +212,13 @@ public class ZenModeView extends RelativeLayout {
}
}
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mAdapter != null) {
+ mAdapter.dispose();
+ }
+ }
+
public void setAutoActivate(boolean value) {
mAutoActivate = value;
}
@@ -396,6 +403,7 @@ public class ZenModeView extends RelativeLayout {
void setMode(boolean mode);
void select(ExitCondition ec);
void init();
+ void dispose();
void setCallbacks(Callbacks callbacks);
ExitCondition getExitCondition(int d);
int getExitConditionCount();
@@ -406,6 +414,7 @@ public class ZenModeView extends RelativeLayout {
public String line1;
public String line2;
public String action;
+ public Object tag;
}
public interface Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
index c97ba8d..a5e016a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ZenModeViewAdapter.java
@@ -16,14 +16,22 @@
package com.android.systemui.statusbar.phone;
+import android.app.INotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
+import android.net.Uri;
import android.os.AsyncTask;
import android.os.Handler;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.provider.Settings;
+import android.service.notification.Condition;
+import android.service.notification.IConditionListener;
+import android.util.ArrayMap;
import android.util.Log;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -34,8 +42,10 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
private final ContentResolver mResolver;
private final Handler mHandler = new Handler();
private final SettingsObserver mObserver;
- private final List<ExitCondition> mExits = Arrays.asList(
- newExit("Until you turn this off", "Until", "You turn this off"));
+ private final List<ExitCondition> mExits = new ArrayList<ExitCondition>(Arrays.asList(
+ newExit("Until you turn this off", "Until", "You turn this off", null)));
+ private final INotificationManager mNoMan;
+ private final ArrayMap<Uri, Condition> mConditions = new ArrayMap<Uri, Condition>();
private Callbacks mCallbacks;
private int mExitIndex;
@@ -45,6 +55,13 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
mContext = context;
mResolver = mContext.getContentResolver();
mObserver = new SettingsObserver(mHandler);
+ mNoMan = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
+ try {
+ mNoMan.requestZenModeConditions(mListener, true /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
mObserver.init();
init();
}
@@ -77,6 +94,15 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
}
}
+ @Override
+ public void dispose() {
+ try {
+ mNoMan.requestZenModeConditions(mListener, false /*requested*/);
+ } catch (RemoteException e) {
+ // noop
+ }
+ }
+
private void dispatchChanged() {
mHandler.removeCallbacks(mChanged);
mHandler.post(mChanged);
@@ -117,13 +143,20 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
}
mExitIndex = i;
dispatchChanged();
+ final Uri conditionUri = (Uri) ec.tag;
+ try {
+ mNoMan.setZenModeCondition(conditionUri);
+ } catch (RemoteException e) {
+ // noop
+ }
}
- private static ExitCondition newExit(String summary, String line1, String line2) {
+ private static ExitCondition newExit(String summary, String line1, String line2, Object tag) {
final ExitCondition rt = new ExitCondition();
rt.summary = summary;
rt.line1 = line1;
rt.line2 = line2;
+ rt.tag = tag;
return rt;
}
@@ -168,4 +201,21 @@ public abstract class ZenModeViewAdapter implements ZenModeView.Adapter {
return v != Settings.Global.ZEN_MODE_OFF;
}
}
+
+ private final IConditionListener mListener = new IConditionListener.Stub() {
+ @Override
+ public void onConditionsReceived(Condition[] conditions) {
+ if (conditions == null || conditions.length == 0) return;
+ for (Condition c : conditions) {
+ mConditions.put(c.id, c);
+ }
+ for (int i = mExits.size() - 1; i > 0; i--) {
+ mExits.remove(i);
+ }
+ for (Condition c : mConditions.values()) {
+ mExits.add(newExit(c.caption, "", "", c.id));
+ }
+ dispatchChanged();
+ }
+ };
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index a282270..2c5d69c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -17,21 +17,40 @@
package com.android.server.notification;
import android.content.Context;
+import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.RemoteException;
import android.provider.Settings;
-import android.service.notification.IConditionProvider;
+import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionListener;
+import android.service.notification.IConditionProvider;
+import android.util.ArrayMap;
import android.util.Slog;
import com.android.internal.R;
+import libcore.util.Objects;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+
public class ConditionProviders extends ManagedServices {
+ private final ZenModeHelper mZenModeHelper;
+ private final ArrayMap<IBinder, IConditionListener> mListeners
+ = new ArrayMap<IBinder, IConditionListener>();
+ private final ArrayMap<Uri, ManagedServiceInfo> mConditions
+ = new ArrayMap<Uri, ManagedServiceInfo>();
+
+ private Uri mCurrentConditionId;
+
public ConditionProviders(Context context, Handler handler,
- Object mutex, UserProfiles userProfiles) {
- super(context, handler, mutex, userProfiles);
+ UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
+ super(context, handler, new Object(), userProfiles);
+ mZenModeHelper = zenModeHelper;
}
@Override
@@ -47,6 +66,28 @@ public class ConditionProviders extends ManagedServices {
}
@Override
+ public void dump(PrintWriter pw) {
+ super.dump(pw);
+ synchronized(mMutex) {
+ pw.print(" mCurrentConditionId="); pw.println(mCurrentConditionId);
+ pw.print(" mListeners("); pw.print(mListeners.size()); pw.println("):");
+ for (int i = 0; i < mListeners.size(); i++) {
+ pw.print(" "); pw.println(mListeners.keyAt(i));
+ }
+ pw.print(" mConditions("); pw.print(mConditions.size()); pw.println("):");
+ for (int i = 0; i < mConditions.size(); i++) {
+ pw.print(" "); pw.print(mConditions.keyAt(i));
+ final ManagedServiceInfo info = mConditions.valueAt(i);
+ pw.print(" -> "); pw.print(info.component);
+ if (!mServices.contains(info)) {
+ pw.print(" (orphan)");
+ }
+ pw.println();
+ }
+ }
+ }
+
+ @Override
protected IInterface asInterface(IBinder binder) {
return IConditionProvider.Stub.asInterface(binder);
}
@@ -54,5 +95,144 @@ public class ConditionProviders extends ManagedServices {
@Override
protected void onServiceAdded(IInterface service) {
Slog.d(TAG, "onServiceAdded " + service);
+ final IConditionProvider provider = (IConditionProvider) service;
+ try {
+ provider.onConnected();
+ } catch (RemoteException e) {
+ // we tried
+ }
+ }
+
+ @Override
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+ if (removed == null) return;
+ for (int i = mConditions.size() - 1; i >= 0; i--) {
+ if (removed.equals(mConditions.valueAt(i))) {
+ mConditions.removeAt(i);
+ }
+ }
+ }
+
+ public ManagedServiceInfo checkServiceToken(IConditionProvider provider) {
+ synchronized(mMutex) {
+ return checkServiceTokenLocked(provider);
+ }
+ }
+
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
+ + " requested=" + requested);
+ if (callback == null) return;
+ if (requested) {
+ mListeners.put(callback.asBinder(), callback);
+ requestConditionsLocked(Condition.FLAG_RELEVANT_NOW);
+ } else {
+ mListeners.remove(callback.asBinder());
+ if (mListeners.isEmpty()) {
+ requestConditionsLocked(0);
+ }
+ }
+ }
+ }
+
+ public void notifyConditions(String pkg, ManagedServiceInfo info, Condition[] conditions) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
+ + (conditions == null ? null : Arrays.asList(conditions)));
+ if (conditions == null || conditions.length == 0) return;
+ final int N = conditions.length;
+ boolean valid = true;
+ for (int i = 0; i < N; i++) {
+ final Uri id = conditions[i].id;
+ if (!Condition.isValidId(id, pkg)) {
+ Slog.w(TAG, "Ignoring conditions from " + pkg + " for invalid id: " + id);
+ valid = false;
+ }
+ }
+ if (!valid) return;
+
+ for (int i = 0; i < N; i++) {
+ mConditions.put(conditions[i].id, info);
+ }
+ for (IConditionListener listener : mListeners.values()) {
+ try {
+ listener.onConditionsReceived(conditions);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error sending conditions to listener " + listener, e);
+ }
+ }
+ if (mCurrentConditionId != null) {
+ for (int i = 0; i < N; i++) {
+ final Condition c = conditions[i];
+ if (!c.id.equals(mCurrentConditionId)) continue;
+ if (c.state == Condition.STATE_TRUE || c.state == Condition.STATE_ERROR) {
+ triggerExitLocked(c.state == Condition.STATE_ERROR);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private void triggerExitLocked(boolean error) {
+ if (error) {
+ Slog.w(TAG, "Zen mode exit condition failed");
+ } else if (DEBUG) {
+ Slog.d(TAG, "Zen mode exit condition triggered");
+ }
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ unsubscribeLocked(mCurrentConditionId);
+ mCurrentConditionId = null;
+ }
+
+ public void setZenModeCondition(Uri conditionId) {
+ synchronized(mMutex) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ if (Objects.equal(mCurrentConditionId, conditionId)) return;
+
+ if (mCurrentConditionId != null) {
+ unsubscribeLocked(mCurrentConditionId);
+ }
+ if (conditionId != null) {
+ final ManagedServiceInfo info = mConditions.get(conditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onSubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error subscribing to " + conditionId
+ + " from " + info.component, e);
+ }
+ }
+ mCurrentConditionId = conditionId;
+ }
+ }
+
+ private void unsubscribeLocked(Uri conditionId) {
+ final ManagedServiceInfo info = mConditions.get(mCurrentConditionId);
+ final IConditionProvider provider = provider(info);
+ if (provider == null) return;
+ try {
+ provider.onUnsubscribe(conditionId);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error unsubscribing to " + conditionId + " from " + info.component, e);
+ }
+ }
+
+ private static IConditionProvider provider(ManagedServiceInfo info) {
+ return info == null ? null : (IConditionProvider) info.service;
+ }
+
+ private void requestConditionsLocked(int flags) {
+ for (ManagedServiceInfo info : mServices) {
+ final IConditionProvider provider = provider(info);
+ if (provider == null) continue;
+ try {
+ provider.onRequestConditions(flags);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Error requesting conditions from " + info.component, e);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 81b28e8..0621f58 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -46,6 +46,7 @@ import android.util.SparseArray;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -66,7 +67,7 @@ abstract public class ManagedServices {
private static final String ENABLED_SERVICES_SEPARATOR = ":";
private final Context mContext;
- private final Object mMutex;
+ protected final Object mMutex;
private final UserProfiles mUserProfiles;
private final SettingsObserver mSettingsObserver;
private final Config mConfig;
@@ -102,6 +103,8 @@ abstract public class ManagedServices {
abstract protected void onServiceAdded(IInterface service);
+ protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
+
private ManagedServiceInfo newServiceInfo(IInterface service,
ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
int targetSdkVersion) {
@@ -114,21 +117,24 @@ abstract public class ManagedServices {
}
public void dump(PrintWriter pw) {
- pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
+ pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
+ ") enabled for current profiles:");
for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
- pw.println(" " + cmpt);
+ pw.println(" " + cmpt);
}
- pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
+ pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
for (ManagedServiceInfo info : mServices) {
- pw.println(" " + info.component
+ pw.println(" " + info.component
+ " (user " + info.userid + "): " + info.service
+ (info.isSystem?" SYSTEM":""));
}
}
public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
+ if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
+ + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
+ + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
boolean anyServicesInvolved = false;
if (pkgList != null && (pkgList.length > 0)) {
for (String pkgName : pkgList) {
@@ -195,7 +201,7 @@ abstract public class ManagedServices {
new Intent(mConfig.serviceInterface),
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
userId);
-
+ if (DEBUG) Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Set<ComponentName> installed = new ArraySet<ComponentName>();
for (int i = 0, count = installedServices.size(); i < count; i++) {
ResolveInfo resolveInfo = installedServices.get(i);
@@ -327,7 +333,7 @@ abstract public class ManagedServices {
// cut old connections
if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
+ info.service);
- mServices.remove(i);
+ removeServiceLocked(i);
if (info.connection != null) {
mContext.unbindService(info.connection);
}
@@ -408,7 +414,7 @@ abstract public class ManagedServices {
final ManagedServiceInfo info = mServices.get(i);
if (name.equals(info.component)
&& info.userid == userid) {
- mServices.remove(i);
+ removeServiceLocked(i);
if (info.connection != null) {
try {
mContext.unbindService(info.connection);
@@ -429,6 +435,7 @@ abstract public class ManagedServices {
* @return the removed service.
*/
private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
+ if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
ManagedServiceInfo serviceInfo = null;
synchronized (mMutex) {
final int N = mServices.size();
@@ -436,13 +443,20 @@ abstract public class ManagedServices {
final ManagedServiceInfo info = mServices.get(i);
if (info.service.asBinder() == service.asBinder()
&& info.userid == userid) {
- serviceInfo = mServices.remove(i);
+ if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
+ serviceInfo = removeServiceLocked(i);
}
}
}
return serviceInfo;
}
+ private ManagedServiceInfo removeServiceLocked(int i) {
+ final ManagedServiceInfo info = mServices.remove(i);
+ onServiceRemovedLocked(info);
+ return info;
+ }
+
private void checkNotNull(IInterface service) {
if (service == null) {
throw new IllegalArgumentException(getCaption() + " must not be null");
@@ -517,6 +531,18 @@ abstract public class ManagedServices {
this.targetSdkVersion = targetSdkVersion;
}
+ @Override
+ public String toString() {
+ return new StringBuilder("ManagedServiceInfo[")
+ .append("component=").append(component)
+ .append(",userid=").append(userid)
+ .append(",isSystem=").append(isSystem)
+ .append(",targetSdkVersion=").append(targetSdkVersion)
+ .append(",connection=").append(connection == null ? null : "<connection>")
+ .append(",service=").append(service)
+ .append(']').toString();
+ }
+
public boolean enabledAndUserMatches(int nid) {
if (!isEnabledForCurrentProfiles()) {
return false;
@@ -532,6 +558,7 @@ abstract public class ManagedServices {
@Override
public void binderDied() {
+ if (DEBUG) Slog.d(TAG, "binderDied");
// Remove the service, but don't unbind from the service. The system will bring the
// service back up, and the onServiceConnected handler will readd the service with the
// new binding. If this isn't a bound service, and is just a registered
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 5a1f9b2..96e3a9f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,6 +58,7 @@ import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.Settings;
import android.service.notification.INotificationListener;
+import android.service.notification.IConditionListener;
import android.service.notification.IConditionProvider;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
@@ -706,7 +707,7 @@ public class NotificationManagerService extends SystemService {
String pkgList[] = null;
boolean queryReplace = queryRemove &&
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
- if (DBG) Slog.i(TAG, "queryReplace=" + queryReplace);
+ if (DBG) Slog.i(TAG, "action=" + action + " queryReplace=" + queryReplace);
if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
} else if (queryRestart) {
@@ -852,7 +853,7 @@ public class NotificationManagerService extends SystemService {
mListeners = new NotificationListeners();
mConditionProviders = new ConditionProviders(getContext(),
- mHandler, mNotificationList, mUserProfiles);
+ mHandler, mUserProfiles, mZenModeHelper);
mStatusBar = getLocalService(StatusBarManagerInternal.class);
mStatusBar.setNotificationDelegate(mNotificationDelegate);
@@ -1341,9 +1342,34 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void notifyCondition(IConditionProvider provider, Condition condition) {
- // TODO check token
- mZenModeHelper.notifyCondition(condition);
+ public void notifyConditions(String pkg, IConditionProvider provider,
+ Condition[] conditions) {
+ final ManagedServiceInfo info = mConditionProviders.checkServiceToken(provider);
+ checkCallerIsSystemOrSameApp(pkg);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mConditionProviders.notifyConditions(pkg, info, conditions);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void requestZenModeConditions(IConditionListener callback, boolean requested) {
+ enforceSystemOrSystemUI("INotificationManager.requestZenModeConditions");
+ mConditionProviders.requestZenModeConditions(callback, requested);
+ }
+
+ @Override
+ public void setZenModeCondition(Uri conditionId) {
+ enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
+ mConditionProviders.setZenModeCondition(conditionId);
+ }
+
+ private void enforceSystemOrSystemUI(String message) {
+ if (isCallerSystem()) return;
+ getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
+ message);
}
@Override
@@ -1378,9 +1404,6 @@ public class NotificationManagerService extends SystemService {
void dumpImpl(PrintWriter pw) {
pw.println("Current Notification Manager state:");
- mListeners.dump(pw);
- mConditionProviders.dump(pw);
-
int N;
synchronized (mToastQueue) {
@@ -1434,6 +1457,12 @@ public class NotificationManagerService extends SystemService {
pw.println("\n Zen Mode:");
mZenModeHelper.dump(pw, " ");
+
+ pw.println("\n Notification listeners:");
+ mListeners.dump(pw);
+
+ pw.println("\n Condition providers:");
+ mConditionProviders.dump(pw);
}
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index b00beb6..b06e0cb 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -33,7 +33,6 @@ import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
import android.provider.Settings.Global;
-import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.util.Slog;
@@ -133,6 +132,10 @@ public class ZenModeHelper {
return false;
}
+ public void setZenMode(int zenModeValue) {
+ Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
+ }
+
public void updateZenMode() {
final int mode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF);
@@ -202,10 +205,6 @@ public class ZenModeHelper {
return true;
}
- public void notifyCondition(Condition condition) {
- Slog.d(TAG, "notifyCondition " + condition);
- }
-
private boolean isCall(String pkg, Notification n) {
return CALL_PACKAGES.contains(pkg);
}
@@ -305,7 +304,7 @@ public class ZenModeHelper {
if (skip) {
Slog.d(TAG, "Skipping zen mode update for the weekend");
} else {
- Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
+ ZenModeHelper.this.setZenMode(zenModeValue);
}
updateAlarms();
}