FileDocCategorySizeDatePackage
ConditionProviders.javaAPI DocAndroid 5.1 API25901Thu Mar 12 22:22:42 GMT 2015com.android.server.notification

ConditionProviders

public class ConditionProviders extends ManagedServices
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.

Fields Summary
private static final android.service.notification.Condition[]
NO_CONDITIONS
private final ZenModeHelper
mZenModeHelper
private final android.util.ArrayMap
mListeners
private final ArrayList
mRecords
private final android.util.ArraySet
mSystemConditionProviders
private final CountdownConditionProvider
mCountdown
private final DowntimeConditionProvider
mDowntime
private final NextAlarmConditionProvider
mNextAlarm
private final NextAlarmTracker
mNextAlarmTracker
private android.service.notification.Condition
mExitCondition
private android.content.ComponentName
mExitConditionComponent
Constructors Summary
public ConditionProviders(android.content.Context context, android.os.Handler handler, UserProfiles userProfiles, ZenModeHelper zenModeHelper)


        
                
        super(context, handler, new Object(), userProfiles);
        mZenModeHelper = zenModeHelper;
        mZenModeHelper.addCallback(new ZenModeHelperCallback());
        mSystemConditionProviders = safeSet(PropConfig.getStringArray(mContext,
                "system.condition.providers",
                R.array.config_system_condition_providers));
        final boolean countdown = mSystemConditionProviders.contains(ZenModeConfig.COUNTDOWN_PATH);
        final boolean downtime = mSystemConditionProviders.contains(ZenModeConfig.DOWNTIME_PATH);
        final boolean nextAlarm = mSystemConditionProviders.contains(ZenModeConfig.NEXT_ALARM_PATH);
        mNextAlarmTracker = (downtime || nextAlarm) ? new NextAlarmTracker(mContext) : null;
        mCountdown = countdown ? new CountdownConditionProvider() : null;
        mDowntime = downtime ? new DowntimeConditionProvider(this, mNextAlarmTracker,
                mZenModeHelper) : null;
        mNextAlarm = nextAlarm ? new NextAlarmConditionProvider(mNextAlarmTracker) : null;
        loadZenConfig();
    
Methods Summary
protected android.os.IInterfaceasInterface(android.os.IBinder binder)

        return IConditionProvider.Stub.asInterface(binder);
    
public ManagedServiceInfocheckServiceToken(android.service.notification.IConditionProvider provider)

        synchronized(mMutex) {
            return checkServiceTokenLocked(provider);
        }
    
