1 /*
2  * Copyright (C) 2014 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.example.android.wearable.timer;
18 
19 import android.app.Activity;
20 import android.app.AlarmManager;
21 import android.app.Notification;
22 import android.app.NotificationManager;
23 import android.app.PendingIntent;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.res.Resources;
27 import android.os.Bundle;
28 import android.provider.AlarmClock;
29 import android.support.wearable.view.WearableListView;
30 import android.util.Log;
31 import android.view.LayoutInflater;
32 import android.view.ViewGroup;
33 import android.widget.TextView;
34 
35 import com.example.android.wearable.timer.util.Constants;
36 import com.example.android.wearable.timer.util.TimerFormat;
37 
38 /** This class sets a timer. */
39 public class SetTimerActivity extends Activity implements WearableListView.ClickListener {
40 
41     public static final int NUMBER_OF_TIMES = 10;
42     public static final String TAG = "SetTimerActivity";
43 
44     private ListViewItem[] mTimeOptions = new ListViewItem[NUMBER_OF_TIMES];
45     private WearableListView mWearableListView;
46 
47 
48     @Override
onCreate(Bundle savedInstanceState)49     public void onCreate(Bundle savedInstanceState) {
50         super.onCreate(savedInstanceState);
51 
52         int paramLength = getIntent().getIntExtra(AlarmClock.EXTRA_LENGTH, 0);
53         if (Log.isLoggable(TAG, Log.DEBUG)) {
54             Log.d(TAG, "SetTimerActivity:onCreate=" + paramLength);
55         }
56         if (paramLength > 0 && paramLength <= 86400) {
57             long durationMillis = paramLength * 1000;
58             setupTimer(durationMillis);
59             finish();
60             return;
61         }
62 
63         Resources res = getResources();
64         for (int i = 0; i < NUMBER_OF_TIMES; i++) {
65             mTimeOptions[i] = new ListViewItem(
66                     res.getQuantityString(R.plurals.timer_minutes, i + 1, i + 1),
67                     (i + 1) * 60 * 1000);
68         }
69 
70         setContentView(R.layout.timer_set_timer);
71 
72         // Initialize a simple list of countdown time options.
73         mWearableListView = (WearableListView) findViewById(R.id.times_list_view);
74         mWearableListView.setAdapter(new TimerWearableListViewAdapter(this));
75         mWearableListView.setClickListener(this);
76     }
77 
78     /**
79      * Sets up an alarm (and an associated notification) to go off after <code>duration</code>
80      * milliseconds.
81      */
setupTimer(long duration)82     private void setupTimer(long duration) {
83         NotificationManager notifyMgr =
84                 ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
85 
86         // Delete dataItem and cancel a potential old countdown.
87         cancelCountdown(notifyMgr);
88 
89         // Build notification and set it.
90         notifyMgr.notify(Constants.NOTIFICATION_TIMER_COUNTDOWN, buildNotification(duration));
91 
92         // Register with the alarm manager to display a notification when the timer is done.
93         registerWithAlarmManager(duration);
94 
95         finish();
96     }
97 
98     @Override
onClick(WearableListView.ViewHolder holder)99     public void onClick(WearableListView.ViewHolder holder) {
100         long duration = mTimeOptions[holder.getPosition()].duration;
101         setupTimer(duration);
102     }
103 
104     @Override
onTopEmptyRegionClick()105     public void onTopEmptyRegionClick() {
106     }
107 
registerWithAlarmManager(long duration)108     private void registerWithAlarmManager(long duration) {
109         // Get the alarm manager.
110         AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
111 
112         // Create intent that gets fired when timer expires.
113         Intent intent = new Intent(Constants.ACTION_SHOW_ALARM, null, this,
114                 TimerNotificationService.class);
115         PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent,
116                 PendingIntent.FLAG_UPDATE_CURRENT);
117 
118         // Calculate the time when it expires.
119         long wakeupTime = System.currentTimeMillis() + duration;
120 
121         // Schedule an alarm.
122         alarm.setExact(AlarmManager.RTC_WAKEUP, wakeupTime, pendingIntent);
123     }
124 
125     /**
126      * Build a notification including different actions and other various setup and return it.
127      *
128      * @param duration the duration of the timer.
129      * @return the notification to display.
130      */
131 
buildNotification(long duration)132     private Notification buildNotification(long duration) {
133         // Intent to restart a timer.
134         Intent restartIntent = new Intent(Constants.ACTION_RESTART_ALARM, null, this,
135                 TimerNotificationService.class);
136         PendingIntent pendingIntentRestart = PendingIntent
137                 .getService(this, 0, restartIntent, PendingIntent.FLAG_UPDATE_CURRENT);
138 
139         // Intent to delete a timer.
140         Intent deleteIntent = new Intent(Constants.ACTION_DELETE_ALARM, null, this,
141                 TimerNotificationService.class);
142         PendingIntent pendingIntentDelete = PendingIntent
143                 .getService(this, 0, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT);
144 
145         // Create countdown notification using a chronometer style.
146         return new Notification.Builder(this)
147                 .setSmallIcon(R.drawable.ic_cc_alarm)
148                 .setContentTitle(getString(R.string.timer_time_left))
149                 .setContentText(TimerFormat.getTimeString(duration))
150                 .setUsesChronometer(true)
151                 .setWhen(System.currentTimeMillis() + duration)
152                 .addAction(R.drawable.ic_cc_alarm, getString(R.string.timer_restart),
153                         pendingIntentRestart)
154                 .addAction(R.drawable.ic_cc_alarm, getString(R.string.timer_delete),
155                         pendingIntentDelete)
156                 .setDeleteIntent(pendingIntentDelete)
157                 .setLocalOnly(true)
158                 .build();
159     }
160 
161     /**
162      * Cancels an old countdown and deletes the dataItem.
163      *
164      * @param notifyMgr the notification manager.
165      */
cancelCountdown(NotificationManager notifyMgr)166     private void cancelCountdown(NotificationManager notifyMgr) {
167         notifyMgr.cancel(Constants.NOTIFICATION_TIMER_EXPIRED);
168     }
169 
170     /** Model class for the listview. */
171     private static class ListViewItem {
172 
173         // Duration in milliseconds.
174         long duration;
175         // Label to display.
176         private String label;
177 
ListViewItem(String label, long duration)178         public ListViewItem(String label, long duration) {
179             this.label = label;
180             this.duration = duration;
181         }
182 
183         @Override
toString()184         public String toString() {
185             return label;
186         }
187     }
188 
189     private final class TimerWearableListViewAdapter extends WearableListView.Adapter {
190         private final Context mContext;
191         private final LayoutInflater mInflater;
192 
TimerWearableListViewAdapter(Context context)193         private TimerWearableListViewAdapter(Context context) {
194             mContext = context;
195             mInflater = LayoutInflater.from(context);
196         }
197 
198         @Override
onCreateViewHolder(ViewGroup parent, int viewType)199         public WearableListView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
200             return new WearableListView.ViewHolder(
201                     mInflater.inflate(R.layout.timer_list_item, null));
202         }
203 
204         @Override
onBindViewHolder(WearableListView.ViewHolder holder, int position)205         public void onBindViewHolder(WearableListView.ViewHolder holder, int position) {
206             TextView view = (TextView) holder.itemView.findViewById(R.id.time_text);
207             view.setText(mTimeOptions[position].label);
208             holder.itemView.setTag(position);
209         }
210 
211         @Override
getItemCount()212         public int getItemCount() {
213             return NUMBER_OF_TIMES;
214         }
215     }
216 
217 }
218