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