package net.micode.notes.data;

import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.telephony.PhoneNumberUtils;
import android.util.Log;

import java.util.HashMap;

public class Contact {
    private static HashMap<String, String> sContactCache;
//用于构建查询联系人的条件语句
    private static final String TAG = "Contact";

    private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
    + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
    + " AND " + Data.RAW_CONTACT_ID + " IN "
            + "(SELECT raw_contact_id "
            + " FROM phone_lookup"
            + " WHERE min_match = '+')";

    public static String getContact(Context context, String phoneNumber) {
        if(sContactCache == null) {
            sContactCache = new HashMap<String, String>();
        }

        if(sContactCache.containsKey(phoneNumber)) {
            return sContactCache.get(phoneNumber);
        }
//这个条件语句使用了Android提供的一些常量和函数，用于查询电话号码相等且数据类型为电话的联系人信息。

        String selection = CALLER_ID_SELECTION.replace("+",
                PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
//方法将电话号码中的"+"替换为最小匹配的呼叫者ID。
        Cursor cursor = context.getContentResolver().query(
                Data.CONTENT_URI,
//查询联系人数据。
                new String [] { Phone.DISPLAY_NAME },
                selection,
                new String[] { phoneNumber },
                null);
//表示查询条件，即根据电话号码进行匹配。
        if (cursor != null && cursor.moveToFirst()) {
            try {
                String name = cursor.getString(0);
                sContactCache.put(phoneNumber, name);
                return name;
            } catch (IndexOutOfBoundsException e) {
                Log.e(TAG, " Cursor get string error " + e.toString());
                return null;
            } finally {
                cursor.close();
            }
        } else {
            Log.d(TAG, "No contact matched with number:" + phoneNumber);
//表示查询条件中的参数，即要匹配的电话号码。
            return null;
        }
    }
}

```java
package net.micode.notes.data;

import android.net.Uri;

/**
 * 此类表示与笔记相关的常量和数据结构。
 */
public class Notes {

    // 内容提供程序的权限
    public static final String AUTHORITY = "micode_notes";

    // 用于记录日志的标签
    public static final String TAG = "Notes";

    // 表示不同类型笔记的常量
    public static final int TYPE_NOTE     = 0;
    public static final int TYPE_FOLDER   = 1;
    public static final int TYPE_SYSTEM   = 2;

    /**
     * 以下是系统文件夹的标识符：
     * {@link Notes#ID_ROOT_FOLDER} 是默认文件夹
     * {@link Notes#ID_TEMPARAY_FOLDER} 用于不属于任何文件夹的笔记
     * {@link Notes#ID_CALL_RECORD_FOLDER} 用于存储通话记录
     * {@link Notes#ID_TRASH_FOLDER} 用于垃圾文件夹
     */
    public static final int ID_ROOT_FOLDER = 0;
    public static final int ID_TEMPARAY_FOLDER = -1;
    public static final int ID_CALL_RECORD_FOLDER = -2;
    public static final int ID_TRASH_FOLDER = -3;

    // Intent额外键
    public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";
    public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";
    public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
    public static final String INTENT_EXTRA_WIDGET_TYPE = "net.micode.notes.widget_type";
    public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
    public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";

    // 表示不同类型小部件的常量
    public static final int TYPE_WIDGET_INVALID = -1;
    public static final int TYPE_WIDGET_2X = 0;
    public static final int TYPE_WIDGET_4X = 1;

    /**
     * 包含数据类型常量的内部类。
     */
    public static class DataConstants {
        // 不同笔记类型的内容项类型
        public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
        public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
    }
}
```java
/**
 * 用于查询所有笔记和文件夹的 Uri
 */
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");

/**
 * 用于查询数据的 Uri
 */
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");

public interface NoteColumns {
    /**
     * 行的唯一 ID
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String ID = "_id";

    /**
     * 笔记或文件夹的父级 ID
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String PARENT_ID = "parent_id";

    /**
     * 笔记或文件夹的创建日期
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String CREATED_DATE = "created_date";

    /**
     * 最新修改日期
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String MODIFIED_DATE = "modified_date";


    /**
     * 提醒日期
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String ALERTED_DATE = "alert_date";

    /**
     * 文件夹名称或笔记的文本内容
     * <P> 类型: TEXT </P>
     */
    public static final String SNIPPET = "snippet";

