Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93d837fd authored by John Spurlock's avatar John Spurlock Committed by Android (Google) Code Review
Browse files

Merge "Zen: handle exit conditions across reboots." into lmp-dev

parents 61e9bf24 50806fc4
Loading
Loading
Loading
Loading
+13 −3
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@ public class ZenModeConfig implements Parcelable {

    private static final String EXIT_CONDITION_TAG = "exitCondition";
    private static final String EXIT_CONDITION_ATT_ID = "id";
    private static final String EXIT_CONDITION_ATT_COMPONENT = "component";

    public boolean allowCalls;
    public boolean allowMessages;
@@ -89,6 +90,7 @@ public class ZenModeConfig implements Parcelable {
    public ComponentName[] conditionComponents;
    public Uri[] conditionIds;
    public Uri exitConditionId;
    public ComponentName exitConditionComponent;

    public ZenModeConfig() { }

@@ -114,6 +116,7 @@ public class ZenModeConfig implements Parcelable {
        }
        allowFrom = source.readInt();
        exitConditionId = source.readParcelable(null);
        exitConditionComponent = source.readParcelable(null);
    }

    @Override
@@ -144,6 +147,7 @@ public class ZenModeConfig implements Parcelable {
        }
        dest.writeInt(allowFrom);
        dest.writeParcelable(exitConditionId, 0);
        dest.writeParcelable(exitConditionComponent, 0);
    }

    @Override
@@ -160,6 +164,7 @@ public class ZenModeConfig implements Parcelable {
            .append(",conditionIds=")
            .append(conditionIds == null ? null : TextUtils.join(",", conditionIds))
            .append(",exitConditionId=").append(exitConditionId)
            .append(",exitConditionComponent=").append(exitConditionComponent)
            .append(']').toString();
    }

@@ -191,7 +196,8 @@ public class ZenModeConfig implements Parcelable {
                && other.sleepEndMinute == sleepEndMinute
                && Objects.deepEquals(other.conditionComponents, conditionComponents)
                && Objects.deepEquals(other.conditionIds, conditionIds)
                && Objects.equals(other.exitConditionId, exitConditionId);
                && Objects.equals(other.exitConditionId, exitConditionId)
                && Objects.equals(other.exitConditionComponent, exitConditionComponent);
    }

    @Override
@@ -199,7 +205,7 @@ public class ZenModeConfig implements Parcelable {
        return Objects.hash(allowCalls, allowMessages, allowFrom, sleepMode,
                sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
                Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
                exitConditionId);
                exitConditionId, exitConditionComponent);
    }

    public boolean isValid() {
@@ -289,6 +295,8 @@ public class ZenModeConfig implements Parcelable {
                    }
                } else if (EXIT_CONDITION_TAG.equals(tag)) {
                    rt.exitConditionId = safeUri(parser, EXIT_CONDITION_ATT_ID);
                    rt.exitConditionComponent =
                            safeComponentName(parser, EXIT_CONDITION_ATT_COMPONENT);
                }
            }
        }
