1 /* 2 * Copyright (C) 2015 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 17 package com.android.deskclock; 18 19 import android.app.Activity; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.os.Bundle; 23 24 import com.android.deskclock.data.City; 25 import com.android.deskclock.data.DataModel; 26 import com.android.deskclock.data.Timer; 27 import com.android.deskclock.events.Events; 28 import com.android.deskclock.worldclock.CitySelectionActivity; 29 30 import java.util.List; 31 import java.util.Set; 32 33 public class HandleDeskClockApiCalls extends Activity { 34 private Context mAppContext; 35 36 private static final String ACTION_PREFIX = "com.android.deskclock.action."; 37 38 // shows the tab with world clocks 39 public static final String ACTION_SHOW_CLOCK = ACTION_PREFIX + "SHOW_CLOCK"; 40 // extra for ACTION_SHOW_CLOCK indicating the clock is being displayed from tapping the widget 41 public static final String EXTRA_FROM_WIDGET = "com.android.deskclock.extra.clock.FROM_WIDGET"; 42 // add a clock of a selected city, if no city is specified opens the city selection screen 43 public static final String ACTION_ADD_CLOCK = ACTION_PREFIX + "ADD_CLOCK"; 44 // delete a clock of a selected city, if no city is specified shows CitiesActivity for the user 45 // to choose a city 46 public static final String ACTION_DELETE_CLOCK = ACTION_PREFIX + "DELETE_CLOCK"; 47 // extra for ACTION_ADD_CLOCK and ACTION_DELETE_CLOCK 48 public static final String EXTRA_CITY = "com.android.deskclock.extra.clock.CITY"; 49 50 // shows the tab with the stopwatch 51 public static final String ACTION_SHOW_STOPWATCH = ACTION_PREFIX + "SHOW_STOPWATCH"; 52 // starts the current stopwatch 53 public static final String ACTION_START_STOPWATCH = ACTION_PREFIX + "START_STOPWATCH"; 54 // pauses the current stopwatch that's currently running 55 public static final String ACTION_PAUSE_STOPWATCH = ACTION_PREFIX + "PAUSE_STOPWATCH"; 56 // laps the stopwatch that's currently running 57 public static final String ACTION_LAP_STOPWATCH = ACTION_PREFIX + "LAP_STOPWATCH"; 58 // resets the stopwatch if it's stopped 59 public static final String ACTION_RESET_STOPWATCH = ACTION_PREFIX + "RESET_STOPWATCH"; 60 61 // shows the tab with timers; optionally scrolls to a specific timer 62 public static final String ACTION_SHOW_TIMERS = ACTION_PREFIX + "SHOW_TIMERS"; 63 // pauses running timers; resets expired timers 64 public static final String ACTION_PAUSE_TIMER = ACTION_PREFIX + "PAUSE_TIMER"; 65 // starts the sole timer 66 public static final String ACTION_START_TIMER = ACTION_PREFIX + "START_TIMER"; 67 // resets the timer 68 public static final String ACTION_RESET_TIMER = ACTION_PREFIX + "RESET_TIMER"; 69 // adds an extra minute to the timer 70 public static final String ACTION_ADD_MINUTE_TIMER = ACTION_PREFIX + "ADD_MINUTE_TIMER"; 71 72 // extra for many actions specific to a given timer 73 public static final String EXTRA_TIMER_ID = 74 "com.android.deskclock.extra.TIMER_ID"; 75 76 // Describes the entity responsible for the action being performed. 77 public static final String EXTRA_EVENT_LABEL = "com.android.deskclock.extra.EVENT_LABEL"; 78 79 @Override 80 protected void onCreate(Bundle icicle) { 81 try { 82 super.onCreate(icicle); 83 mAppContext = getApplicationContext(); 84 85 final Intent intent = getIntent(); 86 if (intent == null) { 87 return; 88 } 89 90 final String action = intent.getAction(); 91 LogUtils.i("HandleDeskClockApiCalls " + action); 92 93 switch (action) { 94 case ACTION_START_STOPWATCH: 95 case ACTION_PAUSE_STOPWATCH: 96 case ACTION_LAP_STOPWATCH: 97 case ACTION_SHOW_STOPWATCH: 98 case ACTION_RESET_STOPWATCH: 99 handleStopwatchIntent(intent); 100 break; 101 case ACTION_SHOW_TIMERS: 102 case ACTION_RESET_TIMER: 103 case ACTION_PAUSE_TIMER: 104 case ACTION_START_TIMER: 105 handleTimerIntent(intent); 106 break; 107 case ACTION_SHOW_CLOCK: 108 case ACTION_ADD_CLOCK: 109 case ACTION_DELETE_CLOCK: 110 handleClockIntent(intent); 111 break; 112 } 113 } finally { 114 finish(); 115 } 116 } 117 118 private void handleStopwatchIntent(Intent intent) { 119 final String action = intent.getAction(); 120 121 // Determine where this intent originated. 122 final int eventLabel = intent.getIntExtra(EXTRA_EVENT_LABEL, R.string.label_intent); 123 124 if (ACTION_SHOW_STOPWATCH.equals(action)) { 125 Events.sendStopwatchEvent(R.string.action_show, eventLabel); 126 } else { 127 final String reason; 128 boolean fail = false; 129 switch (action) { 130 case ACTION_START_STOPWATCH: { 131 DataModel.getDataModel().startStopwatch(); 132 Events.sendStopwatchEvent(R.string.action_start, eventLabel); 133 reason = getString(R.string.stopwatch_started); 134 break; 135 } 136 case ACTION_PAUSE_STOPWATCH: { 137 DataModel.getDataModel().pauseStopwatch(); 138 Events.sendStopwatchEvent(R.string.action_pause, eventLabel); 139 reason = getString(R.string.stopwatch_paused); 140 break; 141 } 142 case ACTION_RESET_STOPWATCH: { 143 DataModel.getDataModel().clearLaps(); 144 DataModel.getDataModel().resetStopwatch(); 145 Events.sendStopwatchEvent(R.string.action_reset, eventLabel); 146 reason = getString(R.string.stopwatch_reset); 147 break; 148 } 149 case ACTION_LAP_STOPWATCH: { 150 if (!DataModel.getDataModel().getStopwatch().isRunning()) { 151 fail = true; 152 reason = getString(R.string.stopwatch_isnt_running); 153 } else { 154 DataModel.getDataModel().addLap(); 155 Events.sendStopwatchEvent(R.string.action_lap, eventLabel); 156 reason = getString(R.string.stopwatch_lapped); 157 } 158 break; 159 } 160 default: 161 throw new IllegalArgumentException("unknown stopwatch action: " + action); 162 } 163 164 if (fail) { 165 Voice.notifyFailure(this, reason); 166 } else { 167 Voice.notifySuccess(this, reason); 168 } 169 LogUtils.i(reason); 170 } 171 172 // Open the UI to the stopwatch. 173 final Intent stopwatchIntent = new Intent(mAppContext, DeskClock.class) 174 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.STOPWATCH_TAB_INDEX); 175 startActivity(stopwatchIntent); 176 } 177 178 private void handleTimerIntent(Intent intent) { 179 final String action = intent.getAction(); 180 181 // Determine where this intent originated. 182 final int eventLabel = intent.getIntExtra(EXTRA_EVENT_LABEL, R.string.label_intent); 183 int timerId = intent.getIntExtra(EXTRA_TIMER_ID, -1); 184 Timer timer = null; 185 186 if (ACTION_SHOW_TIMERS.equals(action)) { 187 Events.sendTimerEvent(R.string.action_show, eventLabel); 188 } else { 189 String reason = null; 190 if (timerId == -1) { 191 // No timer id was given explicitly, so check if only one timer exists. 192 final List<Timer> timers = DataModel.getDataModel().getTimers(); 193 if (timers.isEmpty()) { 194 // No timers exist to control. 195 reason = getString(R.string.no_timers_exist); 196 } else if (timers.size() > 1) { 197 // Many timers exist so the control command is ambiguous. 198 reason = getString(R.string.too_many_timers_exist); 199 } else { 200 timer = timers.get(0); 201 } 202 } else { 203 // Verify that the given timer does exist. 204 timer = DataModel.getDataModel().getTimer(timerId); 205 if (timer == null) { 206 reason = getString(R.string.timer_does_not_exist); 207 } 208 } 209 210 if (timer == null) { 211 Voice.notifyFailure(this, reason); 212 } else { 213 timerId = timer.getId(); 214 215 // Otherwise the control command can be honored. 216 switch (action) { 217 case ACTION_RESET_TIMER: { 218 DataModel.getDataModel().resetOrDeleteTimer(timer, eventLabel); 219 if (timer.isExpired() && timer.getDeleteAfterUse()) { 220 timerId = -1; 221 reason = getString(R.string.timer_deleted); 222 } else { 223 reason = getString(R.string.timer_was_reset); 224 } 225 break; 226 } 227 case ACTION_START_TIMER: { 228 DataModel.getDataModel().startTimer(timer); 229 Events.sendTimerEvent(R.string.action_start, eventLabel); 230 reason = getString(R.string.timer_started); 231 break; 232 } 233 case ACTION_PAUSE_TIMER: { 234 DataModel.getDataModel().pauseTimer(timer); 235 Events.sendTimerEvent(R.string.action_pause, eventLabel); 236 reason = getString(R.string.timer_paused); 237 break; 238 } 239 default: 240 throw new IllegalArgumentException("unknown timer action: " + action); 241 } 242 243 Voice.notifySuccess(this, reason); 244 } 245 246 LogUtils.i(reason); 247 } 248 249 // Open the UI to the timers. 250 final Intent showTimers = new Intent(mAppContext, DeskClock.class) 251 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.TIMER_TAB_INDEX); 252 if (timerId != -1) { 253 showTimers.putExtra(EXTRA_TIMER_ID, timerId); 254 } 255 startActivity(showTimers); 256 } 257 258 private void handleClockIntent(Intent intent) { 259 final String action = intent.getAction(); 260 261 if (ACTION_SHOW_CLOCK.equals(action)) { 262 final boolean fromWidget = intent.getBooleanExtra(EXTRA_FROM_WIDGET, false); 263 final int label = fromWidget ? R.string.label_widget : R.string.label_intent; 264 Events.sendClockEvent(R.string.action_show, label); 265 } else { 266 final String cityName = intent.getStringExtra(EXTRA_CITY); 267 268 final String reason; 269 boolean fail = false; 270 271 // If no city was given, start the city chooser. 272 if (cityName == null) { 273 reason = getString(R.string.no_city_selected); 274 LogUtils.i(reason); 275 Voice.notifySuccess(this, reason); 276 startActivity(new Intent(this, CitySelectionActivity.class) 277 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 278 switch (action) { 279 case ACTION_ADD_CLOCK: 280 Events.sendClockEvent(R.string.action_add, R.string.label_intent); 281 break; 282 case ACTION_DELETE_CLOCK: 283 Events.sendClockEvent(R.string.action_delete, R.string.label_intent); 284 break; 285 } 286 return; 287 } 288 289 // If a city was given, ensure it can be located. 290 final City city = DataModel.getDataModel().getCity(cityName); 291 if (city == null) { 292 reason = getString(R.string.the_city_you_specified_is_not_available); 293 LogUtils.i(reason); 294 Voice.notifyFailure(this, reason); 295 switch (action) { 296 case ACTION_ADD_CLOCK: 297 Events.sendClockEvent(R.string.action_add, R.string.label_intent); 298 break; 299 case ACTION_DELETE_CLOCK: 300 Events.sendClockEvent(R.string.action_delete, R.string.label_intent); 301 break; 302 } 303 return; 304 } 305 306 final Set<City> selectedCities = 307 Utils.newArraySet(DataModel.getDataModel().getSelectedCities()); 308 309 switch (action) { 310 case ACTION_ADD_CLOCK: { 311 // Fail if the city is already present. 312 if (!selectedCities.add(city)) { 313 fail = true; 314 reason = getString(R.string.the_city_already_added); 315 break; 316 } 317 318 // Otherwise report the success. 319 DataModel.getDataModel().setSelectedCities(selectedCities); 320 reason = getString(R.string.city_added, city.getName()); 321 Events.sendClockEvent(R.string.action_add, R.string.label_intent); 322 break; 323 } 324 case ACTION_DELETE_CLOCK: { 325 // Fail if the city is not present. 326 if (!selectedCities.remove(city)) { 327 fail = true; 328 reason = getString(R.string.the_city_you_specified_is_not_available); 329 break; 330 } 331 332 // Otherwise report the success. 333 DataModel.getDataModel().setSelectedCities(selectedCities); 334 reason = getString(R.string.city_deleted, city.getName()); 335 Events.sendClockEvent(R.string.action_delete, R.string.label_intent); 336 break; 337 } 338 default: 339 throw new IllegalArgumentException("unknown clock action: " + action); 340 } 341 342 if (fail) { 343 Voice.notifyFailure(this, reason); 344 } else { 345 Voice.notifySuccess(this, reason); 346 } 347 LogUtils.i(reason); 348 } 349 350 // Opens the UI for clocks 351 final Intent clockIntent = new Intent(mAppContext, DeskClock.class) 352 .setAction(action) 353 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 354 .putExtra(DeskClock.SELECT_TAB_INTENT_EXTRA, DeskClock.CLOCK_TAB_INDEX); 355 startActivity(clockIntent); 356 } 357 }