Home | History | Annotate | Download | only in deskclock
      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 }