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

Commit 4b318436 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Update 'next alarm' tracking

Also improves logging and adds tests.

Test: runtest systemui-notification
Bug: 67028535
Bug: 69440234
Change-Id: I259fdc2d253d2a4ac415e23bd66a0b9d7c69b053
parent 9cc5b4f0
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -890,7 +890,17 @@ public class ZenModeConfig implements Parcelable {
    }

    public static boolean isValidScheduleConditionId(Uri conditionId) {
        return tryParseScheduleConditionId(conditionId) != null;
        ScheduleInfo info;
        try {
            info = tryParseScheduleConditionId(conditionId);
        } catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
            return false;
        }

        if (info == null || info.days == null || info.days.length == 0) {
            return false;
        }
        return true;
    }

    public static ScheduleInfo tryParseScheduleConditionId(Uri conditionId) {
+2 −2
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<com.android.systemui.HardwareUiLayout
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
@@ -45,4 +45,4 @@
        </LinearLayout>

    </RelativeLayout>
</com.android.systemui.HardwareUiLayout>
</RelativeLayout>
+49 −10
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package com.android.systemui.volume;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;

import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;

import android.accessibilityservice.AccessibilityServiceInfo;
@@ -42,6 +45,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.Log;
import android.util.Slog;
@@ -67,6 +71,7 @@ import android.widget.TextView;

import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.HardwareBgDrawable;
import com.android.systemui.HardwareUiLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -74,6 +79,7 @@ import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
import com.android.systemui.util.leak.RotationUtils;

import java.io.PrintWriter;
import java.util.ArrayList;
@@ -97,9 +103,13 @@ public class VolumeDialogImpl implements VolumeDialog {
    private final VolumeDialogController mController;

    private Window mWindow;
    private HardwareUiLayout mHardwareLayout;
    //private HardwareUiLayout mHardwareLayout;
    private CustomDialog mDialog;
    private ViewGroup mDialogView;
    private boolean mEdgeBleed;
    private boolean mRoundedDivider;
    private HardwareBgDrawable mBackground;
    private int mRotation = ROTATION_NONE;
    private ViewGroup mDialogRowsView;
    private ViewGroup mDialogContentView;
    private final List<VolumeRow> mRows = new ArrayList<>();
@@ -111,6 +121,8 @@ public class VolumeDialogImpl implements VolumeDialog {
    private final Accessibility mAccessibility = new Accessibility();
    private final ColorStateList mActiveSliderTint;
    private final ColorStateList mInactiveSliderTint;
    private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
    private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";

    private boolean mShowing;
    private boolean mShowA11yStream;
@@ -181,8 +193,16 @@ public class VolumeDialogImpl implements VolumeDialog {
                return true;
            }
        });
        mHardwareLayout = HardwareUiLayout.get(mDialogView);
        mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));

        mEdgeBleed = Settings.Secure.getInt(mContext.getContentResolver(),
                EDGE_BLEED, 0) != 0;
        mRoundedDivider = Settings.Secure.getInt(mContext.getContentResolver(),
                ROUNDED_DIVIDER, 1) != 0;
        updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
        mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, mContext);
        mDialogView.setBackground(mBackground);
        //mHardwareLayout = HardwareUiLayout.get(mDialogView);
        //mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));

        mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
        mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
@@ -210,6 +230,25 @@ public class VolumeDialogImpl implements VolumeDialog {
        updateRowsH(getActiveRow());
    }

    private int getEdgePadding() {
        return mContext.getResources().getDimensionPixelSize(R.dimen.edge_margin);
    }

    private void updateEdgeMargin(int edge) {
        if (mDialogView != null) {
            mRotation = RotationUtils.getRotation(mContext);
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mDialogView.getLayoutParams();
            if (mRotation == ROTATION_LANDSCAPE) {
                params.topMargin = edge;
            } else if (mRotation == ROTATION_SEASCAPE) {
                params.bottomMargin = edge;
            } else {
                params.rightMargin = edge;
            }
            mDialogView.setLayoutParams(params);
        }
    }

    private ColorStateList loadColorStateList(int colorResId) {
        return ColorStateList.valueOf(mContext.getColor(colorResId));
    }