public voiddump(java.io.PrintWriter pw, com.android.server.notification.NotificationManagerService.DumpFilter filter)

        super.dump(pw, filter);
        synchronized(mMutex) {
            if (filter == null) {
                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("    mRecords("); pw.print(mRecords.size()); pw.println("):");
            for (int i = 0; i < mRecords.size(); i++) {
                final ConditionRecord r = mRecords.get(i);
                if (filter != null && !filter.matches(r.component)) continue;
                pw.print("      "); pw.println(r);
                final String countdownDesc =  CountdownConditionProvider.tryParseDescription(r.id);
                if (countdownDesc != null) {
                    pw.print("        ("); pw.print(countdownDesc); pw.println(")");
                }
            }
        }
        pw.print("    mSystemConditionProviders: "); pw.println(mSystemConditionProviders);
        if (mCountdown != null) {
            mCountdown.dump(pw, filter);
        }
        if (mDowntime != null) {
            mDowntime.dump(pw, filter);
        }
        if (mNextAlarm != null) {
            mNextAlarm.dump(pw, filter);
        }
        if (mNextAlarmTracker != null) {
            mNextAlarmTracker.dump(pw, filter);
        }
    
private voidensureRecordExists(android.service.notification.Condition condition, android.service.notification.IConditionProvider provider, android.content.ComponentName component)

        // constructed by convention, make sure the record exists...
        final ConditionRecord r = getRecordLocked(condition.id, component);
        if (r.info == null) {
            // ... and is associated with the in-process service
            r.info = checkServiceTokenLocked(provider);
        }
    
public android.service.notification.Condition[]getAutomaticZenModeConditions()

        synchronized(mMutex) {
            final int N = mRecords.size();
            ArrayList<Condition> rt = null;
            for (int i = 0; i < N; i++) {
                final ConditionRecord r = mRecords.get(i);
                if (r.isAutomatic && r.condition != null) {
                    if (rt == null) rt = new ArrayList<Condition>();
                    rt.add(r.condition);
                }
            }
            return rt == null ? NO_CONDITIONS : rt.toArray(new Condition[rt.size()]);
        }
    
protected ConfiggetConfig()

        Config c = new Config();
        c.caption = "condition provider";
        c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
        c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
        c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
        c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
        c.clientLabel = R.string.condition_provider_service_binding_label;
        return c;
    
private com.android.server.notification.ConditionProviders$ConditionRecordgetRecordLocked(android.net.Uri id, android.content.ComponentName component)

        final int N = mRecords.size();
        for (int i = 0; i < N; i++) {
            final ConditionRecord r = mRecords.get(i);
            if (r.id.equals(id) && r.component.equals(component)) {
                return r;
            }
        }
        final ConditionRecord r = new ConditionRecord(id, component);
        mRecords.add(r);
        return r;
    
public booleanisSystemConditionProviderEnabled(java.lang.String path)

        return mSystemConditionProviders.contains(path);
    
private voidloadZenConfig()

        final ZenModeConfig config = mZenModeHelper.getConfig();
        if (config == null) {
            if (DEBUG) Slog.d(TAG, "loadZenConfig: no config");
            return;
        }
        synchronized (mMutex) {
            final boolean changingExit = !Objects.equals(mExitCondition, config.exitCondition);
            mExitCondition = config.exitCondition;
            mExitConditionComponent = config.exitConditionComponent;
            if (changingExit) {
                ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
            }
            if (mDowntime != null) {
                mDowntime.setConfig(config);
            }
            if (config.conditionComponents == null || config.conditionIds == null
                    || config.conditionComponents.length != config.conditionIds.length) {
                if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
                setAutomaticZenModeConditions(null, false /*save*/);
                return;
            }
            final ArraySet<Uri> newIds = new ArraySet<Uri>();
            final int N = config.conditionComponents.length;
            for (int i = 0; i < N; i++) {
                final ComponentName component = config.conditionComponents[i];
                final Uri id = config.conditionIds[i];
                if (component != null && id != null) {
                    getRecordLocked(id, component);  // ensure record exists
                    newIds.add(id);
                }
            }
            if (DEBUG) Slog.d(TAG, "loadZenConfig: N=" + N);
            setAutomaticZenModeConditions(newIds.toArray(new Uri[newIds.size()]), false /*save*/);
        }
    
public voidnotifyConditions(java.lang.String pkg, ManagedServiceInfo info, android.service.notification.Condition[] conditions)

        synchronized(mMutex) {
            if (DEBUG) Slog.d(TAG, "notifyConditions pkg=" + pkg + " info=" + info + " conditions="
                    + (conditions == null ? null : Arrays.asList(conditions)));
            conditions = validateConditions(pkg, conditions);
            if (conditions == null || conditions.length == 0) return;
            final int N = conditions.length;
            for (IConditionListener listener : mListeners.values()) {
                try {
                    listener.onConditionsReceived(conditions);
                } catch (RemoteException e) {
                    Slog.w(TAG, "Error sending conditions to listener " + listener, e);
                }
            }
            for (int i = 0; i < N; i++) {
                final Condition c = conditions[i];
                final ConditionRecord r = getRecordLocked(c.id, info.component);
                final Condition oldCondition = r.condition;
                final boolean conditionUpdate = oldCondition != null && !oldCondition.equals(c);
                r.info = info;
                r.condition = c;
                // if manual, exit zen if false (or failed), update if true (and changed)
                if (r.isManual) {
                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
                        final boolean failed = c.state == Condition.STATE_ERROR;
                        if (failed) {
                            Slog.w(TAG, "Exit zen: manual condition failed: " + c);
                        } else if (DEBUG) {
                            Slog.d(TAG, "Exit zen: manual condition false: " + c);
                        }
                        onManualConditionClearing();
                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
                                "manualConditionExit");
                        unsubscribeLocked(r);
                        r.isManual = false;
                    } else if (c.state == Condition.STATE_TRUE && conditionUpdate) {
                        if (DEBUG) Slog.d(TAG, "Current condition updated, still true. old="
                                + oldCondition + " new=" + c);
                        setZenModeCondition(c, "conditionUpdate");
                    }
                }
                // if automatic, exit zen if false (or failed), enter zen if true
                if (r.isAutomatic) {
                    if (c.state == Condition.STATE_FALSE || c.state == Condition.STATE_ERROR) {
                        final boolean failed = c.state == Condition.STATE_ERROR;
                        if (failed) {
                            Slog.w(TAG, "Exit zen: automatic condition failed: " + c);
                        } else if (DEBUG) {
                            Slog.d(TAG, "Exit zen: automatic condition false: " + c);
                        }
                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
                                "automaticConditionExit");
                    } else if (c.state == Condition.STATE_TRUE) {
                        Slog.d(TAG, "Enter zen: automatic condition true: " + c);
                        mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
                                "automaticConditionEnter");
                    }
                }
            }
        }
    
