HandleApiCalls.java revision 6c6337ce2b39ffa1395e8039bd739893b41a1b3a
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.deskclock; 18 19import android.app.Activity; 20import android.content.ContentResolver; 21import android.content.Intent; 22import android.content.SharedPreferences; 23import android.media.RingtoneManager; 24import android.net.Uri; 25import android.os.Bundle; 26import android.preference.PreferenceManager; 27import android.support.v7.app.AppCompatActivity; 28import android.text.TextUtils; 29 30import com.android.deskclock.alarms.AlarmStateManager; 31import com.android.deskclock.provider.Alarm; 32import com.android.deskclock.provider.AlarmInstance; 33import com.android.deskclock.provider.DaysOfWeek; 34import com.android.deskclock.timer.TimerFullScreenFragment; 35import com.android.deskclock.timer.TimerObj; 36import com.android.deskclock.timer.Timers; 37 38import java.util.ArrayList; 39import java.util.Calendar; 40import java.util.List; 41 42import static android.provider.AlarmClock.ACTION_SET_ALARM; 43import static android.provider.AlarmClock.ACTION_SET_TIMER; 44import static android.provider.AlarmClock.ACTION_SHOW_ALARMS; 45import static android.provider.AlarmClock.EXTRA_DAYS; 46import static android.provider.AlarmClock.EXTRA_HOUR; 47import static android.provider.AlarmClock.EXTRA_LENGTH; 48import static android.provider.AlarmClock.EXTRA_MESSAGE; 49import static android.provider.AlarmClock.EXTRA_MINUTES; 50import static android.provider.AlarmClock.EXTRA_RINGTONE; 51import static android.provider.AlarmClock.EXTRA_SKIP_UI; 52import static android.provider.AlarmClock.EXTRA_VIBRATE; 53import static android.provider.AlarmClock.VALUE_RINGTONE_SILENT; 54 55public class HandleApiCalls extends AppCompatActivity { 56 57 public static final long TIMER_MIN_LENGTH = 1000; 58 public static final long TIMER_MAX_LENGTH = 24 * 60 * 60 * 1000; 59 60 @Override 61 protected void onCreate(Bundle icicle) { 62 try { 63 super.onCreate(icicle); 64 Intent intent = getIntent(); 65 if (intent != null) { 66 if (ACTION_SET_ALARM.equals(intent.getAction())) { 67 handleSetAlarm(intent); 68 } else if (ACTION_SHOW_ALARMS.equals(intent.getAction())) { 69 handleShowAlarms(); 70 } else if (ACTION_SET_TIMER.equals(intent.getAction())) { 71 handleSetTimer(intent); 72 } 73 } 74 } finally { 75 finish(); 76 } 77 } 78 79 /*** 80 * Processes the SET_ALARM intent 81 * @param intent 82 */ 83 private void handleSetAlarm(Intent intent) { 84 // If not provided or invalid, show UI 85 final int hour = intent.getIntExtra(EXTRA_HOUR, -1); 86 87 // If not provided, use zero. If it is provided, make sure it's valid, otherwise, show UI 88 final int minutes; 89 if (intent.hasExtra(EXTRA_MINUTES)) { 90 minutes = intent.getIntExtra(EXTRA_MINUTES, -1); 91 } else { 92 minutes = 0; 93 } 94 if (hour < 0 || hour > 23 || minutes < 0 || minutes > 59) { 95 // Intent has no time or an invalid time, open the alarm creation UI 96 Intent createAlarm = Alarm.createIntent(this, DeskClock.class, Alarm.INVALID_ID); 97 createAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 98 createAlarm.putExtra(AlarmClockFragment.ALARM_CREATE_NEW_INTENT_EXTRA, true); 99 createAlarm.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX); 100 startActivity(createAlarm); 101 finish(); 102 LogUtils.i("HandleApiCalls no/invalid time; opening UI"); 103 return; 104 } 105 106 final boolean skipUi = intent.getBooleanExtra(EXTRA_SKIP_UI, false); 107 108 final StringBuilder selection = new StringBuilder(); 109 final List<String> args = new ArrayList<String>(); 110 setSelectionFromIntent(intent, hour, minutes, selection, args); 111 112 // Check if the alarm already exists and handle it 113 final ContentResolver cr = getContentResolver(); 114 final List<Alarm> alarms = Alarm.getAlarms(cr, 115 selection.toString(), 116 args.toArray(new String[args.size()])); 117 if (!alarms.isEmpty()) { 118 Alarm alarm = alarms.get(0); 119 alarm.enabled = true; 120 Alarm.updateAlarm(cr, alarm); 121 122 // Delete all old instances and create a new one with updated values 123 AlarmStateManager.deleteAllInstances(this, alarm.id); 124 setupInstance(alarm.createInstanceAfter(Calendar.getInstance()), skipUi); 125 LogUtils.i("HandleApiCalls deleted old, created new alarm: %s", alarm); 126 finish(); 127 return; 128 } 129 130 // Otherwise insert it and handle it 131 final String message = getMessageFromIntent(intent); 132 final DaysOfWeek daysOfWeek = getDaysFromIntent(intent); 133 final boolean vibrate = intent.getBooleanExtra(EXTRA_VIBRATE, false); 134 final String alert = intent.getStringExtra(EXTRA_RINGTONE); 135 136 Alarm alarm = new Alarm(hour, minutes); 137 alarm.enabled = true; 138 alarm.label = message; 139 alarm.daysOfWeek = daysOfWeek; 140 alarm.vibrate = vibrate; 141 142 if (alert == null) { 143 alarm.alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); 144 } else if (VALUE_RINGTONE_SILENT.equals(alert) || alert.isEmpty()) { 145 alarm.alert = Alarm.NO_RINGTONE_URI; 146 } else { 147 alarm.alert = Uri.parse(alert); 148 } 149 alarm.deleteAfterUse = !daysOfWeek.isRepeating() && skipUi; 150 151 alarm = Alarm.addAlarm(cr, alarm); 152 setupInstance(alarm.createInstanceAfter(Calendar.getInstance()), skipUi); 153 LogUtils.i("HandleApiCalls set up alarm: %s", alarm); 154 finish(); 155 } 156 157 private void handleShowAlarms() { 158 startActivity(new Intent(this, DeskClock.class) 159 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX)); 160 LogUtils.i("HandleApiCalls show alarms"); 161 } 162 163 private void handleSetTimer(Intent intent) { 164 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); 165 // If no length is supplied , show the timer setup view 166 if (!intent.hasExtra(EXTRA_LENGTH)) { 167 startActivity(new Intent(this, DeskClock.class) 168 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX) 169 .putExtra(TimerFullScreenFragment.GOTO_SETUP_VIEW, true)); 170 LogUtils.i("HandleApiCalls showing timer setup"); 171 return; 172 } 173 174 final long length = 1000l * intent.getIntExtra(EXTRA_LENGTH, 0); 175 if (length < TIMER_MIN_LENGTH || length > TIMER_MAX_LENGTH) { 176 LogUtils.i("Invalid timer length requested: " + length); 177 return; 178 } 179 String label = getMessageFromIntent(intent); 180 181 TimerObj timer = null; 182 // Find an existing matching time 183 final ArrayList<TimerObj> timers = new ArrayList<TimerObj>(); 184 TimerObj.getTimersFromSharedPrefs(prefs, timers); 185 for (TimerObj t : timers) { 186 if (t.mSetupLength == length && (TextUtils.equals(label, t.mLabel)) 187 && t.mState == TimerObj.STATE_RESTART) { 188 timer = t; 189 break; 190 } 191 } 192 193 boolean skipUi = intent.getBooleanExtra(EXTRA_SKIP_UI, false); 194 if (timer == null) { 195 // Use a new timer 196 timer = new TimerObj(length, label, this /* context */); 197 // Timers set without presenting UI to the user will be deleted after use 198 timer.mDeleteAfterUse = skipUi; 199 } 200 201 timer.setState(TimerObj.STATE_RUNNING); 202 timer.mStartTime = Utils.getTimeNow(); 203 timer.writeToSharedPref(prefs); 204 205 // Tell TimerReceiver that the timer was started 206 sendBroadcast(new Intent().setAction(Timers.START_TIMER) 207 .putExtra(Timers.TIMER_INTENT_EXTRA, timer.mTimerId)); 208 209 if (skipUi) { 210 Utils.showInUseNotifications(this); 211 } else { 212 startActivity(new Intent(this, DeskClock.class) 213 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX) 214 .putExtra(Timers.FIRST_LAUNCH_FROM_API_CALL, true)); 215 } 216 LogUtils.i("HandleApiCalls timer created: %s", timer); 217 } 218 219 private void setupInstance(AlarmInstance instance, boolean skipUi) { 220 instance = AlarmInstance.addInstance(this.getContentResolver(), instance); 221 AlarmStateManager.registerInstance(this, instance, true); 222 AlarmUtils.popAlarmSetToast(this, instance.getAlarmTime().getTimeInMillis()); 223 if (!skipUi) { 224 Intent showAlarm = Alarm.createIntent(this, DeskClock.class, instance.mAlarmId); 225 showAlarm.putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.ALARM_TAB_INDEX); 226 showAlarm.putExtra(AlarmClockFragment.SCROLL_TO_ALARM_INTENT_EXTRA, instance.mAlarmId); 227 showAlarm.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 228 startActivity(showAlarm); 229 } 230 } 231 232 private String getMessageFromIntent(Intent intent) { 233 final String message = intent.getStringExtra(EXTRA_MESSAGE); 234 return message == null ? "" : message; 235 } 236 237 private DaysOfWeek getDaysFromIntent(Intent intent) { 238 final DaysOfWeek daysOfWeek = new DaysOfWeek(0); 239 final ArrayList<Integer> days = intent.getIntegerArrayListExtra(EXTRA_DAYS); 240 if (days != null) { 241 final int[] daysArray = new int[days.size()]; 242 for (int i = 0; i < days.size(); i++) { 243 daysArray[i] = days.get(i); 244 } 245 daysOfWeek.setDaysOfWeek(true, daysArray); 246 } else { 247 // API says to use an ArrayList<Integer> but we allow the user to use a int[] too. 248 final int[] daysArray = intent.getIntArrayExtra(EXTRA_DAYS); 249 if (daysArray != null) { 250 daysOfWeek.setDaysOfWeek(true, daysArray); 251 } 252 } 253 return daysOfWeek; 254 } 255 256 private void setSelectionFromIntent( 257 Intent intent, 258 int hour, 259 int minutes, 260 StringBuilder selection, 261 List<String> args) { 262 selection.append(Alarm.HOUR).append("=?"); 263 args.add(String.valueOf(hour)); 264 selection.append(" AND ").append(Alarm.MINUTES).append("=?"); 265 args.add(String.valueOf(minutes)); 266 267 if (intent.hasExtra(EXTRA_MESSAGE)) { 268 selection.append(" AND ").append(Alarm.LABEL).append("=?"); 269 args.add(getMessageFromIntent(intent)); 270 } 271 272 // Days is treated differently that other fields because if days is not specified, it 273 // explicitly means "not recurring". 274 selection.append(" AND ").append(Alarm.DAYS_OF_WEEK).append("=?"); 275 args.add(String.valueOf(intent.hasExtra(EXTRA_DAYS) 276 ? getDaysFromIntent(intent).getBitSet() : DaysOfWeek.NO_DAYS_SET)); 277 278 if (intent.hasExtra(EXTRA_VIBRATE)) { 279 selection.append(" AND ").append(Alarm.VIBRATE).append("=?"); 280 args.add(intent.getBooleanExtra(EXTRA_VIBRATE, false) ? "1" : "0"); 281 } 282 283 if (intent.hasExtra(EXTRA_RINGTONE)) { 284 selection.append(" AND ").append(Alarm.RINGTONE).append("=?"); 285 286 String ringTone = intent.getStringExtra(EXTRA_RINGTONE); 287 if (ringTone == null) { 288 // If the intent explicitly specified a NULL ringtone, treat it as the default 289 // ringtone. 290 ringTone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM).toString(); 291 } else if (VALUE_RINGTONE_SILENT.equals(ringTone) || ringTone.isEmpty()) { 292 ringTone = Alarm.NO_RINGTONE; 293 } 294 args.add(ringTone); 295 } 296 } 297} 298