11c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley/*
21c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Copyright (C) 2015 The Android Open Source Project
31c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley *
41c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Licensed under the Apache License, Version 2.0 (the "License");
51c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * you may not use this file except in compliance with the License.
61c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * You may obtain a copy of the License at
71c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley *
81c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley *      http://www.apache.org/licenses/LICENSE-2.0
91c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley *
101c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Unless required by applicable law or agreed to in writing, software
111c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * distributed under the License is distributed on an "AS IS" BASIS,
121c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * See the License for the specific language governing permissions and
141c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * limitations under the License.
151c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley */
161c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
171c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileypackage android.app.test;
181c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
191c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.any;
201c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.anyInt;
211c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.anyLong;
221c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.anyString;
231c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.doAnswer;
241c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport static org.mockito.Mockito.mock;
251c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
261c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport android.app.AlarmManager;
271c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport android.app.test.MockAnswerUtil.AnswerWithArguments;
281c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport android.os.Handler;
291c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
301c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport java.util.ArrayList;
311c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport java.util.Iterator;
321c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport java.util.List;
331c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileyimport java.util.Objects;
341c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
351c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley/**
361c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Creates an AlarmManager whose alarm dispatch can be controlled
371c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Currently only supports alarm listeners
381c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley *
391c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * Alarm listeners will be dispatched to the handler provided or will
401c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * be dispatched immediately if they would have been sent to the main
411c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley * looper (handler was null).
421c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley */
431c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wileypublic class TestAlarmManager {
441c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private final AlarmManager mAlarmManager;
451c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private final List<PendingAlarm> mPendingAlarms;
461c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
471c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    public TestAlarmManager() throws Exception {
481c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        mPendingAlarms = new ArrayList<>();
491c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
501c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        mAlarmManager = mock(AlarmManager.class);
511c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        doAnswer(new SetListenerAnswer()).when(mAlarmManager).set(anyInt(), anyLong(), anyString(),
521c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                any(AlarmManager.OnAlarmListener.class), any(Handler.class));
531c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        doAnswer(new SetListenerAnswer()).when(mAlarmManager).setExact(anyInt(), anyLong(),
541c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                anyString(), any(AlarmManager.OnAlarmListener.class), any(Handler.class));
551c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        doAnswer(new CancelListenerAnswer())
561c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                .when(mAlarmManager).cancel(any(AlarmManager.OnAlarmListener.class));
571c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
581c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
591c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    public AlarmManager getAlarmManager() {
601c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        return mAlarmManager;
611c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
621c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
631c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    /**
641c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     * Dispatch a pending alarm with the given tag
651c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     * @return if any alarm was dispatched
661c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     */
671c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    public boolean dispatch(String tag) {
681c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        for (int i = 0; i < mPendingAlarms.size(); ++i) {
691c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            PendingAlarm alarm = mPendingAlarms.get(i);
701c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            if (Objects.equals(tag, alarm.getTag())) {
711c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                mPendingAlarms.remove(i);
721c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                alarm.dispatch();
731c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                return true;
741c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
751c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
761c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        return false;
771c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
781c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
791c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    /**
801c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     * @return if an alarm with the given tag is pending
811c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     */
821c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    public boolean isPending(String tag) {
831c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        for (int i = 0; i < mPendingAlarms.size(); ++i) {
841c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            PendingAlarm alarm = mPendingAlarms.get(i);
851c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            if (Objects.equals(tag, alarm.getTag())) {
861c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                return true;
871c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
881c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
891c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        return false;
901c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
911c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
921c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    /**
931c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     * @return trigger time of an pending alarm with the given tag
941c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     *         -1 if no pending alarm with the given tag
951c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley     */
961c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    public long getTriggerTimeMillis(String tag) {
971c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        for (int i = 0; i < mPendingAlarms.size(); ++i) {
981c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            PendingAlarm alarm = mPendingAlarms.get(i);
991c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            if (Objects.equals(tag, alarm.getTag())) {
1001c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                return alarm.getTriggerTimeMillis();
1011c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
1021c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1031c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        return -1;
1041c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
1051c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1061c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private static class PendingAlarm {
1071c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final int mType;
1081c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final long mTriggerAtMillis;
1091c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final String mTag;
1101c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final Runnable mCallback;
1111c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1121c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public PendingAlarm(int type, long triggerAtMillis, String tag, Runnable callback) {
1131c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mType = type;
1141c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mTriggerAtMillis = triggerAtMillis;
1151c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mTag = tag;
1161c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mCallback = callback;
1171c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1181c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1191c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public void dispatch() {
1201c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            if (mCallback != null) {
1211c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                mCallback.run();
1221c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
1231c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1241c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1251c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public Runnable getCallback() {
1261c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            return mCallback;
1271c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1281c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1291c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public String getTag() {
1301c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            return mTag;
1311c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1321c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1331c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public long getTriggerTimeMillis() {
1341c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            return mTriggerAtMillis;
1351c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1361c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
1371c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1381c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private class SetListenerAnswer extends AnswerWithArguments {
1391c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public void answer(int type, long triggerAtMillis, String tag,
1401c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                AlarmManager.OnAlarmListener listener, Handler handler) {
1411c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mPendingAlarms.add(new PendingAlarm(type, triggerAtMillis, tag,
1421c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                            new AlarmListenerRunnable(listener, handler)));
1431c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1441c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
1451c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1461c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private class CancelListenerAnswer extends AnswerWithArguments {
1471c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public void answer(AlarmManager.OnAlarmListener listener) {
1481c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            Iterator<PendingAlarm> alarmItr = mPendingAlarms.iterator();
1491c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            while (alarmItr.hasNext()) {
1501c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                PendingAlarm alarm = alarmItr.next();
1511c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                if (alarm.getCallback() instanceof AlarmListenerRunnable) {
1521c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                    AlarmListenerRunnable alarmCallback =
1531c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                            (AlarmListenerRunnable) alarm.getCallback();
1541c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                    if (alarmCallback.getListener() == listener) {
1551c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                        alarmItr.remove();
1561c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                    }
1571c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                }
1581c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
1591c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1601c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
1611c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1621c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    private static class AlarmListenerRunnable implements Runnable {
1631c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final AlarmManager.OnAlarmListener mListener;
1641c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        private final Handler mHandler;
1651c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public AlarmListenerRunnable(AlarmManager.OnAlarmListener listener, Handler handler) {
1661c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mListener = listener;
1671c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            mHandler = handler;
1681c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1691c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1701c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public AlarmManager.OnAlarmListener getListener() {
1711c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            return mListener;
1721c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1731c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley
1741c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        @Override
1751c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        public void run() {
1761c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            if (mHandler != null) {
1771c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                mHandler.post(new Runnable() {
1781c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                        @Override
1791c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                        public void run() {
1801c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                            mListener.onAlarm();
1811c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                        }
1821c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                    });
1831c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            } else { // normally gets dispatched in main looper
1841c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley                mListener.onAlarm();
1851c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley            }
1861c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley        }
1871c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley    }
1881c811fa46810612adf039f8aafa235ddb39aaa32Christopher Wiley}
189