    /**
     * 笔记的小部件 ID
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String WIDGET_ID = "widget_id";

    /**
     * 笔记的小部件类型
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String WIDGET_TYPE = "widget_type";

    /**
     * 笔记的背景颜色 ID
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String BG_COLOR_ID = "bg_color_id";

    /**
     * 对于文本笔记，它没有附件，对于多媒体笔记，它至少有一个附件
     * <P> 类型: INTEGER </P>
     */
    public static final String HAS_ATTACHMENT = "has_attachment";

    /**
     * 文件夹中笔记的计数
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String NOTES_COUNT = "notes_count";
}

```java
/**
 * 用于表示文本笔记的静态内部类
 */
public static final class TextNote implements DataColumns {
    /**
     * 指示文本是否处于待办事项模式的模式
     * <P> 类型: Integer 1: 待办事项模式 0: 正常模式 </P>
     */
    public static final String MODE = DATA1;

    public static final int MODE_CHECK_LIST = 1;

    /**
     * 内容类型为文本笔记的目录类型
     */
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";

    /**
     * 内容项类型为文本笔记的项目类型
     */
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note";

    /**
     * 用于查询文本笔记的 Uri
     */
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
}

/**
 * 用于表示通话记录的静态内部类
 */
public static final class CallNote implements DataColumns {
    /**
     * 此记录的通话日期
     * <P> 类型: INTEGER (long) </P>
     */
    public static final String CALL_DATE = DATA1;

    /**
     * 此记录的电话号码
     * <P> 类型: TEXT </P>
     */
    public static final String PHONE_NUMBER = DATA3;

    /**
     * 内容类型为通话记录的目录类型
     */
    public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";

    /**
     * 内容项类型为通话记录的项目类型
     */
    public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note";

