diff options
author | John Spurlock <jspurlock@google.com> | 2014-04-26 10:24:59 -0400 |
---|---|---|
committer | John Spurlock <jspurlock@google.com> | 2014-04-27 11:36:32 -0400 |
commit | e77bb36d48b6b8b5c3bb6a1195aca469bb237919 (patch) | |
tree | 29f877996112bebd253e25a18a2b731a086abfb3 | |
parent | 31dc634be3610b062fbcc4afa02607ce8f4125f5 (diff) | |
download | frameworks_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
12 files changed, 415 insertions, 68 deletions
@@ -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(); } |