public voidonBootPhaseAppsCanStart()

        super.onBootPhaseAppsCanStart();
        if (mNextAlarmTracker != null) {
            mNextAlarmTracker.init();
        }
        if (mCountdown != null) {
            mCountdown.attachBase(mContext);
            registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
                    UserHandle.USER_OWNER);
        }
        if (mDowntime != null) {
            mDowntime.attachBase(mContext);
            registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
                    UserHandle.USER_OWNER);
        }
        if (mNextAlarm != null) {
            mNextAlarm.attachBase(mContext);
            registerService(mNextAlarm.asInterface(), NextAlarmConditionProvider.COMPONENT,
                    UserHandle.USER_OWNER);
        }
    
private voidonManualConditionClearing()

        if (mDowntime != null) {
            mDowntime.onManualConditionClearing();
        }
    
protected voidonServiceAdded(ManagedServiceInfo info)

        final IConditionProvider provider = provider(info);
        try {
            provider.onConnected();
        } catch (RemoteException e) {
            // we tried
        }
        synchronized (mMutex) {
            if (info.component.equals(mExitConditionComponent)) {
                // ensure record exists, we'll wire it up and subscribe below
                final ConditionRecord manualRecord =
                        getRecordLocked(mExitCondition.id, mExitConditionComponent);
                manualRecord.isManual = true;
            }
            final int N = mRecords.size();
            for(int i = 0; i < N; i++) {
                final ConditionRecord r = mRecords.get(i);
                if (!r.component.equals(info.component)) continue;
                r.info = info;
                // if automatic or manual, auto-subscribe
                if (r.isAutomatic || r.isManual) {
                    subscribeLocked(r);
                }
            }
        }
    
protected voidonServiceRemovedLocked(ManagedServiceInfo removed)

        if (removed == null) return;
        for (int i = mRecords.size() - 1; i >= 0; i--) {
            final ConditionRecord r = mRecords.get(i);
            if (!r.component.equals(removed.component)) continue;
            if (r.isManual) {
                // removing the current manual condition, exit zen
                onManualConditionClearing();
                mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
            }
            if (r.isAutomatic) {
                // removing an automatic condition, exit zen
                mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "automaticServiceRemoved");
            }
            mRecords.remove(i);
        }
    
public voidonUserSwitched()

        super.onUserSwitched();
        if (mNextAlarmTracker != null) {
            mNextAlarmTracker.onUserSwitched();
        }
    
