轉載請標明出處:http://blog.csdn.net/wdaming1986/article/details/7461043
有人問我:“當設置一個鬧鐘後,然後調系統時間超過設置的鬧鐘的時間,這時候鬧鐘響了??”
通過源碼,我發現這種情況是正常的。不是bug。可以理解。
以下是我發現的幾點鬧鐘中重要的點,分享一下:
(1)在鬧鐘中有AudioManager管理機制,這個機制可以申請和釋放OnAudioFocusChangeListener監聽。
還有mTelephonyManager對象,處理在鬧鐘響的時候,來電鈴聲的切換。
(2)廣播接收鬧鐘,通過廣播啓動AlarmKlaxon這個Service,隱式啓動service:
public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm";
- // Play the alarm alert and vibrate the device.
- Intent playAlarm = new Intent(Alarms.ALARM_ALERT_ACTION);
- playAlarm.putExtra(Alarms.ALARM_INTENT_EXTRA, alarm);
- context.startService(playAlarm);
在mainfest中,AlarmKlaxon這個服務的定義如下:
- <service android:name="AlarmKlaxon"
- android:description="@string/alarm_klaxon_service_desc"
- >
- <intent-filter>
- <action android:name="com.cn.daming.deskclock.ALARM_ALERT" />
- </intent-filter>
- </service>
這個service做的是允許別的Activity打斷正在響鈴的鈴聲,播放其他的鈴聲,例如,鬧鐘響的時候來電話了。
(3)在listview中包含checkbox,這時候鬧鐘的處理時,activity實現一個OnItemClickListener的監聽,點擊每一項的監聽。然後在checkbox單獨拿出去寫一個類,繼承LinearLayout,重寫setPressed()這個方法,以實現“當點擊checkbox的時候不觸發parent的click事件”。關鍵代碼如下:
- <span style="font-size:18px;"> @Override
- public void setPressed(boolean pressed) {
- // If the parent is pressed, do not set to pressed.
- if (pressed && ((View) getParent()).isPressed()) {
- return;
- }
- super.setPressed(pressed);
- }</span>
下面看看我的程序截圖:
紅色圈的圖標爲我的鬧鐘。 點擊“玲鬧鐘”後的界面
點擊新建鬧鐘出現的界面 設置好時間彈出的toast。
下面我把我的主要入口類的代碼貼出來:
DeskClockMainActivity.Java
- <span style="font-size:18px;">package com.cn.daming.deskclock;
- import java.util.Calendar;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.SharedPreferences;
- import android.database.Cursor;
- import android.graphics.Typeface;
- import android.os.Bundle;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.ContextMenu;
- import android.view.ContextMenu.ContextMenuInfo;
- import android.view.View.OnClickListener;
- import android.view.ViewGroup;
- import android.widget.AdapterView;
- import android.widget.AdapterView.AdapterContextMenuInfo;
- import android.widget.AdapterView.OnItemClickListener;
- import android.widget.CheckBox;
- import android.widget.CursorAdapter;
- import android.widget.ImageButton;
- import android.widget.ImageView;
- import android.widget.ListView;
- import android.widget.TextView;
- public class DeskClockMainActivity extends Activity implements OnItemClickListener{
- static final String PREFERENCES = "AlarmClock";
- /** This must be false for production. If true, turns on logging,
- test code, etc. */
- static final boolean DEBUG = false;
- private SharedPreferences mPrefs;
- private LayoutInflater mFactory;
- private ListView mAlarmsList;
- private Cursor mCursor;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //取自定義佈局的LayoutInflater
- mFactory = LayoutInflater.from(this);
- //取getSharedPreferences中key==“AlarmClock”的值
- mPrefs = getSharedPreferences(PREFERENCES, 0);
- //獲取鬧鐘的cursor
- mCursor = Alarms.getAlarmsCursor(getContentResolver());
- //更新佈局界面
- updateLayout();
- }
- //加載更新界面佈局
- private void updateLayout() {
- setContentView(R.layout.alarm_clock);
- mAlarmsList = (ListView) findViewById(R.id.alarms_list);
- AlarmTimeAdapter adapter = new AlarmTimeAdapter(this, mCursor);
- mAlarmsList.setAdapter(adapter);
- mAlarmsList.setVerticalScrollBarEnabled(true);
- mAlarmsList.setOnItemClickListener(this);
- mAlarmsList.setOnCreateContextMenuListener(this);
- View addAlarm = findViewById(R.id.add_alarm);
- addAlarm.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- addNewAlarm();
- }
- });
- // Make the entire view selected when focused.
- addAlarm.setOnFocusChangeListener(new View.OnFocusChangeListener() {
- public void onFocusChange(View v, boolean hasFocus) {
- v.setSelected(hasFocus);
- }
- });
- ImageButton deskClock =
- (ImageButton) findViewById(R.id.desk_clock_button);
- deskClock.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- }
- });
- }
- private void addNewAlarm() {
- startActivity(new Intent(this, SetAlarm.class));
- }
- /**
- * listview的適配器繼承CursorAdapter
- * @author wangxianming
- * 也可以使用BaseAdapter
- */
- private class AlarmTimeAdapter extends CursorAdapter {
- public AlarmTimeAdapter(Context context, Cursor cursor) {
- super(context, cursor);
- }
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- View ret = mFactory.inflate(R.layout.alarm_time, parent, false);
- DigitalClock digitalClock =
- (DigitalClock) ret.findViewById(R.id.digitalClock);
- digitalClock.setLive(false);
- return ret;
- }
- //把view綁定cursor的每一項
- public void bindView(View view, Context context, Cursor cursor) {
- final Alarm alarm = new Alarm(cursor);
- View indicator = view.findViewById(R.id.indicator);
- // Set the initial resource for the bar image.
- final ImageView barOnOff =
- (ImageView) indicator.findViewById(R.id.bar_onoff);
- barOnOff.setImageResource(alarm.enabled ?
- R.drawable.ic_indicator_on : R.drawable.ic_indicator_off);
- // Set the initial state of the clock "checkbox"
- final CheckBox clockOnOff =
- (CheckBox) indicator.findViewById(R.id.clock_onoff);
- clockOnOff.setChecked(alarm.enabled);
- // Clicking outside the "checkbox" should also change the state.
- //對checkbox設置監聽,使裏外一致
- indicator.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- clockOnOff.toggle();
- updateIndicatorAndAlarm(clockOnOff.isChecked(),
- barOnOff, alarm);
- }
- });
- DigitalClock digitalClock =
- (DigitalClock) view.findViewById(R.id.digitalClock);
- // set the alarm text
- final Calendar c = Calendar.getInstance();
- c.set(Calendar.HOUR_OF_DAY, alarm.hour);
- c.set(Calendar.MINUTE, alarm.minutes);
- digitalClock.updateTime(c);
- digitalClock.setTypeface(Typeface.DEFAULT);
- // Set the repeat text or leave it blank if it does not repeat.
- TextView daysOfWeekView =
- (TextView) digitalClock.findViewById(R.id.daysOfWeek);
- final String daysOfWeekStr =
- alarm.daysOfWeek.toString(DeskClockMainActivity.this, false);
- if (daysOfWeekStr != null && daysOfWeekStr.length() != 0) {
- daysOfWeekView.setText(daysOfWeekStr);
- daysOfWeekView.setVisibility(View.VISIBLE);
- } else {
- daysOfWeekView.setVisibility(View.GONE);
- }
- // Display the label
- TextView labelView =
- (TextView) view.findViewById(R.id.label);
- if (alarm.label != null && alarm.label.length() != 0) {
- labelView.setText(alarm.label);
- labelView.setVisibility(View.VISIBLE);
- } else {
- labelView.setVisibility(View.GONE);
- }
- }
- };
- //更新checkbox
- private void updateIndicatorAndAlarm(boolean enabled, ImageView bar,
- Alarm alarm) {
- bar.setImageResource(enabled ? R.drawable.ic_indicator_on
- : R.drawable.ic_indicator_off);
- Alarms.enableAlarm(this, alarm.id, enabled);
- if (enabled) {
- SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
- alarm.daysOfWeek);
- }
- }
- /*
- * (non-Javadoc)
- * @see android.app.Activity#onContextItemSelected(android.view.MenuItem)
- * 創建上下文菜單
- */
- @Override
- public boolean onContextItemSelected(final MenuItem item) {
- final AdapterContextMenuInfo info =
- (AdapterContextMenuInfo) item.getMenuInfo();
- final int id = (int) info.id;
- // Error check just in case.
- if (id == -1) {
- return super.onContextItemSelected(item);
- }
- switch (item.getItemId()) {
- case R.id.delete_alarm:
- // Confirm that the alarm will be deleted.
- new AlertDialog.Builder(this)
- .setTitle(getString(R.string.delete_alarm))
- .setMessage(getString(R.string.delete_alarm_confirm))
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface d,
- int w) {
- Alarms.deleteAlarm(DeskClockMainActivity.this, id);
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .show();
- return true;
- case R.id.enable_alarm:
- final Cursor c = (Cursor) mAlarmsList.getAdapter()
- .getItem(info.position);
- final Alarm alarm = new Alarm(c);
- Alarms.enableAlarm(this, alarm.id, !alarm.enabled);
- if (!alarm.enabled) {
- SetAlarm.popAlarmSetToast(this, alarm.hour, alarm.minutes,
- alarm.daysOfWeek);
- }
- return true;
- case R.id.edit_alarm:
- Intent intent = new Intent(this, SetAlarm.class);
- intent.putExtra(Alarms.ALARM_ID, id);
- startActivity(intent);
- return true;
- default:
- break;
- }
- return super.onContextItemSelected(item);
- }
- /*
- * (non-Javadoc)
- * @see android.app.Activity#onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo)
- * 創建菜單
- */
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view,
- ContextMenuInfo menuInfo) {
- // Inflate the menu from xml.
- getMenuInflater().inflate(R.menu.context_menu, menu);
- // Use the current item to create a custom view for the header.
- final AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- final Cursor c =
- (Cursor) mAlarmsList.getAdapter().getItem((int) info.position);
- final Alarm alarm = new Alarm(c);
- // Construct the Calendar to compute the time.
- final Calendar cal = Calendar.getInstance();
- cal.set(Calendar.HOUR_OF_DAY, alarm.hour);
- cal.set(Calendar.MINUTE, alarm.minutes);
- final String time = Alarms.formatTime(this, cal);
- // Inflate the custom view and set each TextView's text.
- final View v = mFactory.inflate(R.layout.context_menu_header, null);
- TextView textView = (TextView) v.findViewById(R.id.header_time);
- textView.setText(time);
- textView = (TextView) v.findViewById(R.id.header_label);
- textView.setText(alarm.label);
- // Set the custom view on the menu.
- menu.setHeaderView(v);
- // Change the text based on the state of the alarm.
- if (alarm.enabled) {
- menu.findItem(R.id.enable_alarm).setTitle(R.string.disable_alarm);
- }
- }
- /*
- * (non-Javadoc)
- * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
- * 設置菜單的點擊事件的處理
- */
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.menu_item_settings:
- startActivity(new Intent(this, SettingsActivity.class));
- return true;
- case R.id.menu_item_desk_clock:
- //modify by wangxianming in 2012-4-14
- // startActivity(new Intent(this, DeskClock.class));
- return true;
- case R.id.menu_item_add_alarm:
- addNewAlarm();
- return true;
- default:
- break;
- }
- return super.onOptionsItemSelected(item);
- }
- /*
- * (non-Javadoc)
- * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
- * 創建菜單
- */
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.alarm_list_menu, menu);
- return super.onCreateOptionsMenu(menu);
- }
- /*
- * (non-Javadoc)
- * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, android.view.View, int, long)
- * 創建菜單的點擊事件響應
- */
- public void onItemClick(AdapterView<?> adapterView, View v, int pos, long id) {
- Intent intent = new Intent(this, SetAlarm.class);
- intent.putExtra(Alarms.ALARM_ID, (int) id);
- startActivity(intent);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- ToastMaster.cancelToast();
- mCursor.close();
- }
- }</span>