blob: 5575348244cd9c4eecac5517a5d78ad19ebb15c1 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.deskclock;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
import android.provider.AlarmClock;
import com.android.deskclock.alarms.AlarmStateManager;
import com.android.deskclock.controller.Controller;
import com.android.deskclock.provider.Alarm;
import com.android.deskclock.provider.AlarmInstance;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
* Returns a list of alarms that are specified by the intent
* processed by HandleDeskClockApiCalls
* if there are more than 1 matching alarms and the SEARCH_MODE is not ALL
* we show a picker UI dialog
*/
class FetchMatchingAlarmsAction implements Runnable {
private final Context mContext;
private final List<Alarm> mAlarms;
private final Intent mIntent;
private final List<Alarm> mMatchingAlarms = new ArrayList<>();
private final Activity mActivity;
public FetchMatchingAlarmsAction(Context context, List<Alarm> alarms, Intent intent,
Activity activity) {
mContext = context;
// only enabled alarms are passed
mAlarms = alarms;
mIntent = intent;
mActivity = activity;
}
@Override
public void run() {
Utils.enforceNotMainLooper();
final String searchMode = mIntent.getStringExtra(AlarmClock.EXTRA_ALARM_SEARCH_MODE);
// if search mode isn't specified show all alarms in the UI picker
if (searchMode == null) {
mMatchingAlarms.addAll(mAlarms);
return;
}
final ContentResolver cr = mContext.getContentResolver();
switch (searchMode) {
case AlarmClock.ALARM_SEARCH_MODE_TIME:
// at least one of these has to be specified in this search mode.
final int hour = mIntent.getIntExtra(AlarmClock.EXTRA_HOUR, -1);
// if minutes weren't specified default to 0
final int minutes = mIntent.getIntExtra(AlarmClock.EXTRA_MINUTES, 0);
final Boolean isPm = (Boolean) mIntent.getExtras().get(AlarmClock.EXTRA_IS_PM);
boolean badInput = isPm != null && hour > 12 && isPm;
badInput |= hour < 0 || hour > 23;
badInput |= minutes < 0 || minutes > 59;
if (badInput) {
final String[] ampm = new DateFormatSymbols().getAmPmStrings();
final String amPm = isPm == null ? "" : (isPm ? ampm[1] : ampm[0]);
final String reason = mContext.getString(R.string.invalid_time, hour, minutes,
amPm);
notifyFailureAndLog(reason, mActivity);
return;
}
final int hour24 = Boolean.TRUE.equals(isPm) && hour < 12 ? (hour + 12) : hour;
// there might me multiple alarms at the same time
for (Alarm alarm : mAlarms) {
if (alarm.hour == hour24 && alarm.minutes == minutes) {
mMatchingAlarms.add(alarm);
}
}
if (mMatchingAlarms.isEmpty()) {
final String reason = mContext.getString(R.string.no_alarm_at, hour24, minutes);
notifyFailureAndLog(reason, mActivity);
return;
}
break;
case AlarmClock.ALARM_SEARCH_MODE_NEXT:
// Match currently firing alarms before scheduled alarms.
for (Alarm alarm : mAlarms) {
final AlarmInstance alarmInstance =
AlarmInstance.getNextUpcomingInstanceByAlarmId(cr, alarm.id);
if (alarmInstance != null
&& alarmInstance.mAlarmState == AlarmInstance.FIRED_STATE) {
mMatchingAlarms.add(alarm);
}
}
if (!mMatchingAlarms.isEmpty()) {
// return the matched firing alarms
return;
}
final AlarmInstance nextAlarm = AlarmStateManager.getNextFiringAlarm(mContext);
if (nextAlarm == null) {
final String reason = mContext.getString(R.string.no_scheduled_alarms);
notifyFailureAndLog(reason, mActivity);
return;
}
// get time from nextAlarm and see if there are any other alarms matching this time
final Calendar nextTime = nextAlarm.getAlarmTime();
final List<Alarm> alarmsFiringAtSameTime = getAlarmsByHourMinutes(
nextTime.get(Calendar.HOUR_OF_DAY), nextTime.get(Calendar.MINUTE), cr);
// there might me multiple alarms firing next
mMatchingAlarms.addAll(alarmsFiringAtSameTime);
break;
case AlarmClock.ALARM_SEARCH_MODE_ALL:
mMatchingAlarms.addAll(mAlarms);
break;
case AlarmClock.ALARM_SEARCH_MODE_LABEL:
// EXTRA_MESSAGE has to be set in this mode
final String label = mIntent.getStringExtra(AlarmClock.EXTRA_MESSAGE);
if (label == null) {
final String reason = mContext.getString(R.string.no_label_specified);
notifyFailureAndLog(reason, mActivity);
return;
}
// there might me multiple alarms with this label
for (Alarm alarm : mAlarms) {
if (alarm.label.contains(label)) {
mMatchingAlarms.add(alarm);
}
}
if (mMatchingAlarms.isEmpty()) {
final String reason = mContext.getString(R.string.no_alarms_with_label);
notifyFailureAndLog(reason, mActivity);
return;
}
break;
}
}
private List<Alarm> getAlarmsByHourMinutes(int hour24, int minutes, ContentResolver cr) {
// if we want to dismiss we should only add enabled alarms
final String selection = String.format("%s=? AND %s=? AND %s=?",
Alarm.HOUR, Alarm.MINUTES, Alarm.ENABLED);
final String[] args = { String.valueOf(hour24), String.valueOf(minutes), "1" };
return Alarm.getAlarms(cr, selection, args);
}
public List<Alarm> getMatchingAlarms() {
return mMatchingAlarms;
}
private void notifyFailureAndLog(String reason, Activity activity) {
LogUtils.e(reason);
Controller.getController().notifyVoiceFailure(activity, reason);
}
}