1 /* 2 * Copyright (C) 2007 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.app.AlertDialog; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.Intent; 24 import android.content.SharedPreferences; 25 import android.content.res.Configuration; 26 import android.database.Cursor; 27 import android.graphics.Typeface; 28 import android.net.Uri; 29 import android.os.Bundle; 30 import android.os.Handler; 31 import android.view.ContextMenu; 32 import android.view.ContextMenu.ContextMenuInfo; 33 import android.view.LayoutInflater; 34 import android.view.Menu; 35 import android.view.MenuItem; 36 import android.view.View; 37 import android.view.View.OnClickListener; 38 import android.view.ViewGroup; 39 import android.widget.AdapterView; 40 import android.widget.AdapterView.AdapterContextMenuInfo; 41 import android.widget.AdapterView.OnItemClickListener; 42 import android.widget.Button; 43 import android.widget.CheckBox; 44 import android.widget.CursorAdapter; 45 import android.widget.ImageButton; 46 import android.widget.ImageView; 47 import android.widget.ListView; 48 import android.widget.TextView; 49 50 import java.util.Calendar; 51 52 /** 53 * AlarmClock application. 54 */ 55 public class AlarmClock extends Activity implements OnItemClickListener { 56 57 static final String PREFERENCES = "AlarmClock"; 58 59 /** This must be false for production. If true, turns on logging, 60 test code, etc. */ 61 static final boolean DEBUG = false; 62 63 private SharedPreferences mPrefs; 64 private LayoutInflater mFactory; 65 private ListView mAlarmsList; 66 private Cursor mCursor; 67 68 private void updateIndicatorAndAlarm(boolean enabled, ImageView bar, 69 Alarm alarm) { 70 bar.setImageResource(enabled ? R.drawable.ic_indicator_on 71 : R.drawable.ic_indicator_off); 72 Alarms.enableAlarm(this, alarm.id, enabled); 73 if (enabled) { 74 SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes, 75 alarm.daysOfWeek); 76 } 77 } 78 79 private class AlarmTimeAdapter extends CursorAdapter { 80 public AlarmTimeAdapter(Context context, Cursor cursor) { 81 super(context, cursor); 82 } 83 84 public View newView(Context context, Cursor cursor, ViewGroup parent) { 85 View ret = mFactory.inflate(R.layout.alarm_time, parent, false); 86 87 DigitalClock digitalClock = 88 (DigitalClock) ret.findViewById(R.id.digitalClock); 89 digitalClock.setLive(false); 90 return ret; 91 } 92 93 public void bindView(View view, Context context, Cursor cursor) { 94 final Alarm alarm = new Alarm(cursor); 95 96 View indicator = view.findViewById(R.id.indicator); 97 98 // Set the initial resource for the bar image. 99 final ImageView barOnOff = 100 (ImageView) indicator.findViewById(R.id.bar_onoff); 101 barOnOff.setImageResource(alarm.enabled ? 102 R.drawable.ic_indicator_on : R.drawable.ic_indicator_off); 103 104 // Set the initial state of the clock "checkbox" 105 final CheckBox clockOnOff = 106 (CheckBox) indicator.findViewById(R.id.clock_onoff); 107 clockOnOff.setChecked(alarm.enabled); 108 109 // Clicking outside the "checkbox" should also change the state. 110 indicator.setOnClickListener(new OnClickListener() { 111 public void onClick(View v) { 112 clockOnOff.toggle(); 113 updateIndicatorAndAlarm(clockOnOff.isChecked(), 114 barOnOff, alarm); 115 } 116 }); 117 118 DigitalClock digitalClock = 119 (DigitalClock) view.findViewById(R.id.digitalClock); 120 121 // set the alarm text 122 final Calendar c = Calendar.getInstance(); 123 c.set(Calendar.HOUR_OF_DAY, alarm.hour); 124 c.set(Calendar.MINUTE, alarm.minutes); 125 digitalClock.updateTime(c); 126 digitalClock.setTypeface(Typeface.DEFAULT); 127 128 // Set the repeat text or leave it blank if it does not repeat. 129 TextView daysOfWeekView = 130 (TextView) digitalClock.findViewById(R.id.daysOfWeek); 131 final String daysOfWeekStr = 132 alarm.daysOfWeek.toString(AlarmClock.this, false); 133 if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) { 134 daysOfWeekView.setText(daysOfWeekStr); 135 daysOfWeekView.setVisibility(View.VISIBLE); 136 } else { 137 daysOfWeekView.setVisibility(View.GONE); 138 } 139 140 // Display the label 141 TextView labelView = 142 (TextView) view.findViewById(R.id.label); 143 if (alarm.label != null && alarm.label.length() != 0) { 144 labelView.setText(alarm.label); 145 labelView.setVisibility(View.VISIBLE); 146 } else { 147 labelView.setVisibility(View.GONE); 148 } 149 } 150 }; 151 152 @Override 153 public boolean onContextItemSelected(final MenuItem item) { 154 final AdapterContextMenuInfo info = 155 (AdapterContextMenuInfo) item.getMenuInfo(); 156 final int id = (int) info.id; 157 switch (item.getItemId()) { 158 case R.id.delete_alarm: 159 // Confirm that the alarm will be deleted. 160 new AlertDialog.Builder(this) 161 .setTitle(getString(R.string.delete_alarm)) 162 .setMessage(getString(R.string.delete_alarm_confirm)) 163 .setPositiveButton(android.R.string.ok, 164 new DialogInterface.OnClickListener() { 165 public void onClick(DialogInterface d, 166 int w) { 167 Alarms.deleteAlarm(AlarmClock.this, id); 168 } 169 }) 170 .setNegativeButton(android.R.string.cancel, null) 171 .show(); 172 return true; 173 174 case R.id.enable_alarm: 175 final Cursor c = (Cursor) mAlarmsList.getAdapter() 176 .getItem(info.position); 177 final Alarm alarm = new Alarm(c); 178 Alarms.enableAlarm(this, alarm.id, !alarm.enabled); 179 if (!alarm.enabled) { 180 SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes, 181 alarm.daysOfWeek); 182 } 183 return true; 184 185 case R.id.edit_alarm: 186 Intent intent = new Intent(this, SetAlarm.class); 187 intent.putExtra(Alarms.ALARM_ID, id); 188 startActivity(intent); 189 return true; 190 191 default: 192 break; 193 } 194 return super.onContextItemSelected(item); 195 } 196 197 @Override 198 protected void onCreate(Bundle icicle) { 199 super.onCreate(icicle); 200 201 mFactory = LayoutInflater.from(this); 202 mPrefs = getSharedPreferences(PREFERENCES, 0); 203 mCursor = Alarms.getAlarmsCursor(getContentResolver()); 204 205 updateLayout(); 206 } 207 208 private void updateLayout() { 209 setContentView(R.layout.alarm_clock); 210 mAlarmsList = (ListView) findViewById(R.id.alarms_list); 211 AlarmTimeAdapter adapter = new AlarmTimeAdapter(this, mCursor); 212 mAlarmsList.setAdapter(adapter); 213 mAlarmsList.setVerticalScrollBarEnabled(true); 214 mAlarmsList.setOnItemClickListener(this); 215 mAlarmsList.setOnCreateContextMenuListener(this); 216 217 View addAlarm = findViewById(R.id.add_alarm); 218 addAlarm.setOnClickListener(new View.OnClickListener() { 219 public void onClick(View v) { 220 addNewAlarm(); 221 } 222 }); 223 // Make the entire view selected when focused. 224 addAlarm.setOnFocusChangeListener(new View.OnFocusChangeListener() { 225 public void onFocusChange(View v, boolean hasFocus) { 226 v.setSelected(hasFocus); 227 } 228 }); 229 230 ImageButton deskClock = 231 (ImageButton) findViewById(R.id.desk_clock_button); 232 deskClock.setOnClickListener(new View.OnClickListener() { 233 public void onClick(View v) { 234 startActivity(new Intent(AlarmClock.this, DeskClock.class)); 235 } 236 }); 237 } 238 239 private void addNewAlarm() { 240 startActivity(new Intent(this, SetAlarm.class)); 241 } 242 243 @Override 244 protected void onDestroy() { 245 super.onDestroy(); 246 ToastMaster.cancelToast(); 247 mCursor.deactivate(); 248 } 249 250 @Override 251 public void onCreateContextMenu(ContextMenu menu, View view, 252 ContextMenuInfo menuInfo) { 253 // Inflate the menu from xml. 254 getMenuInflater().inflate(R.menu.context_menu, menu); 255 256 // Use the current item to create a custom view for the header. 257 final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; 258 final Cursor c = 259 (Cursor) mAlarmsList.getAdapter().getItem((int) info.position); 260 final Alarm alarm = new Alarm(c); 261 262 // Construct the Calendar to compute the time. 263 final Calendar cal = Calendar.getInstance(); 264 cal.set(Calendar.HOUR_OF_DAY, alarm.hour); 265 cal.set(Calendar.MINUTE, alarm.minutes); 266 final String time = Alarms.formatTime(this, cal); 267 268 // Inflate the custom view and set each TextView's text. 269 final View v = mFactory.inflate(R.layout.context_menu_header, null); 270 TextView textView = (TextView) v.findViewById(R.id.header_time); 271 textView.setText(time); 272 textView = (TextView) v.findViewById(R.id.header_label); 273 textView.setText(alarm.label); 274 275 // Set the custom view on the menu. 276 menu.setHeaderView(v); 277 // Change the text based on the state of the alarm. 278 if (alarm.enabled) { 279 menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm); 280 } 281 } 282 283 @Override 284 public boolean onOptionsItemSelected(MenuItem item) { 285 switch (item.getItemId()) { 286 case R.id.menu_item_settings: 287 startActivity(new Intent(this, SettingsActivity.class)); 288 return true; 289 case R.id.menu_item_desk_clock: 290 startActivity(new Intent(this, DeskClock.class)); 291 return true; 292 case R.id.menu_item_add_alarm: 293 addNewAlarm(); 294 return true; 295 default: 296 break; 297 } 298 return super.onOptionsItemSelected(item); 299 } 300 301 @Override 302 public boolean onCreateOptionsMenu(Menu menu) { 303 getMenuInflater().inflate(R.menu.alarm_list_menu, menu); 304 return super.onCreateOptionsMenu(menu); 305 } 306 307 public void onItemClick(AdapterView parent, View v, int pos, long id) { 308 Intent intent = new Intent(this, SetAlarm.class); 309 intent.putExtra(Alarms.ALARM_ID, (int) id); 310 startActivity(intent); 311 } 312 } 313