    /**
     * 用于查询通话记录的 Uri
     */
    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
}
```


package net.micode.notes.ui;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Dialoginterface.OnClickListener;
import android.content.DialogInterface.OnDismissListener;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri; import android.os.Bundle;
import android.os.PowerManager;
import android.provider.Settings;
import android.view.Window;
import android.view.WindowManager;
import net.micode.notes.R:
import net.micode.notes.data.Notes;
import net.micode.notes.tool.DataUtils;
import java.io.IOException;

public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { 
	private long mNoteld;
	//文本在数据库存储中的ID号 
	private String mSnippet;
	//闹钟提示时出现的文本片段 
	private static final intSNIPPET_PREW_MAX_LEN=60;

MediaPlayer mPlayer;

@Override
protected vold onCreate(Bundle savedInstanceState) { 
	super.onCreate(savedInstanceState);
//Bundle类型的数据与Map类型的数据相似，都是以key-value的形式存储数据的
//onsavelnstanceState方法是用来保存Activity的状态的
//能从 onCreate的参数savedInsanceState中获得状态数据 
requestWindowFeature(Window.FEATURE_NO_TITLE);
//界面显示一-无标题
final Window win=getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG SHOW_WHEN LOCKED);
if (lisScreenOn()){
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
//保持窗体点亮
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
//将窗体点亮
|WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//允许窗体点亮时锁屏
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);]
//在手机锁屏后如果到了闹钟提示时间，点亮屏幕
Intent intent =getIntent();
try{
mNoteld=Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet =DataUtils.getSnippetByld(this.getContentResolver(), mNoteld);
//根据ID从数据库中获取标签的内容:
//getContentResolver()是实现数据共享，实例存储。
mSnippet = mSnippet.length() >SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN)+getResources().getString(R.string.notelist_string_info):mSnippet;
//判断标签片段是否达到符合长度} catch (IllegalArgumentException e){ e.printStackTrace(); return;

try
// 代码区

catch(Exception e)
//异常处理
代码区如果有错误，就会返回所写异常的处理。*/ mPlayer = new MediaPlayer();
if (DataUtils,visibleInNoteDatabase(getContentResolver(), mNoteld, Notes.TYPE_NOTE)) { showActionDialog();
试访	试读	
//弹出对话框 playAlarmSound();//闹钟提示音激发}else{ finish();
//完成闹钟动作

private boolean isScreenOn(){
//判断屏幕是否锁屏，调用系统函数判断
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); return pm.isScreenOn();

private vold playAlarmSound() {//闹钟提示音激发
Uri	url	RingtoneManager.getActualDefaultRingtoneUri(this,	
RingtoneManager.TYPE_ALARM);
//调用系统的铃声管理URI，得到闹钟提示音
int silentModeStreams =Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED,0);
if ((silentModeStreams & (1<<AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
}else{
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try{
mPlayer.setDataSource(this, url);
//方法:setDataSource(Context context, Uri uri)
//解释:无返回值，设置多媒体数据来源[根据Uni]
mPlayer.prepare();
//准备同步
mPlayer.setLooping(true);
//设置是否循环播放

mPlayer.start();
//开始播放
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block e.printStackTrace();
//e.printStackTrace()函数功能是抛出异常，还将显示出更深的调用信息
//System.out.printin(e)，这个方法打印出异常，并且输出在哪里出现的异常
}catch (SecurityException e) {
// TODO Auto-generated catch block 
e.printStackTrace();
} catch (IllegalStateException e)
{
// TODO Auto-generated catch block e.printStackTrace();} catch (I0Exception e)
 {
// TODO Auto-generated catch block e.printStackTrace();

private void showActionDialog(){
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
//AlertDialog的构造方法全部是Protected的
//所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。
//要创建一个AlertDialog，就要用到AlertDialog.Builder中的create()方法

//为对话框设置标题
dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮 if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);}
//对话框添加"No"按钮
dialog.show().setOnDismissListener(this);

public void onClick(Dialoginterface dialog, int which) { 
switch (which) {
//用which 来选择click后下一步的操作 case DialogInterface.BUTTON NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);
//实现两个类间的数据传输

MediaPlayer mPlayer;
@Override
protected void onCreate(Bundle savedInstanceState) { 
super.onCreate(savedInstanceState);
//Bundle 类型的数据与Map类型的数据相似，都是以key-value的形式存储数据的
//onsavelnstanceState方法是用来保存Activity的状态的
//能从onCreate的参数savedInsanceState中获得状态数据 requestWindowFeature(Window.FEATURE_NO_TITLE);
//界面显示

final Window win=getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
if(!isScreenOn()){
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON

//保持窗体点亮
|WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
//将窗体点亮
|WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//允许窗体点亮时锁屏
|WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);}
//在手机锁屏后如果到了闹钟提示时间，点亮屏幕
Intent intent =getintent();
try{

mNoteld =Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet = DataUtils.getSnippetByld(this.getContentResolver(),mNoteld);
//根据ID从数据库中获取标签的内容;
//getContentResolver()是实现数据共享，实例存储。
mSnippet = mSnippet.length() >SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN) +getResources().getString(R.string.notelist_string_info):mSnippet;
//判断标签片段是否达到符合长度} catch (IllegalArgumentException e){ e.printStackTrace(); return;
/* try
// 代码区
catch(Exception e){
//异常处理
代码区如果有错误，就会返回所写异常的处理。*/ mPlayer = new MediaPlayer();
if (DataUtils.visiblelnNoteDatabase(getContentResolver(), mNoteld, Notes.TYPE_NOTE)) { showActionDialog();
//弹出对话框 playAlarmSound();
//闹钟提示音激发

} else{ finish();
//完成闹钟动作

private boolean isScreenOn(){
//判断屏幕是否锁屏，调用系统函数判断，最后返回值是布尔类型
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); return pm.isScreenOn();

private void playAlarmSound() {
//闹钟提示音激发
Uri	url	RingtoneManager.getActualDefaultRingtoneUri(this,	
RingtoneManager.TYPE_ALARM);
//调用系统的铃声管理URI，得到闹钟提示音
int silentModeStreams = Settings.System.getint(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0);
if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { mPlayer.setAudioStreamType(silentModeStreams);}else{
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
try{
mPlayer.setDataSource(this, url);
//方法:setDataSource(Context context, Uri uri)
//解释:无返回值，设置多媒体数据来源[根据Uni] mPlayer.prepare();
//准备同步
mPlayer.setLooping(true);//设置是否循环播放

mPlayer.start();
//开始播放
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block e.printStackTrace();

// TODO Auto-generated catch block e.printStackTrace();
}catch (IllegalStateException e){
// TODO Auto-generated ctch block e.printStackTrace();} catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace();

private void showActionDialog(){
AlertDialog,Builder dialog = new AlertDialog.Builder(this);
//AlertDialog的构造方法全部是Protected的
//所以不能直接通过new一个AlertDialog来创建出一个AlertDialog.

//要创建一个AlertDialog，就要用到AlertDialog,Builder 中的create()方法
//如这里的 dialog 就是新建了一个AlertDialog dialog.setTitle(R.string.app_name);
//为对话框设置标题
dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮 if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);}
//对话框添加"No"按钮
dialog.show().setOnDismissListener(this);

public void onClick(DialogInterface dialog, int which) { switch (which) {
//用which 来选择 click后下一步的操作 case DialogInterface.BUTTON_NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);//实现两个类间的数据传输

/*
*Get currentMinute
*@return The Current Minute

public int getCurrentMinute(){
return mDate.get(Calendar.MINUTE);
/**
*Set current minute
public void setCurrentMinute(int minute){
if (!mlnitialising && minute ==getCurrentMinute()) { return;

mMinuteSpinner.setValue(minute);

mDate.set(Calendar.MINUTE,minute); onDateTimeChanged();

1**
*@return true lf this is in 24 hour view else false.
\
public boolean is24HourView (){ return mls24HourView;

/*
*Set whether in 24 hour or AM/PM mode.
*@param is24HourView True for 24 hour mode. False for AM/PM mode.
public void set24HourView(boolean is24HourView){
// TODO Auto-generated catch block e.printStackTrace();
//e.printStackTrace()函数功能是抛出异常，还将显示出更深的调用信息
//System.out.printin(e)，这个方法打印出异常，并且输出在哪里出现的异常
}catch (SecurityException e) {
// TODO Auto-generated catch block 
e.printStackTrace();
} catch (IllegalStateException e)
{
// TODO Auto-generated catch block e.printStackTrace();} catch (I0Exception e)
 {
// TODO Auto-generated catch block e.printStackTrace();

private void showActionDialog(){
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
//AlertDialog的构造方法全部是Protected的
//所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。
//要创建一个AlertDialog，就要用到AlertDialog.Builder中的create()方法

//为对话框设置标题
dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮 if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);}
//对话框添加"No"按钮
dialog.show().setOnDismissListener(this);

public void onClick(Dialoginterface dialog, int which) { 
switch (which) {
//用which 来选择click后下一步的操作 case DialogInterface.BUTTON NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);
//实现两个类间的数据传输


if (mls24HourView== is24HourView) { return;
mls24HourView= is24HourView;
mAmPmSpinner.setVisibility(is24HourView?View.GONE:View.VISIBLE); 
int hour = getCurrentHourOfDay(); 
updateHourControl(); setCurrentHour(hour); 
updateAmPmControl();

private void updateDateControl(){
Calendar cal =Calendar.getlnstance();
cal.setTimelnMillis(mDate.getTimelnMillis());
cal.add(Calendar.DAY OF YEAR,-DAYS IN ALL WEEK/2-1); 
mDateSpinner.setDisplayedValues(null); for (inti=0;i<DAYS_IN_ALL_WEEK; ++i) { 
cal.add(Calendar.DAY_OF_YEAR, 1);
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
mDateSpinner.setDisplayedValues(mDateDisplayValues); 
mDateSpinner.setValue(DAYS_IN_ALL_WEEK/ 2); mDateSpinner.invalidate();}
//对于星期几的算法
private void updateAmPmControl(){ if (mls24HourView) {
mAmPmSpinner.setVisibility(View.GONE);}else{
int index= mlsAm ? Calendar.AM:Calendar.PM; 
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);}
//对于上下午操作的算法

private void updateHourControl(){ if (mls24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);}else{
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);}
//对与小时的算法

*Set the callback that indicates the 'Set' button has been pressed.* @param callback the callback, if null will do nothing
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback){ 
mOnDateTimeChangedListener =callback;
package net.micode.notes.data;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;

/**
 * 笔记数据库帮助类，用于创建和管理笔记数据库
 */
public class NotesDatabaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "note.db"; // 数据库名称

    private static final int DB_VERSION = 4; // 数据库版本号



MediaPlayer mPlayer;

@Override
protected vold onCreate(Bundle savedInstanceState) { 
	super.onCreate(savedInstanceState);
//Bundle类型的数据与Map类型的数据相似，都是以key-value的形式存储数据的
//onsavelnstanceState方法是用来保存Activity的状态的
//能从 onCreate的参数savedInsanceState中获得状态数据 
requestWindowFeature(Window.FEATURE_NO_TITLE);
//界面显示一-无标题
final Window win=getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG SHOW_WHEN LOCKED);
if (lisScreenOn()){
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
//保持窗体点亮
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
//将窗体点亮
|WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//允许窗体点亮时锁屏
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);]
//在手机锁屏后如果到了闹钟提示时间，点亮屏幕
Intent intent =getIntent();
try{
mNoteld=Long.valueOf(intent.getData().getPathSegments().get(1));
mSnippet =DataUtils.getSnippetByld(this.getContentResolver(), mNoteld);
//根据ID从数据库中获取标签的内容:
//getContentResolver()是实现数据共享，实例存储。
mSnippet = mSnippet.length() >SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0,
SNIPPET_PREW_MAX_LEN)+getResources().getString(R.string.notelist_string_info):mSnippet;
//判断标签片段是否达到符合长度} catch (IllegalArgumentException e){ e.printStackTrace(); return;

try
// 代码区

catch(Exception e)
//异常处理
代码区如果有错误，就会返回所写异常的处理。*/ mPlayer = new MediaPlayer();
if (DataUtils,visibleInNoteDatabase(getContentResolver(), mNoteld, Notes.TYPE_NOTE)) { showActionDialog();
试访	试读	
//弹出对话框 playAlarmSound();//闹钟提示音激发}else{ finish();
//完成闹钟动作

private boolean isScreenOn(){
//判断屏幕是否锁屏，调用系统函数判断
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); return pm.isScreenOn();

private vold playAlarmSound() {//闹钟提示音激发
Uri	url	RingtoneManager.getActualDefaultRingtoneUri(this,	
RingtoneManager.TYPE_ALARM);
//调用系统的铃声管理URI，得到闹钟提示音
int silentModeStreams =Settings.System.getInt(getContentResolver(),
Settings.System.MODE_RINGER_STREAMS_AFFECTED,0);
if ((silentModeStreams & (1<<AudioManager.STREAM_ALARM)) != 0) {
mPlayer.setAudioStreamType(silentModeStreams);
}else{
mPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
}
try{
mPlayer.setDataSource(this, url);
//方法:setDataSource(Context context, Uri uri)
//解释:无返回值，设置多媒体数据来源[根据Uni]
mPlayer.prepare();
//准备同步
mPlayer.setLooping(true);
//设置是否循环播放

mPlayer.start();
//开始播放
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block e.printStackTrace();
//e.printStackTrace()函数功能是抛出异常，还将显示出更深的调用信息
//System.out.printin(e)，这个方法打印出异常，并且输出在哪里出现的异常
}catch (SecurityException e) {
// TODO Auto-generated catch block 
e.printStackTrace();
} catch (IllegalStateException e)
{
// TODO Auto-generated catch block e.printStackTrace();} catch (I0Exception e)
 {
// TODO Auto-generated catch block e.printStackTrace();

private void showActionDialog(){
AlertDialog.Builder dialog = new AlertDialog.Builder(this);
//AlertDialog的构造方法全部是Protected的
//所以不能直接通过new一个AlertDialog来创建出一个AlertDialog。
//要创建一个AlertDialog，就要用到AlertDialog.Builder中的create()方法

//为对话框设置标题
dialog.setMessage(mSnippet);
//为对话框设置内容
dialog.setPositiveButton(R.string.notealert_ok, this);
//给对话框添加"Yes"按钮 if (isScreenOn()) {
dialog.setNegativeButton(R.string.notealert_enter, this);}
//对话框添加"No"按钮
dialog.show().setOnDismissListener(this);

public void onClick(Dialoginterface dialog, int which) { 
switch (which) {
//用which 来选择click后下一步的操作 case DialogInterface.BUTTON NEGATIVE:
//这是取消操作
Intent intent = new Intent(this, NoteEditActivity.class);
//实现两个类间的数据传输


if (mls24HourView== is24HourView) { return;
mls24HourView= is24HourView;
mAmPmSpinner.setVisibility(is24HourView?View.GONE:View.VISIBLE); 
int hour = getCurrentHourOfDay(); 
updateHourControl(); setCurrentHour(hour); 
updateAmPmControl();

private void updateDateControl(){
Calendar cal =Calendar.getlnstance();
cal.setTimelnMillis(mDate.getTimelnMillis());
cal.add(Calendar.DAY OF YEAR,-DAYS IN ALL WEEK/2-1); 
mDateSpinner.setDisplayedValues(null); for (inti=0;i<DAYS_IN_ALL_WEEK; ++i) { 
cal.add(Calendar.DAY_OF_YEAR, 1);
mDateDisplayValues[i] = (String) DateFormat.format("MM.dd EEEE", cal);
mDateSpinner.setDisplayedValues(mDateDisplayValues); 
mDateSpinner.setValue(DAYS_IN_ALL_WEEK/ 2); mDateSpinner.invalidate();}
//对于星期几的算法
private void updateAmPmControl(){ if (mls24HourView) {
mAmPmSpinner.setVisibility(View.GONE);}else{
int index= mlsAm ? Calendar.AM:Calendar.PM; 
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);}
//对于上下午操作的算法

private void updateHourControl(){ if (mls24HourView) {
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_24_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_24_HOUR_VIEW);}else{
mHourSpinner.setMinValue(HOUR_SPINNER_MIN_VAL_12_HOUR_VIEW);
mHourSpinner.setMaxValue(HOUR_SPINNER_MAX_VAL_12_HOUR_VIEW);}
//对与小时的算法

*Set the callback that indicates the 'Set' button has been pressed.* @param callback the callback, if null will do nothing
public void setOnDateTimeChangedListener(OnDateTimeChangedListener callback){ 
mOnDateTimeChangedListener =callback;
package net.micode.notes.data;

import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;

/**
 * 笔记数据库帮助类，用于创建和管理笔记数据库
 */
public class NotesDatabaseHelper extends SQLiteOpenHelper {
    private static final String DB_NAME = "note.db"; // 数据库名称

    private static final int DB_VERSION = 4; // 数据库版本号

    /**
     * 定义数据库表的接口
     */
    public interface TABLE {
        public static final String NOTE = "note"; // 笔记表

        public static final String DATA = "data"; // 数据表
    }

    private static final String TAG = "NotesDatabaseHelper"; // 日志标签

    private static NotesDatabaseHelper mInstance; // 数据库帮助类实例

    /**
     * 创建笔记表的 SQL 语句
     */
    private static final String CREATE_NOTE_TABLE_SQL =
        "CREATE TABLE " + TABLE.NOTE + "(" +
            NoteColumns.ID + " INTEGER PRIMARY KEY," +
            NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
            NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
            NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
            NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
        ")";

    /**
     * 创建数据表的 SQL 语句
     */
    private static final String CREATE_DATA_TABLE_SQL =
        "CREATE TABLE " + TABLE.DATA + "(" +
            DataColumns.ID + " INTEGER PRIMARY KEY," +
            DataColumns.MIME_TYPE + " TEXT NOT NULL," +
            DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
            NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
            DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
            DataColumns.DATA1 + " INTEGER," +
            DataColumns.DATA2 + " INTEGER," +
            DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
            DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
            DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
        ")";

    // 这里可能还有其他方法，比如构造函数、数据库升级方法等
}

private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
    "CREATE INDEX IF NOT EXISTS note_id_index ON " +
    TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";

/**
 * 当将笔记移动到文件夹时增加文件夹的笔记计数
 */
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
    "CREATE TRIGGER increase_folder_count_on_update "+
    " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
    " BEGIN " +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
    "  WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
    " END";

/**
 * 当从文件夹中移除笔记时减少文件夹的笔记计数
 */
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
    "CREATE TRIGGER decrease_folder_count_on_update " +
    " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
    " BEGIN " +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
    "  WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
    "  AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
    " END";

/**
 * 当将新的笔记插入文件夹时增加文件夹的笔记计数
 */
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
    "CREATE TRIGGER increase_folder_count_on_insert " +
    " AFTER INSERT ON " + TABLE.NOTE +
    " BEGIN " +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
    "  WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
    " END";

/**
 * 当从文件夹中删除笔记时减少文件夹的笔记计数
 */
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
    "CREATE TRIGGER decrease_folder_count_on_delete " +
    " AFTER DELETE ON " + TABLE.NOTE +
    " BEGIN " +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
    "  WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
    "  AND " + NoteColumns.NOTES_COUNT + ">0;" +
    " END";

/**
 * 当插入类型为 {@link DataConstants#NOTE} 的数据时更新笔记内容
 */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
    "CREATE TRIGGER update_note_content_on_insert " +
    " AFTER INSERT ON " + TABLE.DATA +
    " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
    " BEGIN" +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
    "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
    " END";

/**
 * 当类型为 {@link DataConstants#NOTE} 的数据发生更改时更新笔记内容
 */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
    "CREATE TRIGGER update_note_content_on_update " +
    " AFTER UPDATE ON " + TABLE.DATA +
    " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
    " BEGIN" +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
    "  WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
    " END";
```java
/**
 * 当类型为 {@link DataConstants#NOTE} 的数据被删除时，更新笔记内容
 */
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
    "CREATE TRIGGER update_note_content_on_delete " +
    "AFTER delete ON " + TABLE.DATA +
    " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
    " BEGIN" +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.SNIPPET + "=''" +
    "  WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
    " END";

/**
 * 删除已删除笔记所属的数据
 */
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
    "CREATE TRIGGER delete_data_on_delete " +
    "AFTER DELETE ON " + TABLE.NOTE +
    " BEGIN" +
    "  DELETE FROM " + TABLE.DATA +
    "   WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
    " END";

/**
 * 删除已删除文件夹所属的笔记
 */
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
    "CREATE TRIGGER folder_delete_notes_on_delete " +
    "AFTER DELETE ON " + TABLE.NOTE +
    " BEGIN" +
    "  DELETE FROM " + TABLE.NOTE +
    "   WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
    " END";

/**
 * 将已移至回收站的文件夹中的笔记移动至回收站
 */
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
    "CREATE TRIGGER folder_move_notes_on_trash " +
    "AFTER UPDATE ON " + TABLE.NOTE +
    " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
    " BEGIN" +
    "  UPDATE " + TABLE.NOTE +
    "   SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
    "  WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
    " END";

public NotesDatabaseHelper(Context context) {
    super(context, DB_NAME, null, DB_VERSION);
}

public void createNoteTable(SQLiteDatabase db) {
    db.execSQL(CREATE_NOTE_TABLE_SQL);
    reCreateNoteTableTriggers(db);
    createSystemFolder(db);
    Log.d(TAG, "note table has been created");
}

private void reCreateNoteTableTriggers(SQLiteDatabase db) {
    db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
    db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
    db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
    db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
    db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
    db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
    db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");

    db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
    db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
    db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
    db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
    db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
    db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
    db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}

private void createSystemFolder(SQLiteDatabase db) {
    ContentValues values = new ContentValues();

    /**
     * 为通话笔记创建通话记录文件夹
     */
    values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
    values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
    db.insert(TABLE.NOTE, null, values);

    /**
     * 根文件夹，即默认文件夹
     */
    values.clear();
    values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
    values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
    db.insert(TABLE.NOTE, null, values);

    /**
     * 临时文件夹，用于移动笔记
     */
    values.clear();
    values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
    values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
    db.insert(TABLE.NOTE, null, values);

    /**
     * 创建回收站文件夹
     */
    values.clear();
    values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
    values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
    db.insert(TABLE.NOTE, null, values);
}

public void createDataTable(SQLiteDatabase db) {
    db.execSQL(CREATE_DATA_TABLE_SQL);
    reCreateDataTableTriggers(db);
    db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
    Log.d(TAG, "data table has been created");
}

private void reCreateDataTableTriggers(SQLiteDatabase db) {
    db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
    db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
    db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");

    db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
    db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
    db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}


```java
/**
 * 获取数据库辅助类的实例，使用了同步锁确保线程安全
 * @param context 上下文对象
 * @return NotesDatabaseHelper 实例
 */
static synchronized NotesDatabaseHelper getInstance(Context context) {
    if (mInstance == null) {
        mInstance = new NotesDatabaseHelper(context);
    }
    return mInstance;
}

@Override
public void onCreate(SQLiteDatabase db) {
    // 创建笔记表和数据表
    createNoteTable(db);
    createDataTable(db);
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    boolean reCreateTriggers = false; // 是否需要重新创建触发器
    boolean skipV2 = false; // 是否跳过版本2的升级

    if (oldVersion == 1) {
        upgradeToV2(db); // 升级到版本2
        skipV2 = true; // 此次升级包含了从版本2到版本3的升级
        oldVersion++;
    }

    if (oldVersion == 2 && !skipV2) {
        upgradeToV3(db); // 升级到版本3
        reCreateTriggers = true;
        oldVersion++;
    }

    if (oldVersion == 3) {
        upgradeToV4(db); // 升级到版本4
        oldVersion++;
    }

    // 如果需要重新创建触发器，则执行相应的方法
    if (reCreateTriggers) {
        reCreateNoteTableTriggers(db);
        reCreateDataTableTriggers(db);
    }

    // 如果旧版本号与新版本号不匹配，则抛出异常
    if (oldVersion != newVersion) {
        throw new IllegalStateException("升级笔记数据库到版本 " + newVersion + " 失败");
    }
}

/**
 * 升级到版本2的方法
 * @param db SQLiteDatabase 对象
 */
private void upgradeToV2(SQLiteDatabase db) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); // 删除笔记表
    db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA); // 删除数据表
    createNoteTable(db); // 重新创建笔记表
    createDataTable(db); // 重新创建数据表
}

/**
 * 升级到版本3的方法
 * @param db SQLiteDatabase 对象
 */
private void upgradeToV3(SQLiteDatabase db) {
    // 删除不再使用的触发器
    db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
    db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
    db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
    // 添加一个用于保存 Gtask ID 的列
    db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
            + " TEXT NOT NULL DEFAULT ''");
    // 添加一个垃圾箱系统文件夹
    ContentValues values = new ContentValues();
    values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
    values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
    db.insert(TABLE.NOTE, null, values);
}

/**
 * 升级到版本4的方法
 * @param db SQLiteDatabase 对象
 */
private void upgradeToV4(SQLiteDatabase db) {
    // 添加一个版本号的列
    db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
            + " INTEGER NOT NULL DEFAULT 0");
}


