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

Commit 856edeba authored by John Spurlock's avatar John Spurlock
Browse files

Zen: Stateful condition panel.

When DND is on, expanded panel shows the current time
condition, or time remaining.  The last time bucket
selected is remembered as the default option for the
next time.

Move the server-side countdown helper into a proper
condition provider, but register it in-process as a
system provider.

Move common countdown condition parsing into ZenModeConfig
to reuse from system components.

Keep the manual exit condition around in zen mode config
and add plumbing for getting / listening to the
controller.

Keep the last QS detail panel around instead of
recreating it every time.

Fix the time condition's plus and minus button
enabling logic, and enhance the click handler to
deal properly with the next or previous bucket.

Bug:15344758
Change-Id: Ie7018a1c20e20f6d7e5f9e7874188374e6f8e2ab
parent a48e7b55
Loading
Loading
Loading
Loading
+49 −2
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Slog;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -37,6 +38,7 @@ import java.util.Objects;
 * @hide
 */
public class ZenModeConfig implements Parcelable {
    private static String TAG = "ZenModeConfig";

    public static final String SLEEP_MODE_NIGHTS = "nights";
    public static final String SLEEP_MODE_WEEKNIGHTS = "weeknights";
@@ -65,6 +67,9 @@ public class ZenModeConfig implements Parcelable {
    private static final String CONDITION_ATT_COMPONENT = "component";
    private static final String CONDITION_ATT_ID = "id";

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

    public boolean allowCalls;
    public boolean allowMessages;
    public int allowFrom = SOURCE_ANYONE;
@@ -76,6 +81,7 @@ public class ZenModeConfig implements Parcelable {
    public int sleepEndMinute;
    public ComponentName[] conditionComponents;
    public Uri[] conditionIds;
    public Uri exitConditionId;

    public ZenModeConfig() { }

@@ -100,6 +106,7 @@ public class ZenModeConfig implements Parcelable {
            source.readTypedArray(conditionIds, Uri.CREATOR);
        }
        allowFrom = source.readInt();
        exitConditionId = source.readParcelable(null);
    }

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

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

@@ -174,14 +183,16 @@ public class ZenModeConfig implements Parcelable {
                && other.sleepEndHour == sleepEndHour
                && other.sleepEndMinute == sleepEndMinute
                && Objects.deepEquals(other.conditionComponents, conditionComponents)
                && Objects.deepEquals(other.conditionIds, conditionIds);
                && Objects.deepEquals(other.conditionIds, conditionIds)
                && Objects.equals(other.exitConditionId, exitConditionId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(allowCalls, allowMessages, allowFrom, sleepMode,
                sleepStartHour, sleepStartMinute, sleepEndHour, sleepEndMinute,
                Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds));
                Arrays.hashCode(conditionComponents), Arrays.hashCode(conditionIds),
                exitConditionId);
    }

    public boolean isValid() {
@@ -239,6 +250,8 @@ public class ZenModeConfig implements Parcelable {
                        conditionComponents.add(component);
                        conditionIds.add(conditionId);
                    }
                } else if (EXIT_CONDITION_TAG.equals(tag)) {
                    rt.exitConditionId = safeUri(parser, EXIT_CONDITION_ATT_ID);
                }
            }
        }
@@ -275,6 +288,11 @@ public class ZenModeConfig implements Parcelable {
                out.endTag(null, CONDITION_TAG);
            }
        }
        if (exitConditionId != null) {
            out.startTag(null, EXIT_CONDITION_TAG);
            out.attribute(null, EXIT_CONDITION_ATT_ID, exitConditionId.toString());
            out.endTag(null, EXIT_CONDITION_TAG);
        }
        out.endTag(null, ZEN_TAG);
    }