@@ -325,9 +333,11 @@ public class ZenModeConfig implements Parcelable {
                out.endTag(null, CONDITION_TAG);
            }
        }
        if (exitConditionId != null) {
        if (exitConditionId != null && exitConditionComponent != null) {
            out.startTag(null, EXIT_CONDITION_TAG);
            out.attribute(null, EXIT_CONDITION_ATT_ID, exitConditionId.toString());
            out.attribute(null, EXIT_CONDITION_ATT_COMPONENT,
                    exitConditionComponent.flattenToString());
            out.endTag(null, EXIT_CONDITION_TAG);
        }
        out.endTag(null, ZEN_TAG);
+11 −6
Original line number Diff line number Diff line
@@ -32,7 +32,6 @@ import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AnimationUtils;
@@ -54,8 +53,11 @@ public class ZenModePanel extends LinearLayout {
    private static final String TAG = "ZenModePanel";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    private static final int SECONDS_MS = 1000;
    private static final int MINUTES_MS = 60 * SECONDS_MS;

    private static final int[] MINUTE_BUCKETS = DEBUG
            ? new int[] { 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 }
            ? new int[] { 0, 1, 2, 5, 15, 30, 45, 60, 120, 180, 240, 480 }
            : new int[] { 15, 30, 45, 60, 120, 180, 240, 480 };
    private static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
    private static final int MAX_BUCKET_MINUTES = MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
@@ -64,9 +66,7 @@ public class ZenModePanel extends LinearLayout {
    private static final int TIME_CONDITION_INDEX = 1;
    private static final int FIRST_CONDITION_INDEX = 2;
    private static final float SILENT_HINT_PULSE_SCALE = 1.1f;

    private static final int SECONDS_MS = 1000;
    private static final int MINUTES_MS = 60 * SECONDS_MS;
    private static final int ZERO_VALUE_MS = 20 * SECONDS_MS;

    public static final Intent ZEN_SETTINGS = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);

@@ -152,6 +152,7 @@ public class ZenModePanel extends LinearLayout {
        if (DEBUG) Log.d(mTag, "onAttachedToWindow");
        mAttachedZen = getSelectedZen(-1);
        refreshExitConditionText();
        updateWidgets();
    }

    @Override
@@ -292,7 +293,8 @@ public class ZenModePanel extends LinearLayout {

    private Condition newTimeCondition(int minutesFromNow) {
        final long now = System.currentTimeMillis();
        return timeCondition(now + minutesFromNow * MINUTES_MS, minutesFromNow);
        final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS;
        return timeCondition(now + millis, minutesFromNow);
    }

    private Condition timeCondition(long time, int minutes) {
@@ -369,6 +371,9 @@ public class ZenModePanel extends LinearLayout {
        }
        tag.conditionId = condition != null ? condition.id : null;
        tag.rb.setEnabled(enabled);
        if (Objects.equals(tag.conditionId, mExitConditionId)) {
            tag.rb.setChecked(true);
        }
        tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+25 −9
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ public class ConditionProviders extends ManagedServices {
    private final CountdownConditionProvider mCountdown = new CountdownConditionProvider();

    private Uri mExitConditionId;
    private ComponentName mExitConditionComponent;

    public ConditionProviders(Context context, Handler handler,
            UserProfiles userProfiles, ZenModeHelper zenModeHelper) {
@@ -95,6 +96,7 @@ public class ConditionProviders extends ManagedServices {
                }
            }
        }
        mCountdown.dump(pw, filter);
    }

    @Override
@@ -120,20 +122,20 @@ public class ConditionProviders extends ManagedServices {
            // we tried
        }
        synchronized (mMutex) {
            if (info.component.equals(mExitConditionComponent)) {
                // ensure record exists, we'll wire it up and subscribe below
                final ConditionRecord manualRecord =
                        getRecordLocked(mExitConditionId, 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, auto-subscribe
                if (r.isAutomatic) {
                    try {
                        final Uri id = r.id;
                        if (DEBUG) Slog.d(TAG, "Auto-subscribing to configured condition " + id);
                        provider.onSubscribe(id);
                    } catch (RemoteException e) {
                        // we tried
                    }
                // if automatic or manual, auto-subscribe
                if (r.isAutomatic || r.isManual) {
                    subscribeLocked(r);
                }
            }
        }
@@ -274,6 +276,7 @@ public class ConditionProviders extends ManagedServices {
    public void setZenModeCondition(Uri conditionId) {
        if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
        synchronized(mMutex) {
            ComponentName conditionComponent = null;
            if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
                // constructed by the client, make sure the record exists...
                final ConditionRecord r = getRecordLocked(conditionId,
@@ -296,9 +299,13 @@ public class ConditionProviders extends ManagedServices {
                    subscribeLocked(r);
                    r.isManual = true;
                }
                if (idEqual) {
                    conditionComponent = r.component;
                }
            }
            if (!Objects.equals(mExitConditionId, conditionId)) {
                mExitConditionId = conditionId;
                mExitConditionComponent = conditionComponent;
                saveZenConfigLocked();
            }
        }
@@ -404,6 +411,13 @@ public class ConditionProviders extends ManagedServices {
        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) {
@@ -420,6 +434,7 @@ public class ConditionProviders extends ManagedServices {
        }
        synchronized (mMutex) {
            mExitConditionId = config.exitConditionId;
            mExitConditionComponent = config.exitConditionComponent;
            if (config.conditionComponents == null || config.conditionIds == null
                    || config.conditionComponents.length != config.conditionIds.length) {
                if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
@@ -467,6 +482,7 @@ public class ConditionProviders extends ManagedServices {
            }
        }
        config.exitConditionId = mExitConditionId;
        config.exitConditionComponent = mExitConditionComponent;
        if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
        mZenModeHelper.setConfig(config);
    }
+23 −6
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@ import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
import android.util.Slog;

import com.android.server.notification.NotificationManagerService.DumpFilter;

import java.io.PrintWriter;
import java.util.Date;

/** Built-in zen condition provider for simple time-based conditions */
@@ -49,11 +52,18 @@ public class CountdownConditionProvider extends ConditionProviderService {
    private final Receiver mReceiver = new Receiver();

    private boolean mConnected;
    private long mTime;

    public CountdownConditionProvider() {
        if (DEBUG) Slog.d(TAG, "new CountdownConditionProvider()");
    }

    public void dump(PrintWriter pw, DumpFilter filter) {
        pw.println("    CountdownConditionProvider:");
        pw.print("      mConnected="); pw.println(mConnected);
        pw.print("      mTime="); pw.println(mTime);
    }

    @Override
    public void onConnected() {
        if (DEBUG) Slog.d(TAG, "onConnected");
@@ -79,7 +89,7 @@ public class CountdownConditionProvider extends ConditionProviderService {
    @Override
    public void onSubscribe(Uri conditionId) {
        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
        final long time = ZenModeConfig.tryParseCountdownConditionId(conditionId);
        mTime = ZenModeConfig.tryParseCountdownConditionId(conditionId);
        final AlarmManager alarms = (AlarmManager)
                mContext.getSystemService(Context.ALARM_SERVICE);
        final Intent intent = new Intent(ACTION).putExtra(EXTRA_CONDITION_ID, conditionId)
@@ -87,14 +97,21 @@ public class CountdownConditionProvider extends ConditionProviderService {
        final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, REQUEST_CODE,
                intent, PendingIntent.FLAG_UPDATE_CURRENT);
        alarms.cancel(pendingIntent);
        if (time > 0) {
        if (mTime > 0) {
            final long now = System.currentTimeMillis();
            final CharSequence span =
                    DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
                    DateUtils.getRelativeTimeSpanString(mTime, now, DateUtils.MINUTE_IN_MILLIS);
            if (mTime <= now) {
                // in the past, already false
                notifyCondition(newCondition(mTime, Condition.STATE_FALSE));
            } else {
                // in the future, set an alarm
                alarms.setExact(AlarmManager.RTC_WAKEUP, mTime, pendingIntent);
            }
            if (DEBUG) Slog.d(TAG, String.format(
                    "Scheduling %s for %s, %s in the future (%s), now=%s",
                    ACTION, ts(time), time - now, span, ts(now)));
            alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
                    "%s %s for %s, %s in the future (%s), now=%s",
                    (mTime <= now ? "Not scheduling" : "Scheduling"),
                    ACTION, ts(mTime), mTime - now, span, ts(now)));
        }
    }

+75 −54
Original line number Diff line number Diff line
@@ -1340,11 +1340,13 @@ public class NotificationManagerService extends SystemService {
    void dumpImpl(PrintWriter pw, DumpFilter filter) {
        pw.print("Current Notification Manager state");
        if (filter != null) {
            pw.print(" (filtered to '"); pw.print(filter.pkgFilter); pw.print("')");
            pw.print(" (filtered to "); pw.print(filter); pw.print(")");
        }
        pw.println(':');
        int N;
        final boolean zenOnly = filter != null && filter.zen;

        if (!zenOnly) {
            synchronized (mToastQueue) {
                N = mToastQueue.size();
                if (N > 0) {
@@ -1355,8 +1357,10 @@ public class NotificationManagerService extends SystemService {
                    pw.println("  ");
                }
            }
        }

        synchronized (mNotificationList) {
            if (!zenOnly) {
                N = mNotificationList.size();
                if (N > 0) {
                    pw.println("  Notification List:");
@@ -1395,20 +1399,25 @@ public class NotificationManagerService extends SystemService {
                        break;
                    }
                }
            }

            if (!zenOnly) {
                pw.println("\n  Usage Stats:");
                mUsageStats.dump(pw, "    ", filter);
            }

            if (filter == null) {
            if (filter == null || zenOnly) {
                pw.println("\n  Zen Mode:");
                mZenModeHelper.dump(pw, "    ");
            }

            if (!zenOnly) {
                pw.println("\n  Ranking Config:");
                mRankingHelper.dump(pw, "    ", filter);

                pw.println("\n  Notification listeners:");
                mListeners.dump(pw, filter);
            }

            pw.println("\n  Condition providers:");
            mConditionProviders.dump(pw, filter);
@@ -2471,27 +2480,39 @@ public class NotificationManagerService extends SystemService {

    public static final class DumpFilter {
        public String pkgFilter;
        public boolean zen;

        public static DumpFilter parseFromArguments(String[] args) {
            if (args == null || args.length != 2 || !"p".equals(args[0])
                    || args[1] == null || args[1].trim().isEmpty()) {
                return null;
            }
            if (args != null && args.length == 2 && "p".equals(args[0])
                    && args[1] != null && !args[1].trim().isEmpty()) {
                final DumpFilter filter = new DumpFilter();
                filter.pkgFilter = args[1].trim().toLowerCase();
                return filter;
            }
            if (args != null && args.length == 1 && "zen".equals(args[0])) {
                final DumpFilter filter = new DumpFilter();
                filter.zen = true;
                return filter;
            }
            return null;
        }

        public boolean matches(StatusBarNotification sbn) {
            return sbn != null && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
            return zen ? true : sbn != null
                    && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg()));
        }

        public boolean matches(ComponentName component) {
            return component != null && matches(component.getPackageName());
            return zen ? true : component != null && matches(component.getPackageName());
        }

        public boolean matches(String pkg) {
            return pkg != null && pkg.toLowerCase().contains(pkgFilter);
            return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter);
        }

        @Override
        public String toString() {
            return zen ? "zen" : ('\'' + pkgFilter + '\'');
        }
    }
}