private static android.service.notification.IConditionProviderprovider(com.android.server.notification.ConditionProviders$ConditionRecord r)

        return r == null ? null : provider(r.info);
    
private static android.service.notification.IConditionProviderprovider(ManagedServiceInfo info)

        return info == null ? null : (IConditionProvider) info.service;
    
private voidrequestConditionsLocked(int flags)

        for (ManagedServiceInfo info : mServices) {
            final IConditionProvider provider = provider(info);
            if (provider == null) continue;
            // clear all stored conditions from this provider that we no longer care about
            for (int i = mRecords.size() - 1; i >= 0; i--) {
                final ConditionRecord r = mRecords.get(i);
                if (r.info != info) continue;
                if (r.isManual || r.isAutomatic) continue;
                mRecords.remove(i);
            }
            try {
                provider.onRequestConditions(flags);
            } catch (RemoteException e) {
                Slog.w(TAG, "Error requesting conditions from " + info.component, e);
            }
        }
    
public voidrequestZenModeConditions(android.service.notification.IConditionListener callback, int relevance)

        synchronized(mMutex) {
            if (DEBUG) Slog.d(TAG, "requestZenModeConditions callback=" + callback
                    + " relevance=" + Condition.relevanceToString(relevance));
            if (callback == null) return;
            relevance = relevance & (Condition.FLAG_RELEVANT_NOW | Condition.FLAG_RELEVANT_ALWAYS);
            if (relevance != 0) {
                mListeners.put(callback.asBinder(), callback);
                requestConditionsLocked(relevance);
            } else {
                mListeners.remove(callback.asBinder());
                if (mListeners.isEmpty()) {
                    requestConditionsLocked(0);
                }
            }
        }
    
private static android.util.ArraySetsafeSet(T items)

        final ArraySet<T> rt = new ArraySet<T>();
        if (items == null || items.length == 0) return rt;
        final int N = items.length;
        for (int i = 0; i < N; i++) {
            final T item = items[i];
            if (item != null) {
                rt.add(item);
            }
        }
        return rt;
    
private voidsaveZenConfigLocked()

        ZenModeConfig config = mZenModeHelper.getConfig();
        if (config == null) return;
        config = config.copy();
        final ArrayList<ConditionRecord> automatic = new ArrayList<ConditionRecord>();
        final int automaticN = mRecords.size();
        for (int i = 0; i < automaticN; i++) {
            final ConditionRecord r = mRecords.get(i);
            if (r.isAutomatic) {
                automatic.add(r);
            }
        }
        if (automatic.isEmpty()) {
            config.conditionComponents = null;
            config.conditionIds = null;
        } else {
            final int N = automatic.size();
            config.conditionComponents = new ComponentName[N];
            config.conditionIds = new Uri[N];
            for (int i = 0; i < N; i++) {
                final ConditionRecord r = automatic.get(i);
                config.conditionComponents[i] = r.component;
                config.conditionIds[i] = r.id;
            }
        }
        config.exitCondition = mExitCondition;
        config.exitConditionComponent = mExitConditionComponent;
        if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
        mZenModeHelper.setConfig(config);
    
public voidsetAutomaticZenModeConditions(android.net.Uri[] conditionIds)

        setAutomaticZenModeConditions(conditionIds, true /*save*/);
    
private voidsetAutomaticZenModeConditions(android.net.Uri[] conditionIds, boolean save)

        if (DEBUG) Slog.d(TAG, "setAutomaticZenModeConditions "
                + (conditionIds == null ? null : Arrays.asList(conditionIds)));
        synchronized(mMutex) {
            final ArraySet<Uri> newIds = safeSet(conditionIds);
            final int N = mRecords.size();
            boolean changed = false;
            for (int i = 0; i < N; i++) {
                final ConditionRecord r = mRecords.get(i);
                final boolean automatic = newIds.contains(r.id);
                if (!r.isAutomatic && automatic) {
                    // subscribe to new automatic
                    subscribeLocked(r);
                    r.isAutomatic = true;
                    changed = true;
                } else if (r.isAutomatic && !automatic) {
                    // unsubscribe from old automatic
                    unsubscribeLocked(r);
                    r.isAutomatic = false;
                    changed = true;
                }
            }
            if (save && changed) {
                saveZenConfigLocked();
            }
        }
    