@@ -338,4 +356,33 @@ public class ZenModeConfig implements Parcelable {
            return new ZenModeConfig[size];
        }
    };

    // Built-in countdown conditions, e.g. condition://android/countdown/1399917958951

    private static final String COUNTDOWN_AUTHORITY = "android";
    private static final String COUNTDOWN_PATH = "countdown";

    public static Uri toCountdownConditionId(long time) {
        return new Uri.Builder().scheme(Condition.SCHEME)
                .authority(COUNTDOWN_AUTHORITY)
                .appendPath(COUNTDOWN_PATH)
                .appendPath(Long.toString(time))
                .build();
    }

    public static long tryParseCountdownConditionId(Uri conditionId) {
        if (!Condition.isValidId(conditionId, COUNTDOWN_AUTHORITY)) return 0;
        if (conditionId.getPathSegments().size() != 2
                || !COUNTDOWN_PATH.equals(conditionId.getPathSegments().get(0))) return 0;
        try {
            return Long.parseLong(conditionId.getPathSegments().get(1));
        } catch (RuntimeException e) {
            Slog.w(TAG, "Error parsing countdown condition: " + conditionId, e);
            return 0;
        }
    }

    public static boolean isValidCountdownConditionId(Uri conditionId) {
        return tryParseCountdownConditionId(conditionId) != 0;
    }
}
+6 −3
Original line number Diff line number Diff line
@@ -156,12 +156,14 @@ public class QSPanel extends ViewGroup {
        AnimatorListener listener = null;
        if (show) {
            if (mDetailRecord != null) return;
            final View detail = r.tile.createDetailView(mContext, mDetail);
            if (detail == null) return;
            if (r.detailView == null) {
                r.detailView = r.tile.createDetailView(mContext, mDetail);
            }
            if (r.detailView == null) return;
            mDetailRecord = r;
            mDetail.removeAllViews();
            mDetail.bringToFront();
            mDetail.addView(detail);
            mDetail.addView(r.detailView);
        } else {
            if (mDetailRecord == null) return;
            listener = mTeardownDetailWhenDone;
@@ -273,6 +275,7 @@ public class QSPanel extends ViewGroup {
    private static final class TileRecord {
        QSTile<?> tile;
        QSTileView tileView;
        View detailView;
        int row;
        int col;
    }
+1 −1
Original line number Diff line number Diff line
@@ -135,7 +135,7 @@ public class QSTileView extends ViewGroup {
    }

    private Drawable getTileBackground() {
        final int[] attrs = new int[] { android.R.attr.selectableItemBackground};
        final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
        final TypedArray ta = mContext.obtainStyledAttributes(attrs);
        final Drawable d = ta.getDrawable(0);
        ta.recycle();
+4 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.statusbar.policy;

import android.net.Uri;
import android.service.notification.Condition;

public interface ZenModeController {
@@ -24,10 +25,12 @@ public interface ZenModeController {
    void setZen(boolean zen);
    boolean isZen();
    void requestConditions(boolean request);
    void select(Condition condition);
    void setExitConditionId(Uri exitConditionId);
    Uri getExitConditionId();

    public static class Callback {
        public void onZenChanged(boolean zen) {}
        public void onExitConditionChanged(Uri exitConditionId) {}
        public void onConditionsChanged(Condition[] conditions) {}
    }
}
 No newline at end of file
+40 −9
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.ServiceManager;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.service.notification.ZenModeConfig;
import android.util.Slog;

import com.android.systemui.qs.GlobalSetting;
@@ -35,10 +36,12 @@ import java.util.LinkedHashMap;
/** Platform implementation of the zen mode controller. **/
public class ZenModeControllerImpl implements ZenModeController {
    private static final String TAG = "ZenModeControllerImpl";
    private static final boolean DEBUG = false;

    private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
    private final Context mContext;
    private final GlobalSetting mSetting;
    private final GlobalSetting mModeSetting;
    private final GlobalSetting mConfigSetting;
    private final INotificationManager mNoMan;
    private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();

@@ -46,13 +49,20 @@ public class ZenModeControllerImpl implements ZenModeController {

    public ZenModeControllerImpl(Context context, Handler handler) {
        mContext = context;
        mSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
        mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
            @Override
            protected void handleValueChanged(int value) {
                fireZenChanged(value != 0);
            }
        };
        mSetting.setListening(true);
        mConfigSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE_CONFIG_ETAG) {
            @Override
            protected void handleValueChanged(int value) {
                fireExitConditionChanged();
            }
        };
        mModeSetting.setListening(true);
        mConfigSetting.setListening(true);
        mNoMan = INotificationManager.Stub.asInterface(
                ServiceManager.getService(Context.NOTIFICATION_SERVICE));
    }
@@ -69,12 +79,12 @@ public class ZenModeControllerImpl implements ZenModeController {

    @Override
    public boolean isZen() {
        return mSetting.getValue() != 0;
        return mModeSetting.getValue() != 0;
    }

    @Override
    public void setZen(boolean zen) {
        mSetting.setValue(zen ? 1 : 0);
        mModeSetting.setValue(zen ? 1 : 0);
    }

    @Override
@@ -91,12 +101,25 @@ public class ZenModeControllerImpl implements ZenModeController {
    }

    @Override
    public void select(Condition condition) {
    public void setExitConditionId(Uri exitConditionId) {
        try {
            mNoMan.setZenModeCondition(exitConditionId);
        } catch (RemoteException e) {
            // noop
        }
    }

    @Override
    public Uri getExitConditionId() {
        try {
            mNoMan.setZenModeCondition(condition == null ? null : condition.id);
            final ZenModeConfig config = mNoMan.getZenModeConfig();
            if (config != null) {
                return config.exitConditionId;
            }
        } catch (RemoteException e) {
            // noop
        }
        return null;
    }

    private void fireZenChanged(boolean zen) {
@@ -111,6 +134,14 @@ public class ZenModeControllerImpl implements ZenModeController {
        }
    }

    private void fireExitConditionChanged() {
        final Uri exitConditionId = getExitConditionId();
        if (DEBUG) Slog.d(TAG, "exitConditionId changed: " + exitConditionId);
        for (Callback cb : mCallbacks) {
            cb.onExitConditionChanged(exitConditionId);
        }
    }

    private void updateConditions(Condition[] conditions) {
        if (conditions == null || conditions.length == 0) return;
        for (Condition c : conditions) {
@@ -124,8 +155,8 @@ public class ZenModeControllerImpl implements ZenModeController {
    private final IConditionListener mListener = new IConditionListener.Stub() {
        @Override
        public void onConditionsReceived(Condition[] conditions) {
            Slog.d(TAG, "onConditionsReceived " + (conditions == null ? 0 : conditions.length)
                    + " mRequesting=" + mRequesting); 
            if (DEBUG) Slog.d(TAG, "onConditionsReceived "
                    + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting);
            if (!mRequesting) return;
            updateConditions(conditions);
        }
Loading