@@ -389,11 +428,11 @@ public class VolumeDialogImpl implements VolumeDialog {
        rescheduleTimeoutH();
        if (mShowing) return;
        mShowing = true;
        mHardwareLayout.setTranslationX(getAnimTranslation());
        mHardwareLayout.setAlpha(0);
        mHardwareLayout.animate()
        mDialogView.setTranslationY(getAnimTranslation());
        mDialogView.setAlpha(0);
        mDialogView.animate()
                .alpha(1)
                .translationX(0)
                .translationY(0)
                .setDuration(300)
                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                .withEndAction(() -> {
@@ -432,9 +471,9 @@ public class VolumeDialogImpl implements VolumeDialog {
        mHandler.removeMessages(H.SHOW);
        if (!mShowing) return;
        mShowing = false;
        mHardwareLayout.setTranslationX(0);
        mHardwareLayout.setAlpha(1);
        mHardwareLayout.animate()
        mDialogView.setTranslationX(0);
        mDialogView.setAlpha(1);
        mDialogView.animate()
                .alpha(0)
                .translationX(getAnimTranslation())
                .setDuration(300)
+23 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.notification;

import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.util.ArraySet;
import android.util.Log;

import java.util.Calendar;
import java.util.Objects;
@@ -41,10 +42,25 @@ public class ScheduleCalendar {
    }

    public void maybeSetNextAlarm(long now, long nextAlarm) {
        if (mSchedule != null) {
            if (mSchedule.exitAtAlarm
                    && (now > mSchedule.nextAlarm || nextAlarm < mSchedule.nextAlarm)) {
        if (mSchedule != null && mSchedule.exitAtAlarm) {
            // alarm canceled
            if (nextAlarm == 0) {
                mSchedule.nextAlarm = 0;
            }
            // only allow alarms in the future
            if (nextAlarm > now) {
                // store earliest alarm
                if (mSchedule.nextAlarm == 0) {
                    mSchedule.nextAlarm = nextAlarm;
                } else {
                    mSchedule.nextAlarm = Math.min(mSchedule.nextAlarm, nextAlarm);
                }
            } else if (mSchedule.nextAlarm < now) {
                if (ScheduleConditionProvider.DEBUG) {
                    Log.d(ScheduleConditionProvider.TAG,
                            "All alarms are in the past " + mSchedule.nextAlarm);
                }
                mSchedule.nextAlarm = 0;
            }
        }
    }
@@ -87,6 +103,9 @@ public class ScheduleCalendar {
    }

    public boolean shouldExitForAlarm(long time) {
        if (mSchedule == null) {
            return false;
        }
        return mSchedule.exitAtAlarm
                && mSchedule.nextAlarm != 0
                && time >= mSchedule.nextAlarm;
+56 −42
Original line number Diff line number Diff line
@@ -37,6 +37,8 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.notification.NotificationManagerService.DumpFilter;

import java.io.PrintWriter;
@@ -62,10 +64,9 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    private static final String SEPARATOR = ";";
    private static final String SCP_SETTING = "snoozed_schedule_condition_provider";


    private final Context mContext = this;
    private final ArrayMap<Uri, ScheduleCalendar> mSubscriptions = new ArrayMap<>();
    private ArraySet<Uri> mSnoozed = new ArraySet<>();
    private ArraySet<Uri> mSnoozedForAlarm = new ArraySet<>();

    private AlarmManager mAlarmManager;
    private boolean mConnected;
@@ -102,7 +103,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
                pw.println(mSubscriptions.get(conditionId).toString());
            }
        }
        pw.println("      snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozed));
        pw.println("      snoozed due to alarm: " + TextUtils.join(SEPARATOR, mSnoozedForAlarm));
        dumpUpcomingTime(pw, "mNextAlarmTime", mNextAlarmTime, now);
    }

@@ -129,7 +130,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    public void onSubscribe(Uri conditionId) {
        if (DEBUG) Slog.d(TAG, "onSubscribe " + conditionId);
        if (!ZenModeConfig.isValidScheduleConditionId(conditionId)) {
            notifyCondition(createCondition(conditionId, Condition.STATE_FALSE, "badCondition"));
            notifyCondition(createCondition(conditionId, Condition.STATE_ERROR, "invalidId"));
            return;
        }
        synchronized (mSubscriptions) {
@@ -169,37 +170,49 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
        synchronized (mSubscriptions) {
            setRegistered(!mSubscriptions.isEmpty());
            for (Uri conditionId : mSubscriptions.keySet()) {
                final ScheduleCalendar cal = mSubscriptions.get(conditionId);
                if (cal != null && cal.isInSchedule(now)) {
                    if (conditionSnoozed(conditionId) || cal.shouldExitForAlarm(now)) {
                        conditionsToNotify.add(createCondition(
                                conditionId, Condition.STATE_FALSE, "alarmCanceled"));
                Condition condition =
                        evaluateSubscriptionLocked(conditionId, mSubscriptions.get(conditionId),
                                now, nextUserAlarmTime);
                if (condition != null) {
                    conditionsToNotify.add(condition);
                }
            }
        }
        notifyConditions(conditionsToNotify.toArray(new Condition[conditionsToNotify.size()]));
        updateAlarm(now, mNextAlarmTime);
    }

    @VisibleForTesting
    @GuardedBy("mSubscriptions")
    Condition evaluateSubscriptionLocked(Uri conditionId, ScheduleCalendar cal,
            long now, long nextUserAlarmTime) {
        Condition condition;
        if (cal == null) {
            condition = createCondition(conditionId, Condition.STATE_ERROR, "!invalidId");
            removeSnoozed(conditionId);
            return condition;
        }
        if (cal.isInSchedule(now)) {
            if (conditionSnoozed(conditionId)) {
                condition = createCondition(conditionId, Condition.STATE_FALSE, "snoozed");
            } else if (cal.shouldExitForAlarm(now)) {
                condition = createCondition(conditionId, Condition.STATE_FALSE, "alarmCanceled");
                addSnoozed(conditionId);
            } else {
                        conditionsToNotify.add(createCondition(
                                conditionId, Condition.STATE_TRUE, "meetsSchedule"));
                condition = createCondition(conditionId, Condition.STATE_TRUE, "meetsSchedule");
            }
                    cal.maybeSetNextAlarm(now, nextUserAlarmTime);
        } else {
                    conditionsToNotify.add(createCondition(
                            conditionId, Condition.STATE_FALSE, "!meetsSchedule"));
            condition = createCondition(conditionId, Condition.STATE_FALSE, "!meetsSchedule");
            removeSnoozed(conditionId);
                    if (cal != null && nextUserAlarmTime == 0) {
                        cal.maybeSetNextAlarm(now, nextUserAlarmTime);
                    }
        }
                if (cal != null) {
        cal.maybeSetNextAlarm(now, nextUserAlarmTime);
        final long nextChangeTime = cal.getNextChangeTime(now);
        if (nextChangeTime > 0 && nextChangeTime > now) {
            if (mNextAlarmTime == 0 || nextChangeTime < mNextAlarmTime) {
                mNextAlarmTime = nextChangeTime;
            }
        }
                }
            }
        }
        notifyConditions(conditionsToNotify.toArray(new Condition[conditionsToNotify.size()]));
        updateAlarm(now, mNextAlarmTime);
        return condition;
    }

    private void updateAlarm(long now, long time) {
@@ -266,27 +279,28 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
    }

    private boolean conditionSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            return mSnoozed.contains(conditionId);
        synchronized (mSnoozedForAlarm) {
            return mSnoozedForAlarm.contains(conditionId);
        }
    }

    private void addSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            mSnoozed.add(conditionId);
    @VisibleForTesting
    void addSnoozed(Uri conditionId) {
        synchronized (mSnoozedForAlarm) {
            mSnoozedForAlarm.add(conditionId);
            saveSnoozedLocked();
        }
    }

    private void removeSnoozed(Uri conditionId) {
        synchronized (mSnoozed) {
            mSnoozed.remove(conditionId);
        synchronized (mSnoozedForAlarm) {
            mSnoozedForAlarm.remove(conditionId);
            saveSnoozedLocked();
        }
    }

    public void saveSnoozedLocked() {
        final String setting = TextUtils.join(SEPARATOR, mSnoozed);
    private void saveSnoozedLocked() {
        final String setting = TextUtils.join(SEPARATOR, mSnoozedForAlarm);
        final int currentUser = ActivityManager.getCurrentUser();
        Settings.Secure.putStringForUser(mContext.getContentResolver(),
                SCP_SETTING,
@@ -294,8 +308,8 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
                currentUser);
    }

    public void readSnoozed() {
        synchronized (mSnoozed) {
    private void readSnoozed() {
        synchronized (mSnoozedForAlarm) {
            long identity = Binder.clearCallingIdentity();
            try {
                final String setting = Settings.Secure.getStringForUser(
@@ -312,7 +326,7 @@ public class ScheduleConditionProvider extends SystemConditionProviderService {
                        if (TextUtils.isEmpty(token)) {
                            continue;
                        }
                        mSnoozed.add(Uri.parse(token));
                        mSnoozedForAlarm.add(Uri.parse(token));
                    }
                }
            } finally {
Loading