public voidsetZenModeCondition(android.service.notification.Condition condition, java.lang.String reason)

        if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition + " reason=" + reason);
        synchronized(mMutex) {
            ComponentName conditionComponent = null;
            if (condition != null) {
                if (mCountdown != null && ZenModeConfig.isValidCountdownConditionId(condition.id)) {
                    ensureRecordExists(condition, mCountdown.asInterface(),
                            CountdownConditionProvider.COMPONENT);
                }
                if (mDowntime != null && ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
                    ensureRecordExists(condition, mDowntime.asInterface(),
                            DowntimeConditionProvider.COMPONENT);
                }
            }
            final int N = mRecords.size();
            for (int i = 0; i < N; i++) {
                final ConditionRecord r = mRecords.get(i);
                final boolean idEqual = condition != null && r.id.equals(condition.id);
                if (r.isManual && !idEqual) {
                    // was previous manual condition, unsubscribe
                    unsubscribeLocked(r);
                    r.isManual = false;
                } else if (idEqual && !r.isManual) {
                    // is new manual condition, subscribe
                    subscribeLocked(r);
                    r.isManual = true;
                }
                if (idEqual) {
                    conditionComponent = r.component;
                }
            }
            if (!Objects.equals(mExitCondition, condition)) {
                mExitCondition = condition;
                mExitConditionComponent = conditionComponent;
                ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, reason);
                saveZenConfigLocked();
            }
        }
    
private voidsubscribeLocked(com.android.server.notification.ConditionProviders$ConditionRecord r)

        if (DEBUG) Slog.d(TAG, "subscribeLocked " + r);
        final IConditionProvider provider = provider(r);
        RemoteException re = null;
        if (provider != null) {
            try {
                Slog.d(TAG, "Subscribing to " + r.id + " with " + provider);
                provider.onSubscribe(r.id);
            } catch (RemoteException e) {
                Slog.w(TAG, "Error subscribing to " + r, e);
                re = e;
            }
        }
        ZenLog.traceSubscribe(r != null ? r.id : null, provider, re);
    
private voidunsubscribeLocked(com.android.server.notification.ConditionProviders$ConditionRecord r)

        if (DEBUG) Slog.d(TAG, "unsubscribeLocked " + r);
        final IConditionProvider provider = provider(r);
        RemoteException re = null;
        if (provider != null) {
            try {
                provider.onUnsubscribe(r.id);
            } catch (RemoteException e) {
                Slog.w(TAG, "Error unsubscribing to " + r, e);
                re = e;
            }
        }
        ZenLog.traceUnsubscribe(r != null ? r.id : null, provider, re);
    
private android.service.notification.Condition[]validateConditions(java.lang.String pkg, android.service.notification.Condition[] conditions)

        if (conditions == null || conditions.length == 0) return null;
        final int N = conditions.length;
        final ArrayMap<Uri, Condition> valid = new ArrayMap<Uri, Condition>(N);
        for (int i = 0; i < N; i++) {
            final Uri id = conditions[i].id;
            if (!Condition.isValidId(id, pkg)) {
                Slog.w(TAG, "Ignoring condition from " + pkg + " for invalid id: " + id);
                continue;
            }
            if (valid.containsKey(id)) {
                Slog.w(TAG, "Ignoring condition from " + pkg + " for duplicate id: " + id);
                continue;
            }
            valid.put(id, conditions[i]);
        }
        if (valid.size() == 0) return null;
        if (valid.size() == N) return conditions;
        final Condition[] rt = new Condition[valid.size()];
        for (int i = 0; i < rt.length; i++) {
            rt[i] = valid.valueAt(i);
        }
        return rt;