diff --git a/doc/蒋欣萍精读部分/BackupUtils.java b/doc/蒋欣萍精读部分/BackupUtils.java new file mode 100644 index 0000000..802aeab --- /dev/null +++ b/doc/蒋欣萍精读部分/BackupUtils.java @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) //打开网站 + * + * Licensed under the Apache License, Version 2.0 (the "License"); //2.0版本 + * you may not use this file except in compliance with the License. //使用该文件 + * You may obtain a copy of the License at //提交通行证 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. //BackupUtils 是一个备份工具类,用于数据备份读取和显示 + */ + +package net.micode.notes.tool; //定义了功能类数据 + +import android.content.Context; //. 导入小米便签需要的各项函数 +import android.database.Cursor; //查询数据类型 +import android.os.Environment; //导入环境包 +import android.text.TextUtils; //导入安卓文本功能包 +import android.text.format.DateFormat; //用于转换格式 +import android.util.Log; //用于打印与查看日志的类 + +import net.micode.notes.R; // 从Notes项目的其他软件包中调用类。 +import net.micode.notes.data.Notes; //数据便签类 +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.DataConstants; // 数据类型类 +import net.micode.notes.data.Notes.NoteColumns; //便签类 + +import java.io.File; //引入java的文件处理,输入输出等功能 +import java.io.FileNotFoundException; //文件未找到的错误处理 +import java.io.FileOutputStream; //文件的输入 +import java.io.IOException; //操作错误处理 +import java.io.PrintStream; //导入所需要用到的包 + + +public class BackupUtils { //备份工具类,从备份文件中恢复便签 + private static final String TAG = "BackupUtils"; //实例化化对象BackupUtils + // Singleton stuff + private static BackupUtils sInstance; //实例化一个BackupUnils的对象sInstance + + public static synchronized BackupUtils getInstance(Context context) { //定义一个synchronize的函数,每次运行到synchronize时,首先判断这个函数是否有别人在用这个方法,如果有就等完再用,否则即可调用此函数 + if (sInstance == null) { //如果当前备份不存在,则声明一个 + sInstance = new BackupUtils(context); + } + return sInstance; //返回当前sInstance的值(或备份文件) + } + + /** + * Following states are signs to represents backup or restore //以下状态用于表示备份或者恢复 + + * status //定义状态常量 + */ + // Currently, the sdcard is not mounted + public static final int STATE_SD_CARD_UNMOUONTED = 0; //备份文件夹不存在 + // The backup file not exist + public static final int STATE_BACKUP_FILE_NOT_EXIST = 1; //数据已被破坏,可能被修改 + // The data is not well formated, may be changed by other programs + public static final int STATE_DATA_DESTROIED = 2; //系统出现错误 + // Some run-time exception which causes restore or backup fails + public static final int STATE_SYSTEM_ERROR = 3; //导出成功 + // Backup or restore success + public static final int STATE_SUCCESS = 4; //成功导出/状态正常 + + private TextExport mTextExport; //实例化一个textexport的对象 + + private BackupUtils(Context context) { //初始化函数 + mTextExport = new TextExport(context); + } + + private static boolean externalStorageAvailable() { //判断外部存储功能是否可用 + return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); + } + + public int exportToText() { //输出至文本 + return mTextExport.exportToText(); // 返回输出文本状态 + } + + public String getExportedTextFileName() { //获取输出的文本文件名 + return mTextExport.mFileName; //返回输出文本的文件名 + } + + public String getExportedTextFileDir() { //获得输出文本的文本路径 + return mTextExport.mFileDirectory; //返回输出文本文件的路径 + } + + private static class TextExport { //定义了一个TextExport的类,包含笔记ID、修改日期、数据及其格式类型 + private static final String[] NOTE_PROJECTION = { //定义了一个数组储存便签的信息 + NoteColumns.ID, + NoteColumns.MODIFIED_DATE, + NoteColumns.SNIPPET, + NoteColumns.TYPE + }; + + private static final int NOTE_COLUMN_ID = 0; //初始化标识:笔记ID标识为0;笔记的修改日期标识为1;笔记的数据标识为2. + + private static final int NOTE_COLUMN_MODIFIED_DATE = 1; + + private static final int NOTE_COLUMN_SNIPPET = 2; + + private static final String[] DATA_PROJECTION = { //定义字符串存储数据的基本信息 + DataColumns.CONTENT, + DataColumns.MIME_TYPE, + DataColumns.DATA1, + DataColumns.DATA2, + DataColumns.DATA3, + DataColumns.DATA4, + }; + + private static final int DATA_COLUMN_CONTENT = 0; //标识设定:数据内容标识为0;媒体类型标识为1;访问日期标识为2;电话号码标识为4 + + private static final int DATA_COLUMN_MIME_TYPE = 1; + + private static final int DATA_COLUMN_CALL_DATE = 2; + + private static final int DATA_COLUMN_PHONE_NUMBER = 4; + + private final String [] TEXT_FORMAT; //文档格式标识:名称赋值为0,日期赋值为1,内容赋值为2 + private static final int FORMAT_FOLDER_NAME = 0; + private static final int FORMAT_NOTE_DATE = 1; + private static final int FORMAT_NOTE_CONTENT = 2; + + private Context mContext; //定义一个内部上下类 + private String mFileName; //定义文件名 + private String mFileDirectory; //定义文件夹路径 + + public TextExport(Context context) { //从context类实例中获取信息,给对应的属性赋初始值 + TEXT_FORMAT = context.getResources().getStringArray(R.array.format_for_exported_note); + mContext = context; //定义文件内容为便签内容 + mFileName = ""; //文件名初始化为空 + mFileDirectory = ""; //文件路径初始化为空 + } + + private String getFormat(int id) { //获取id对应的格式 + return TEXT_FORMAT[id]; + } + + /** + * Export the folder identified by folder id to text //输出文件夹 + */ + private void exportFolderToText(String folderId, PrintStream ps) { //通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note + // Query notes belong to this folder + Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, //根据便签目录的URI找到利用的数据,并根据PARENT_ID和文件ID在数据里查找,并放到游标中 + NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { + folderId + }, null); //如果查询结果非空那么按照时间格式输出最后修改的时间 + + if (notesCursor != null) { //将查找到的数据全部导到文本里面 + if (notesCursor.moveToFirst()) { // 如果游标执行到第一行 + do { //ps里面保存有这份note的日期 + // Print note's last modified date + ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( //打印最后修改日期 + mContext.getString(R.string.format_datetime_mdhm), + notesCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); + // Query data belong to this note + String noteId = notesCursor.getString(NOTE_COLUMN_ID); //查询属于该便签的数据 + exportNoteToText(noteId, ps); //通过文件的标识将目录导出成文件 + } while (notesCursor.moveToNext()); //遍历这个文件夹底下所有的便签 + } + notesCursor.close(); //关闭游标 + } + } + + /** + * Export note identified by id to a print stream + */ + private void exportNoteToText(String noteId, PrintStream ps) { //打印便签的内容,分为电话号码类型和便签类型 + Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, + DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { //将CONTENT_DATA_URI里DATA_PROFECTION内容扫描到游标中,按默认顺序进行排序 + noteId + }, null); + + if (dataCursor != null) { //如果数据游标不为空 + if (dataCursor.moveToFirst()) { + do { + String mimeType = dataCursor.getString(DATA_COLUMN_MIME_TYPE); // 获得便签的媒体类型 + if (DataConstants.CALL_NOTE.equals(mimeType)) { //判断便签的内容,如果是电话记录,那么在这一个代码块内打印 + // Print phone number + String phoneNumber = dataCursor.getString(DATA_COLUMN_PHONE_NUMBER); //获取手机号码 + long callDate = dataCursor.getLong(DATA_COLUMN_CALL_DATE); // 获取通话时长 + String location = dataCursor.getString(DATA_COLUMN_CONTENT); //获取地址 + + if (!TextUtils.isEmpty(phoneNumber)) { //判断是否是空字符 + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), //输出电话号码phoneNumber + phoneNumber)); + } + // Print call date + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), DateFormat //输出calldate + .format(mContext.getString(R.string.format_datetime_mdhm), + callDate))); + // Print call attachment location + if (!TextUtils.isEmpty(location)) { //判断是否存在位置信息 + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), //打印便签格式和位置信息 + location)); + } + } else if (DataConstants.NOTE.equals(mimeType)) { //如果是便签的内容,那么直接输出便签里面包含的东西 + String content = dataCursor.getString(DATA_COLUMN_CONTENT); + if (!TextUtils.isEmpty(content)) { //如果便签内容不为空值 + ps.println(String.format(getFormat(FORMAT_NOTE_CONTENT), //判断文本包中内容是否为空,若非空则将文本内容输出到打印输出流中 + content)); + } + } + } while (dataCursor.moveToNext()); //光标下移 + } + dataCursor.close(); //关闭光标 + } + // print a line separator between note + try { + ps.write(new byte[] { //在note下面输出一条线 + Character.LINE_SEPARATOR, Character.LETTER_NUMBER + }); + } catch (IOException e) { //检测异常,如果有异常输出红色TAG + Log.e(TAG, e.toString()); //捕获错误信息并记录异常日志 + } + } + + /** + * Note will be exported as text which is user readable + */ + public int exportToText() { //总函数,调用上面的exportFolder和exportNote + if (!externalStorageAvailable()) { //检查外部设备安装情况,如果未安装好,则蓝色字体输出debug信息,并返回STATE_SD_CARD_UNMOUNOTED值为0 + Log.d(TAG, "Media was not mounted"); + return STATE_SD_CARD_UNMOUONTED; + } + + PrintStream ps = getExportToTextPrintStream(); // 获得外部设备存储路径 + if (ps == null) { //导出文件夹,并导出里面包含的便签 + Log.e(TAG, "get print stream error"); //如果ps赋值失败,则输出显示错误的信息,并返回状态错误信息 + return STATE_SYSTEM_ERROR; + } //导出文件夹及其中的便签 + // First export folder and its notes + Cursor folderCursor = mContext.getContentResolver().query( //定位需要导出的文件夹 + Notes.CONTENT_NOTE_URI, + NOTE_PROJECTION, + "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " + + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); + + if (folderCursor != null) { //文件夹游标不为空,即存在文件夹 + if (folderCursor.moveToFirst()) { //文件夹光标在第一行时 + do { //打印输出文件夹的名称 + // Print folder's name + String folderName = ""; //输出文件夹的名字 + if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { // 根据folder在数据库中的位置来找到文件名 + folderName = mContext.getString(R.string.call_record_folder_name); + } else { + folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); //若未得到文件夹位置,则从便签前面一部分字符串为文件夹名称 + } + if (!TextUtils.isEmpty(folderName)) { //判断folderName是否存在,存在即输出其格式和flodername + ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); + } + String folderId = folderCursor.getString(NOTE_COLUMN_ID); //通过便签id得到folderID + exportFolderToText(folderId, ps); //将文件夹中内容导出打印 + } while (folderCursor.moveToNext()); //文件夹的光标下移 + } + folderCursor.close(); //关闭游标 + } + + // Export notes in root's folder + Cursor noteCursor = mContext.getContentResolver().query( //输出根目录下的便签 + Notes.CONTENT_NOTE_URI, + NOTE_PROJECTION, + NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID + + "=0", null, null); + + if (noteCursor != null) { //便签对应游标不为空 + if (noteCursor.moveToFirst()) { //便签光标下移 + do { + ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( //打印便签的修改时间 + mContext.getString(R.string.format_datetime_mdhm), + noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); //访问便签中的数据的相关信息 + // Query data belong to this note + String noteId = noteCursor.getString(NOTE_COLUMN_ID); //找到这块数据的ID. + exportNoteToText(noteId, ps); //将便签以文本的形式导出并打印 + } while (noteCursor.moveToNext()); // 便签光标下移 + } + noteCursor.close(); //关闭游标 + } + ps.close(); + + return STATE_SUCCESS; //返回成功导出的状态 + } + + /** + * Get a print stream pointed to the file {@generateExportedTextFile} + */ + private PrintStream getExportToTextPrintStream() { //将要输出的内容整合到一个输出里并返回该输出流 + File file = generateFileMountedOnSDcard(mContext, R.string.file_path, //初始化存储在SD卡的文件 + R.string.file_name_txt_format); + if (file == null) { //如果文件为空,则创建失败 + Log.e(TAG, "create file to exported failed"); //记录异常日志 + return null; + } + mFileName = file.getName(); //获取文件名字 + mFileDirectory = mContext.getString(R.string.file_path); //获取文件路径 + PrintStream ps = null; //初始化ps + try { + FileOutputStream fos = new FileOutputStream(file); //将ps输出流输出到特定的文件,目的就是导出到文件,而不是直接输出 + ps = new PrintStream(fos); + } catch (FileNotFoundException e) { //找不到系统指定文件 + e.printStackTrace(); + return null; + } catch (NullPointerException e) { //捕获空指针异常 + e.printStackTrace(); + return null; + } + return ps; + } + } + + /** + * Generate the text file to store imported data + */ + private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { //生成文件存储在外部存储器上 + StringBuilder sb = new StringBuilder(); //构建一个动态字符串将外部存储器路径、文件路径、编辑时间加入到其中 + sb.append(Environment.getExternalStorageDirectory()); //加入外部SD卡的存储路径 + sb.append(context.getString(filePathResId)); //文件的存储路径 + File filedir = new File(sb.toString()); //存储路径信息 + sb.append(context.getString( //格式化输出当前系统时间 + fileNameFormatResId, + DateFormat.format(context.getString(R.string.format_date_ymd), //将当前的系统时间以预定的格式输出 + System.currentTimeMillis()))); + File file = new File(sb.toString()); // 创建包含输出内容的文件 + + try { //若没有安全异常、输入输出异常,则在没有文件夹或文件的情况下新建 + if (!filedir.exists()) { + filedir.mkdir(); + } + if (!file.exists()) { + file.createNewFile(); + } + return file; //返回导出的文件 + } catch (SecurityException e) { //捕获安全异常的状况 + e.printStackTrace(); + } catch (IOException e) { //输入输出异常处理 + e.printStackTrace(); + } + + return null; //try catch 异常处理 + } +} + + diff --git a/doc/蒋欣萍精读部分/DataUtils.java b/doc/蒋欣萍精读部分/DataUtils.java new file mode 100644 index 0000000..c7d8eaf --- /dev/null +++ b/doc/蒋欣萍精读部分/DataUtils.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + //对数据处理的操作定义 +package net.micode.notes.tool; //导入相关的包 + +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentResolver; //批量删除笔记 +import android.content.ContentUris; +import android.content.ContentValues; //便签的内容价值 +import android.content.OperationApplicationException; //操作方法 +import android.database.Cursor; +import android.os.RemoteException; //远程交互 +import android.util.Log; + +import net.micode.notes.data.Notes; //便签数据类相关的包 +import net.micode.notes.data.Notes.CallNote; +import net.micode.notes.data.Notes.NoteColumns; //便签栏的数据 +import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute; + +import java.util.ArrayList; // 导入数组处理包 +import java.util.HashSet; //导入需要的包 + + +public class DataUtils { //定义数据工具类 + public static final String TAG = "DataUtils"; + public static boolean batchDeleteNotes(ContentResolver resolver, HashSet ids) { //实现了批量删除便签 + if (ids == null) { //判断是否存在笔记 + Log.d(TAG, "the ids is null"); + return true; + } + if (ids.size() == 0) { //判断笔记内容是否为空 + Log.d(TAG, "no id is in the hashset"); //打印结果到日志里面 ,并进行存储 + return true; + } + + ArrayList operationList = new ArrayList(); //创建一个新的数组列表 + for (long id : ids) { //遍历数据,如果此数据为根目录则跳过此数据不删除,如果不是根目录则将此数据删除 + if(id == Notes.ID_ROOT_FOLDER) { //避免出现删除系统目录的情况 + Log.e(TAG, "Don't delete system folder root"); //检测当前id是不是指向根目录,若是返回一个异常信息 + continue; //如果发现是根文件夹,则不删除 + } + ContentProviderOperation.Builder builder = ContentProviderOperation //使用newdelete进行删除 + .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + operationList.add(builder.build()); //将操作添加至列表 + } + try { //返回被删除的数据,如果返回为空则删除失败返回false,打印异常信息,删除成功返回true + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //主机名Authority用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。 + if (results == null || results.length == 0 || results[0] == null) { + Log.d(TAG, "delete notes failed, ids:" + ids.toString()); //检测当前要删除的便签是否是根目录,如果是根目录,,返回异常信息 + return false; + } + return true; + } catch (RemoteException e) { //对错误进行处理 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + return false; + } + + public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) { //将便签移动到文件夹中 + ContentValues values = new ContentValues(); //实例化一个contentValues类 + values.put(NoteColumns.PARENT_ID, desFolderId); //将当前ID更改为移动的目录ID + values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); //设置origin也即原本的父节点为原本的文件夹的id + values.put(NoteColumns.LOCAL_MODIFIED, 1); //是否修改状态置为1 + resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); //对需要移动的便签进行数据更新,然后用update实现 + } + + public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, //批量的将标签移动到另一个目录下 + long folderId) { + if (ids == null) { // 判断便签ID是否为空 + Log.d(TAG, "the ids is null"); + return true; + } + + ArrayList operationList = new ArrayList(); //将ids里包含的每一列的数据逐次加入到operationList中,等待最后的批量处理 + for (long id : ids) { //遍历所有选中的便签的id + ContentProviderOperation.Builder builder = ContentProviderOperation //通过withAppendedId方法,为该Uri加上ID + .newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); + builder.withValue(NoteColumns.PARENT_ID, folderId); //修改便签的父节点ID为新的文件夹的ID + builder.withValue(NoteColumns.LOCAL_MODIFIED, 1); // 更改状态置为1 + operationList.add(builder.build()); //将移动的操作添加到操作列表 + } + + try { //对异常进行处理与汇报的容错机制 + ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); //使用函数applyBatch一次性处理一个操作列表 + if (results == null || results.length == 0 || results[0] == null) { + Log.d(TAG, "delete notes failed, ids:" + ids.toString()); + return false; + } + return true; + } catch (RemoteException e) { //异常处理 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } catch (OperationApplicationException e) { // 异常处理 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + } + return false; + } + + /** + * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} + */ + public static int getUserFolderCount(ContentResolver resolver) { //获取用户文件夹数 + Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, //数据库操作,拼接字符串使其成为数据库指令 + new String[] { "COUNT(*)" }, + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", + new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, //String.valueof将形参转成字符串返回 + null); + + int count = 0; + if(cursor != null) { //尝试得到用户文件夹的数量 + if(cursor.moveToFirst()) { + try { // 异常处理 + count = cursor.getInt(0); + } catch (IndexOutOfBoundsException e) { // 索引序号超出界限 + Log.e(TAG, "get folder count failed:" + e.toString()); + } finally { + cursor.close(); //关闭游标 + } + } + } + return count; + } + + public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { //判断该便签在数据库中是否可以查看到 + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), //通过withappendedid的方法为uri加上id + null, + NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, // sql语句,表示筛选出列中type等于string数组中type,且每一项的PARENT_ID不等于Notes.ID.TRAXH_FOLDER + new String [] {String.valueOf(type)}, + null); // 查询条件:type符合,且不属于垃圾文件夹 + + boolean exist = false; //判断note是否在数据库中,并返回相应的布尔值 + if (cursor != null) { //用getcount函数判断cursor是否为空 + if (cursor.getCount() > 0) { + exist = true; //判断是否存在于数据库 + } + cursor.close(); //关闭游标 + } + return exist; //返回是否有便签的状态 + } + + public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { //判断该note是否在数据库中存在 + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), + null, null, null, null); + + boolean exist = false; //初始化存在状态 + if (cursor != null) { //根据getcount此时的值可以判断dataID的存在性 + if (cursor.getCount() > 0) { //根据筛选出来的条数判断存在性 + exist = true; + } + cursor.close(); //关闭游标 + } + return exist; + } + + public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { //通过名字查询是否在可见文件夹中 + Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), //通过URI与dataId在数据库中查找数据 + null, null, null, null); + + boolean exist = false; //根据数据的有无返回相应的布尔值 + if (cursor != null) { + if (cursor.getCount() > 0) { //调用对应的uri的数据值进行查询 + exist = true; + } + cursor.close(); + } + return exist; + } + + public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { //通过名字检查可见文件夹是否存在 + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, //筛选出type相同,并且未被删除,名字对的上的 + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.SNIPPET + "=?", + new String[] { name }, null); //通过名字查找文件文件 + boolean exist = false; + if(cursor != null) { //判断找到的文件名返回文件是否存在的bool值 + if(cursor.getCount() > 0) { + exist = true; + } + cursor.close(); + } + return exist; + } + + public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { //获取便签的小部件 + Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, //查询条件:父id为传入的文件夹id + new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, + NoteColumns.PARENT_ID + "=?", + new String[] { String.valueOf(folderId) }, + null); + + HashSet set = null; //根据窗口的记录一一添加对应的属性值 + if (c != null) { //如果为null,说明该文件夹没有窗口,直接返回空即可 + if (c.moveToFirst()) { + set = new HashSet(); + do { + try { //把每一个条目对应的窗口id和type记录下来,放到set里面。每一行的第0个int和第1个int分别对应widgetId和widgetType + AppWidgetAttribute widget = new AppWidgetAttribute(); + widget.widgetId = c.getInt(0); //0对应的NoteColumns.WIDGET_ID + widget.widgetType = c.getInt(1); //1对应的NoteColumns.WIDGET_TYPE + set.add(widget); + } catch (IndexOutOfBoundsException e) { //捕捉序号越界错误,发送红色错误信息 + Log.e(TAG, e.toString()); + } //继续查询下一条 + } while (c.moveToNext()); + } + c.close(); + } + return set; + } + + public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { //通过笔记ID获取号码 + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, + new String [] { CallNote.PHONE_NUMBER }, + CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", + new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, //新建字符列表 + null); + + if (cursor != null && cursor.moveToFirst()) { //获取到电话号码并处理异常 + try { + return cursor.getString(0); //返回电话号码 + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Get call number fails " + e.toString()); + } finally { + cursor.close(); + } + } + return ""; + } + + public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { //获取ID通过电话号码和呼叫日期 + Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, //通过数据库操作,查询条件是(callDate和phoneNumber匹配传入参数的值) + new String [] { CallNote.NOTE_ID }, + CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" + + CallNote.PHONE_NUMBER + ",?)", + new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, + null); + + if (cursor != null) { //得到该note的系统属性,并以Long值的形式来保存 + if (cursor.moveToFirst()) { + try { + return cursor.getLong(0); //0对应的CallNote.NOTE_ID + } catch (IndexOutOfBoundsException e) { + Log.e(TAG, "Get call note id fails " + e.toString()); + } + } + cursor.close(); + } + return 0; + } + + public static String getSnippetById(ContentResolver resolver, long noteId) { //通过ID搜索代码 + Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, //通过ID查询 + new String [] { NoteColumns.SNIPPET }, + NoteColumns.ID + "=?", + new String [] { String.valueOf(noteId)}, + null); //通过数据库操作,查询条件是(callDate和phoneNumber匹配传入参数的值 + + if (cursor != null) { //以string的形式获取该对象当前行指定列的值 + String snippet = ""; //对字符串进行格式处理,将字符串两头的空格去掉同时将换行符去掉 + if (cursor.moveToFirst()) { + snippet = cursor.getString(0); + } + cursor.close(); + return snippet; + } + throw new IllegalArgumentException("Note is not found with id: " + noteId); //IllegalArgumentException即非法传参异常,传的参数类型冲突 + } + + public static String getFormattedSnippet(String snippet) { //把文件名标准化 + if (snippet != null) { + snippet = snippet.trim(); //trim()函数: 移除字符串两侧的空白字符或其他预定义字符 + int index = snippet.indexOf('\n'); + if (index != -1) { + snippet = snippet.substring(0, index); //截取到第一个换行符 + } + } + return snippet; + } +} diff --git a/doc/蒋欣萍精读部分/GTaskStringUtils.java b/doc/蒋欣萍精读部分/GTaskStringUtils.java new file mode 100644 index 0000000..c614485 --- /dev/null +++ b/doc/蒋欣萍精读部分/GTaskStringUtils.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + //定义了很多的静态字符串,目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面 +package net.micode.notes.tool; + +public class GTaskStringUtils { //定义了一堆静态字符常量,方便以后在使用的时候直接调用 + public final static String GTASK_JSON_ACTION_ID = "action_id"; //行动ID + + public final static String GTASK_JSON_ACTION_LIST = "action_list"; //任务列表 + + public final static String GTASK_JSON_ACTION_TYPE = "action_type"; //任务类型 + + public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; //新建 + + public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; + + public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; //移动 + + public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; + + public final static String GTASK_JSON_CREATOR_ID = "creator_id"; + + public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; //子实体 + + public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; //客户端 + + public final static String GTASK_JSON_COMPLETED = "completed"; + + public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; //当前列表位置 + + public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; //失败 + + public final static String GTASK_JSON_DELETED = "deleted"; // 删除 + + public final static String GTASK_JSON_DEST_LIST = "dest_list"; + + public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; + + public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; + + public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; + + public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; + + public final static String GTASK_JSON_GET_DELETED = "get_deleted"; + + public final static String GTASK_JSON_ID = "id"; + + public final static String GTASK_JSON_INDEX = "index"; //索引 + + public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; + + public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; + + public final static String GTASK_JSON_LIST_ID = "list_id"; + + public final static String GTASK_JSON_LISTS = "lists"; + + public final static String GTASK_JSON_NAME = "name"; + + public final static String GTASK_JSON_NEW_ID = "new_id"; + + public final static String GTASK_JSON_NOTES = "notes"; + + public final static String GTASK_JSON_PARENT_ID = "parent_id"; //搭档ID + + public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; + + public final static String GTASK_JSON_RESULTS = "results"; + + public final static String GTASK_JSON_SOURCE_LIST = "source_list"; + + public final static String GTASK_JSON_TASKS = "tasks"; //任务栏 + + public final static String GTASK_JSON_TYPE = "type"; + + public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; + + public final static String GTASK_JSON_TYPE_TASK = "TASK"; //任务 + + public final static String GTASK_JSON_USER = "user"; + + public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; + + public final static String FOLDER_DEFAULT = "Default"; + + public final static String FOLDER_CALL_NOTE = "Call_Note"; //呼叫小米便签 + + public final static String FOLDER_META = "METADATA"; + + public final static String META_HEAD_GTASK_ID = "meta_gid"; + + public final static String META_HEAD_NOTE = "meta_note"; + + public final static String META_HEAD_DATA = "meta_data"; //数据 + + public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; + +} diff --git a/doc/蒋欣萍精读部分/Note.java b/doc/蒋欣萍精读部分/Note.java new file mode 100644 index 0000000..a6b4ad4 --- /dev/null +++ b/doc/蒋欣萍精读部分/Note.java @@ -0,0 +1,253 @@ +/* +//单个便签项 + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.model;//设置包的名称 +import android.content.ContentProviderOperation; //批量更新、插入、删除便签数据 +import android.content.ContentProviderResult; //操作的结果 +import android.content.ContentUris; //用于添加或修改uri后面的ID +import android.content.ContentValues; //设置存储基本数据类型的存储机制 +import android.content.Context; //获取调用者的调用内容 +import android.content.OperationApplicationException; //操作应用数据容错 +import android.net.Uri; //访问uri相关操作 +import android.os.RemoteException; //处理远程异常 +import android.util.Log; //输出工作日志 + +import net.micode.notes.data.Notes; //处理小米便签某些属性的操作 +import net.micode.notes.data.Notes.CallNote; //对小米便签数据处理的调用 +import net.micode.notes.data.Notes.DataColumns; //数据栏操作处理 +import net.micode.notes.data.Notes.NoteColumns; //笔记栏操作处理 +import net.micode.notes.data.Notes.TextNote; //文本操作处理 + +import java.util.ArrayList; //导入Java,Util,ArrayList + + +public class Note { //定义note类,处理单个便签 + private ContentValues mNoteDiffValues; //声明一个ContentValues变量,用于存储与上次保存时修改的内容 + private NoteData mNoteData; //申明一个NoteData变量,存储note的一些数据 + private static final String TAG = "Note"; //设置软件标签 + /** + * Create a new note id for adding a new note to databases //创建一个新的便签id,用于将新便签加入数据库 + */ + public static synchronized long getNewNoteId(Context context, long folderId) { //获取新建便签的编号 + // Create a new note in the database + ContentValues values = new ContentValues(); //在数据库中创建一个新便签文件 + long createdTime = System.currentTimeMillis(); //记录便签创建时间 + values.put(NoteColumns.CREATED_DATE, createdTime); //将创建时间与便签的创建时间、修改时间相匹配,放入数据库 + values.put(NoteColumns.MODIFIED_DATE, createdTime); //修改时间为系统当前时间 + values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); //设定类型为便签类型 + values.put(NoteColumns.LOCAL_MODIFIED,1); //设定局部修改的初值为1 + values.put(NoteColumns.PARENT_ID, folderId); //将数据写入数据库表格 + Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); //得到便签ID,并处理一些异常ID + + long noteId = 0; //设置便签ID初值为0 + try { //获取id并且检测是否异常,如果异常则报错 + noteId = Long.valueOf(uri.getPathSegments().get(1)); //获取路径部分赋值为1时的值,转换成long类型赋给noteId + } catch (NumberFormatException e) { // 异常处理提示 + Log.e(TAG, "Get note id error :" + e.toString()); //获取id错误 + noteId = 0; //将便签的ID置为0 + } + if (noteId == -1) { // 错误ID的异常处理 + throw new IllegalStateException("Wrong note id:" + noteId); //非法状态时返回出错便签编号 + } + return noteId; //若没有异常,那么返回这个id + } + + public Note() { //构造Note,实例化note数据 + mNoteDiffValues = new ContentValues(); //存储便签属性 + mNoteData = new NoteData(); //存储便签的内容 + } + + public void setNoteValue(String key, String value) { //设置数据库表格的标签属性数据 + mNoteDiffValues.put(key, value); //设置key值和对应的value值 + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); //修改之后标志为1 + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); //设置修改时间为系统当前时间 + } + + public void setTextData(String key, String value) { //设置数据库表格的标签文本内容的数据 + mNoteData.setTextData(key, value); //写入key和value值 + } + + public void setTextDataId(long id) { //设置文本数据的ID + mNoteData.setTextDataId(id); //获取文本id + } + + public long getTextDataId() { //获取文本数据ID + return mNoteData.mTextDataId; //返回文本数据的ID号 + } + + public void setCallDataId(long id) { //设置电话号码数据的ID + mNoteData.setCallDataId(id); + } + + public void setCallData(String key, String value) { //设置数据库表格文件中电话号码数据对应的键值和数据 + mNoteData.setCallData(key, value); //设置key,value值 + + public boolean isLocalModified() { //根据属性特征值判定便签是否被本地修改 + return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); //相较上次存在修改size()>0 + } + + public boolean syncNote(Context context, long noteId) { //判断便签是否同步 + if (noteId <= 0) { //便签ID不合法时抛出异常 + throw new IllegalArgumentException("Wrong note id:" + noteId); //抛出异常,弹出对话框错误ID并显示错误ID号 + } + + if (!isLocalModified()) { //如果本地没有发现修改,直接返回1,指示已经同步到数据库中 + return true; + } + + /** + * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and + * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the + * note data info + */ + if (context.getContentResolver().update( //发现更新错误时,及时反馈错误信息 + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, + null) == 0) { + Log.e(TAG, "Update note error, should not happen"); //标志更新失败 + // Do not return, fall through + } + mNoteDiffValues.clear(); //清除修改的版本的属性 + + if (mNoteData.isLocalModified() //.判断数据是否同步 + && (mNoteData.pushIntoContentResolver(context, noteId) == null)) { //如果上下文传输失败,内容与ID为空,则返回false + return false; //失败,返回false + } + + return true; //成功则返回true + } + + private class NoteData { //定义一个基本的便签内容的数据类,主要包含文本数据和电话号码数据 + private long mTextDataId; //文本数据id + + private ContentValues mTextDataValues; //.文本数据内容 + + private long mCallDataId; //电话数据id + + private ContentValues mCallDataValues; //便签的电话号码数据 + + private static final String TAG = "NoteData"; //默认构造函数 + + public NoteData() { // NoteData的构造函数,初始化四个变量 + mTextDataValues = new ContentValues(); //初始化一个文本数据,储存文本 + mCallDataValues = new ContentValues(); //初始化一个电话号码数据,为了储存电话号码 + mTextDataId = 0; //初始化文本数据ID,置为0 + mCallDataId = 0; //初始化电话号码ID,置为0 + } + + boolean isLocalModified() { //判断文本数据是否改变,是返回true,否返回false + return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; + } + + void setTextDataId(long id) { //设置文本数据ID号 + if(id <= 0) { // 对textDataId设置,但是不允许ID小于等于0 + throw new IllegalArgumentException("Text data id should larger than 0"); //ID号默认大于0 + } + mTextDataId = id; //设置电话号码数据ID号 + } + + void setCallDataId(long id) { // 设置呼叫数据ID,若传入参数小于0,则抛出参数错误的异常 + if (id <= 0) { + throw new IllegalArgumentException("Call data id should larger than 0"); //.电话号码数据ID应大于0 + } + mCallDataId = id; //设置电话号码的属性值 + } + + void setCallData(String key, String value) { //设置电话号码数据内容,并且保存修改时间 + mCallDataValues.put(key, value); //写入内容数据 + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); //设置修改时间为系统当前时间 + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); + } + + void setTextData(String key, String value) { //设置数据库中的文本数据 + mTextDataValues.put(key, value); //写入参数key,value + mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); //设置属性值为1 + mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); //设置修改时间为当前系统时间 + } + + Uri pushIntoContentResolver(Context context, long noteId) { //使用uri将数据添加到数据库 + /** + * Check for safety + */ + if (noteId <= 0) { //.判断ID是否非法 + throw new IllegalArgumentException("Wrong note id:" + noteId); //如果ID非法抛出异常,显示错误ID + } + + ArrayList operationList = new ArrayList(); + ContentProviderOperation.Builder builder = null; //数据库的操作列表 + + if(mTextDataValues.size() > 0) { //将文本的数据存入DataColums的数据结构中 + mTextDataValues.put(DataColumns.NOTE_ID, noteId); //将文本数据ID传入文本数据库 + if (mTextDataId == 0) { //文本数据ID为零,则此ID是新建默认的ID + mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); //写入拓展类型 + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mTextDataValues); //uri内容接收器插入文本数据库,放在Notes.CONTENT_DATA_URI的路径下 + try { // 尝试设置文本数据ID + setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + Log.e(TAG, "Insert new text data fail with noteId" + noteId); // 插入数据失败 + mTextDataValues.clear(); //将电话数据加入DataColums的数据结构中,并加入数据库 + return null; + } + } else { + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( //更新builder对象,追加uri数据和文本ID + Notes.CONTENT_DATA_URI, mTextDataId)); //将uri和id合并后,更新 + builder.withValues(mTextDataValues); //操作列表里添加build操作 + operationList.add(builder.build()); + } + mTextDataValues.clear(); //同步完毕之后,把更改的版本删除 + } + + if(mCallDataValues.size() > 0) { + mCallDataValues.put(DataColumns.NOTE_ID, noteId); // 写入noteID + if (mCallDataId == 0) { //将电话ID设置为uri提供的ID + mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mCallDataValues); + try { //异常检测,出现异常则清空电话号码的ID + setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + Log.e(TAG, "Insert new call data fail with noteId" + noteId); //插入新的电话号码数据时出错 + mCallDataValues.clear(); + return null; + } + } else { //当电话号码不为新建时,更新电话号码ID + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mCallDataId)); + builder.withValues(mCallDataValues); + operationList.add(builder.build()); //存储过程中的异常处理 + } + mCallDataValues.clear(); + } + + if (operationList.size() > 0) { //存储过程中如果遇到异常,通过如下进行处理 + try { + ContentProviderResult[] results = context.getContentResolver().applyBatch( //Android源码中对通讯录的操作,应用端使用ContentProvider提供的applyBatch,进行批量处理通讯录的联系人入库 + Notes.AUTHORITY, operationList); + return (results == null || results.length == 0 || results[0] == null) ? null //完成后返回一个URI + : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); + } catch (RemoteException e) { //异常检测,若出现异常则写回日志 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); // 异常日志 + return null; + } catch (OperationApplicationException e) { + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); // 异常日志 + return null; + } + } + return null; + } + } +} diff --git a/doc/蒋欣萍精读部分/NoteItemData.java b/doc/蒋欣萍精读部分/NoteItemData.java new file mode 100644 index 0000000..6f737fd --- /dev/null +++ b/doc/蒋欣萍精读部分/NoteItemData.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// 许可证使用声明 +package net.micode.notes.ui; //类NoteItemData包含在包net.micode.notes.ui里面 + +import android.content.Context; //引入了一系列的功能包以便实现这个类的相关功能 +import android.database.Cursor; +import android.text.TextUtils; + +import net.micode.notes.data.Contact; +import net.micode.notes.data.Notes; +import net.micode.notes.data.Notes.NoteColumns; //便签栏 +import net.micode.notes.tool.DataUtils; + + +public class NoteItemData { //存储了很多note有关的属性、常用变量 + static final String [] PROJECTION = new String [] { //将便签id,提醒时间,背景颜色id,创建时间,关联桌面挂件,修改时间,便签数量,父文件夹id,文件夹id(便签的一段内容),便签的种类,桌面挂件的id,桌面挂件的类型的名称放在一个PROJECTION的字符串数组里 + NoteColumns.ID, //每个便签的序号ID + NoteColumns.ALERTED_DATE, // 警示的日期设置 + NoteColumns.BG_COLOR_ID, //背景颜色的id + NoteColumns.CREATED_DATE, // 创建的时间 + NoteColumns.HAS_ATTACHMENT, //是否有附件。如果是一个text note,它不会有附件,如果是一个多媒体附件,会有至少一个附件 + NoteColumns.MODIFIED_DATE, //修改日期 + NoteColumns.NOTES_COUNT, //便签数量 + NoteColumns.PARENT_ID, + NoteColumns.SNIPPET, //文件夹名称或者文本注释内容 + NoteColumns.TYPE, + NoteColumns.WIDGET_ID, //小挂件的序号 + NoteColumns.WIDGET_TYPE, //小挂件的类型 + }; + + private static final int ID_COLUMN = 0; //声明类属性,包括背景颜色、手机号码等 + private static final int ALERTED_DATE_COLUMN = 1; + private static final int BG_COLOR_ID_COLUMN = 2; + private static final int CREATED_DATE_COLUMN = 3; + private static final int HAS_ATTACHMENT_COLUMN = 4; + private static final int MODIFIED_DATE_COLUMN = 5; + private static final int NOTES_COUNT_COLUMN = 6; + private static final int PARENT_ID_COLUMN = 7; + private static final int SNIPPET_COLUMN = 8; + private static final int TYPE_COLUMN = 9; + private static final int WIDGET_ID_COLUMN = 10; + private static final int WIDGET_TYPE_COLUMN = 11; + + private long mId; //PROJECT的字符串名称对应的值 + private long mAlertDate; + private int mBgColorId; + private long mCreatedDate; + private boolean mHasAttachment; + private long mModifiedDate; + private int mNotesCount; + private long mParentId; + private String mSnippet; + private int mType; + private int mWidgetId; // 宽度 + private int mWidgetType; //宽度形式 + private String mName; + private String mPhoneNumber; + + private boolean mIsLastItem; //布尔类型,判断是否为最后一项 + private boolean mIsFirstItem; + private boolean mIsOnlyOneItem; //判断是否只有一个便签,或者一个文件夹 + private boolean mIsOneNoteFollowingFolder; //布尔类型 判断便签下是否只有一个文件夹 + private boolean mIsMultiNotesFollowingFolder; + + public NoteItemData(Context context, Cursor cursor) { //初始化NoteItemData利用光标和context获取的内容 + mId = cursor.getLong(ID_COLUMN); //gettype:获取指定数据,并以type类型传回 + mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); + mBgColorId = cursor.getInt(BG_COLOR_ID_COLUMN); + mCreatedDate = cursor.getLong(CREATED_DATE_COLUMN); + mHasAttachment = (cursor.getInt(HAS_ATTACHMENT_COLUMN) > 0) ? true : false; //判断行列 + mModifiedDate = cursor.getLong(MODIFIED_DATE_COLUMN); + mNotesCount = cursor.getInt(NOTES_COUNT_COLUMN); + mParentId = cursor.getLong(PARENT_ID_COLUMN); + mSnippet = cursor.getString(SNIPPET_COLUMN); //获得字符串 + mSnippet = mSnippet.replace(NoteEditActivity.TAG_CHECKED, "").replace( //把每项前的方框符号和✔符号去掉 + NoteEditActivity.TAG_UNCHECKED, ""); + mType = cursor.getInt(TYPE_COLUMN); + mWidgetId = cursor.getInt(WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(WIDGET_TYPE_COLUMN); + + mPhoneNumber = ""; //初始化电话号码的信息 + if (mParentId == Notes.ID_CALL_RECORD_FOLDER) { + mPhoneNumber = DataUtils.getCallNumberByNoteId(context.getContentResolver(), mId); //使用DataUtils类中定义的函数获取电话号码信息 + if (!TextUtils.isEmpty(mPhoneNumber)) { //如果mPhoneNumber变量不等于空string,即这个note的PhoneNumber数据是有效的 + mName = Contact.getContact(context, mPhoneNumber); //mphonenumber里有符合字符串,则用contart功能连接 + if (mName == null) { + mName = mPhoneNumber; //如果没保存名字,就以电话号码命名 + } + } + } + + if (mName == null) { //如果没有对name复制成功,则把name设置为空值 + mName = ""; + } + checkPostion(cursor); //检查光标位置 + } + + private void checkPostion(Cursor cursor) { //根据光标位置设置标记 + mIsLastItem = cursor.isLast() ? true : false; //分别为各种描述状态的变量进行赋值 + mIsFirstItem = cursor.isFirst() ? true : false; + mIsOnlyOneItem = (cursor.getCount() == 1); + mIsMultiNotesFollowingFolder = false; //初始化“多重子文件”“单一子文件”2个标记 + mIsOneNoteFollowingFolder = false; + + if (mType == Notes.TYPE_NOTE && !mIsFirstItem) { //如果是note格式并且不是第一个元素,则获取光标位置并根据上一行信息更改标记 + int position = cursor.getPosition(); //获取光标位置 + if (cursor.moveToPrevious()) { //获取光标位置并看向上一行 + if (cursor.getInt(TYPE_COLUMN) == Notes.TYPE_FOLDER + || cursor.getInt(TYPE_COLUMN) == Notes.TYPE_SYSTEM) { //判断光标是否满足系统或便签格式 + if (cursor.getCount() > (position + 1)) { //若数据行数大于当前位置+1,则为多重文件。否则,单一文件 + mIsMultiNotesFollowingFolder = true; + } else { + mIsOneNoteFollowingFolder = true; + } + } + if (!cursor.moveToNext()) { //若光标不能重新向下走则报错 + throw new IllegalStateException("cursor move to previous but can't move back"); + } + } + } + } + + public boolean isOneFollowingFolder() { // 下面一系列函数都是返回状态值等,用于判断状态 + return mIsOneNoteFollowingFolder; + } + + public boolean isMultiFollowingFolder() { //若数据父id为保存至文件夹模式的id且满足电话号码单元不为空,则isCallRecord为true + return mIsMultiNotesFollowingFolder; + } + + public boolean isLast() { //判断是否是最后一个项 + return mIsLastItem; + } + + public String getCallName() { //获得便签名 + return mName; + } + + public boolean isFirst() { //判断是否是第一个项 + return mIsFirstItem; + } + + public boolean isSingle() { // 判断是否只有一个项 + return mIsOnlyOneItem; + } + + public long getId() { //获得对应的ID值 + return mId; + } + + public long getAlertDate() { //获取设置的提醒时间 + return mAlertDate; + } + + public long getCreatedDate() { //获得创建的时间 + return mCreatedDate; + } + + public boolean hasAttachment() { //判断是否与桌面挂件相关 + return mHasAttachment; + } + + public long getModifiedDate() { //获得修改的时间 + return mModifiedDate; + } + + public int getBgColorId() { //获得背景颜色的索引 + return mBgColorId; + } + + public long getParentId() { //获得父进程的id + return mParentId; + } + + public int getNotesCount() { //获得便签数量 + return mNotesCount; + } + + public long getFolderId () { // 获取文件夹id + return mParentId; + } + + public int getType() { // 获得项的类型 + return mType; + } + + public int getWidgetType() { //获得桌面挂件的类型 + return mWidgetType; + } + + public int getWidgetId() { //获得获得桌面挂件id + return mWidgetId; + } + + public String getSnippet() { //获取便签的外观片段 + return mSnippet; + } + + public boolean hasAlert() { //判读此便签是否有提醒 + return (mAlertDate > 0); + } + + public boolean isCallRecord() { //判断便签项是否为CallRecord + return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); //判断是否为电话记录。如果类型匹配,且文本部位空,则表明是电话记录,返回真。否则,返回假 + } + + public static int getNoteType(Cursor cursor) { //获得便签的类型 + return cursor.getInt(TYPE_COLUMN); + } +} diff --git a/doc/蒋欣萍精读部分/ResourceParser.java b/doc/蒋欣萍精读部分/ResourceParser.java new file mode 100644 index 0000000..c871143 --- /dev/null +++ b/doc/蒋欣萍精读部分/ResourceParser.java @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.tool; //定义了包名 + +import android.content.Context; //引用便签所需要的各个库 +import android.preference.PreferenceManager; // 引入了需要使用的类 + +import net.micode.notes.R; +import net.micode.notes.ui.NotesPreferenceActivity; //导入ui包下的类 + +public class ResourceParser { //界面元素的解析工具类:获取颜色资源,字体资源,图片资源并且在手机中使用 + //对不同颜色的静态常量进行赋值,便于使用 + public static final int YELLOW = 0; //为颜色静态常量赋值 + public static final int BLUE = 1; //定义默认颜色为Yellow + public static final int WHITE = 2; //为字体大小静态常量赋值 + public static final int GREEN = 3; //默认字体大小为Medium + public static final int RED = 4; //对对应的颜色资源索取它们的地址 + + public static final int BG_DEFAULT_COLOR = YELLOW; //默认背景颜色是黄色 + + public static final int TEXT_SMALL = 0; //声明字体大小变量 + public static final int TEXT_MEDIUM = 1; + public static final int TEXT_LARGE = 2; + public static final int TEXT_SUPER = 3; + + public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; // 默认字体大小是中等大小 + + public static class NoteBgResources { //便签背景资源的获取 + private final static int [] BG_EDIT_RESOURCES = new int [] { + R.drawable.edit_yellow, + R.drawable.edit_blue, + R.drawable.edit_white, + R.drawable.edit_green, + R.drawable.edit_red + }; + + private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { // 标题颜色的使用情况 + R.drawable.edit_title_yellow, + R.drawable.edit_title_blue, + R.drawable.edit_title_white, + R.drawable.edit_title_green, + R.drawable.edit_title_red + }; + + public static int getNoteBgResource(int id) { //获取便签背景资源id + return BG_EDIT_RESOURCES[id]; + } + + public static int getNoteTitleBgResource(int id) { //获取背景标题资源id + return BG_EDIT_TITLE_RESOURCES[id]; + } + } + + public static int getDefaultBgId(Context context) { //获取默认背景颜色对应id + if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( //若为随机背景颜色,则返回随机背景颜色 + NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { + return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); + } else { + return BG_DEFAULT_COLOR; + } + } + + public static class NoteItemBgResources { //便签项目背景资源子类,包括方法:获得首尾项目等背景资源 + private final static int [] BG_FIRST_RESOURCES = new int [] { //对不同drawable的变量(first、normal、last、single)的初始化(声明) + R.drawable.list_yellow_up, + R.drawable.list_blue_up, + R.drawable.list_white_up, + R.drawable.list_green_up, + R.drawable.list_red_up + }; + + private final static int [] BG_NORMAL_RESOURCES = new int [] { //定义了背景的默认资源 + R.drawable.list_yellow_middle, + R.drawable.list_blue_middle, + R.drawable.list_white_middle, + R.drawable.list_green_middle, + R.drawable.list_red_middle + }; + + private final static int [] BG_LAST_RESOURCES = new int [] { //定义背景的下方资源 + R.drawable.list_yellow_down, + R.drawable.list_blue_down, + R.drawable.list_white_down, + R.drawable.list_green_down, + R.drawable.list_red_down, + }; + + private final static int [] BG_SINGLE_RESOURCES = new int [] { + R.drawable.list_yellow_single, + R.drawable.list_blue_single, + R.drawable.list_white_single, + R.drawable.list_green_single, + R.drawable.list_red_single + }; //根据id获取四种类型便签项目背景资源的方法 + + public static int getNoteBgFirstRes(int id) { //获取四种类型便签项目背景资源的方法 + return BG_FIRST_RESOURCES[id]; + } + + public static int getNoteBgLastRes(int id) { // 通过ID寻找last的颜色值 + return BG_LAST_RESOURCES[id]; + } + + public static int getNoteBgSingleRes(int id) { //通过ID获取单个便签背景颜色资源 + return BG_SINGLE_RESOURCES[id]; + } + + public static int getNoteBgNormalRes(int id) { //通过ID寻找normal的颜色值 + return BG_NORMAL_RESOURCES[id]; + } + + public static int getFolderBgRes() { //设置窗口的资源 + return R.drawable.list_folder; + } + } + + public static class WidgetBgResources { // 获取图片资源类的定义 + private final static int [] BG_2X_RESOURCES = new int [] { //2x小窗口背景资源初始化 + R.drawable.widget_2x_yellow, + R.drawable.widget_2x_blue, + R.drawable.widget_2x_white, + R.drawable.widget_2x_green, + R.drawable.widget_2x_red, + }; + + public static int getWidget2xBgResource(int id) { //通过id获得2x的小窗口背景资源 + return BG_2X_RESOURCES[id]; + } + + private final static int [] BG_4X_RESOURCES = new int [] { //4x小窗口背景资源初始化 + R.drawable.widget_4x_yellow, + R.drawable.widget_4x_blue, + R.drawable.widget_4x_white, + R.drawable.widget_4x_green, + R.drawable.widget_4x_red + }; + + public static int getWidget4xBgResource(int id) { //通过id获得4x的小窗口背景资源 + return BG_4X_RESOURCES[id]; + } + } + + public static class TextAppearanceResources { //文本外观资源,包括默认字体,以及获取资源大小 + private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { //四种不同大小的字体 + R.style.TextAppearanceNormal, + R.style.TextAppearanceMedium, + R.style.TextAppearanceLarge, + R.style.TextAppearanceSuper + }; + + public static int getTexAppearanceResource(int id) { //检测ID是否大于字体大小资源总量,如果是返回默认的结果,如果不是,则返回大小的ID号 + /** + * HACKME: Fix bug of store the resource id in shared preference. //修补bug + * The id may larger than the length of resources, in this case, + * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} + */ + if (id >= TEXTAPPEARANCE_RESOURCES.length) { + return BG_DEFAULT_FONT_SIZE; + } + return TEXTAPPEARANCE_RESOURCES[id]; + } + + public static int getResourcesSize() { //返回字体大小资源的长度 + return TEXTAPPEARANCE_RESOURCES.length; + } + } +} diff --git a/doc/蒋欣萍精读部分/WorkingNote.java b/doc/蒋欣萍精读部分/WorkingNote.java new file mode 100644 index 0000000..578dc12 --- /dev/null +++ b/doc/蒋欣萍精读部分/WorkingNote.java @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) //当前活动便签项 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.micode.notes.model; //设置包 + +import android.appwidget.AppWidgetManager; //该文件调用的其他类 +import android.content.ContentUris; +import android.content.Context; +import android.database.Cursor; //导入其它用来调用的类 +import android.text.TextUtils; +import android.util.Log; + +import net.micode.notes.data.Notes; //小米便签操作的整体属性 +import net.micode.notes.data.Notes.CallNote; +import net.micode.notes.data.Notes.DataColumns; +import net.micode.notes.data.Notes.DataConstants; +import net.micode.notes.data.Notes.NoteColumns; +import net.micode.notes.data.Notes.TextNote; +import net.micode.notes.tool.ResourceParser.NoteBgResources; + + +public class WorkingNote { //设置一个WorkingNote类,包含一些正在进行中的note的属性 + // Note for the working note + private Note mNote; //声明一个Note类型的变量 + // Note Id + private long mNoteId; //声明便签content + // Note content + private String mContent; //声明便签mode + // Note mode + private int mMode; //判断是否为清单模式 + + private long mAlertDate; // 设置闹钟时间 + + private long mModifiedDate; //最后一次修改的时间 + + private int mBgColorId; //背景颜色所对应的ID号 + + private int mWidgetId; //桌面挂件所对应的ID + + private int mWidgetType; //桌面挂件的格式 + + private long mFolderId; //文件夹所对应的ID + + private Context mContext; //当前便签的上下文 + + private static final String TAG = "WorkingNote"; //.声明 一个叫做DATA_PROJECTION字符串数组 + + private boolean mIsDeleted; //是否应该被删除 + + private NoteSettingChangedListener mNoteSettingStatusListener; //判断便签设置值是否改变的监听器 + + public static final String[] DATA_PROJECTION = new String[] { //声明 NOTE_PROJECTION字符串数组 + DataColumns.ID, + DataColumns.CONTENT, + DataColumns.MIME_TYPE, + DataColumns.DATA1, + DataColumns.DATA2, + DataColumns.DATA3, + DataColumns.DATA4, + }; + + public static final String[] NOTE_PROJECTION = new String[] { //保存便签属性信息的string数组 + NoteColumns.PARENT_ID, + NoteColumns.ALERTED_DATE, + NoteColumns.BG_COLOR_ID, + NoteColumns.WIDGET_ID, + NoteColumns.WIDGET_TYPE, + NoteColumns.MODIFIED_DATE + }; //设置数据在哪一列 + + private static final int DATA_ID_COLUMN = 0; //以下定义的整形是上述两个列表中各元素的索引 + + private static final int DATA_CONTENT_COLUMN = 1; + + private static final int DATA_MIME_TYPE_COLUMN = 2; + + private static final int DATA_MODE_COLUMN = 3; + + private static final int NOTE_PARENT_ID_COLUMN = 0; //. 以下6个常量表示便签投影的0-5列 + + private static final int NOTE_ALERTED_DATE_COLUMN = 1; + + private static final int NOTE_BG_COLOR_ID_COLUMN = 2; + + private static final int NOTE_WIDGET_ID_COLUMN = 3; + + private static final int NOTE_WIDGET_TYPE_COLUMN = 4; + + private static final int NOTE_MODIFIED_DATE_COLUMN = 5; + + // New note construct + private WorkingNote(Context context, long folderId) { //.声明一个新的note construct + mContext = context; //构造函数声明 + mAlertDate = 0; //默认提醒日期为0 + mModifiedDate = System.currentTimeMillis(); //获取系统当前时间的方法,返回当前时间 + mFolderId = folderId; //默认最后一次修改日期为当前时间 + mNote = new Note(); //加载一个已存在的便签 + mNoteId = 0; + mIsDeleted = false; + mMode = 0; + mWidgetType = Notes.TYPE_WIDGET_INVALIDE; + } + + // Existing note construct + private WorkingNote(Context context, long noteId, long folderId) { //载入便签 + mContext = context; //通过数据库调用query函数找到第一个条目 + mNoteId = noteId; + mFolderId = folderId; + mIsDeleted = false; + mNote = new Note(); + loadNote(); //加载便签 + } + + private void loadNote() { //输出mNoteId的所有属性值,比如位置信息、颜色信息、控件信息等 + Cursor cursor = mContext.getContentResolver().query( //判断是否存储相应信息 + ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, + null, null); + + if (cursor != null) { //若存在,则存储相应信息 + if (cursor.moveToFirst()) { //通过判断cursor.moveToFirst()的值为true或false来确定查询结果是否为空 + mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); //获取文档的属性 + mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); //关闭cursor游标 + mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); + mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); + mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); + mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); + } + cursor.close(); //不存在时返回错误信息 + } else { //否则说明不存在这个便签,加载错误 + Log.e(TAG, "No note with id:" + mNoteId); //未能找到此note,返回异常 + throw new IllegalArgumentException("Unable to find note with id " + mNoteId); //.抛出异常,找不到NoteID + } + loadNoteData(); // 调用方法loadNoteData,导入便签的内容。 + } + + private void loadNoteData() { //加载NoteData + Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, //调用query函数查找到便签ID为mNoteId的位置,并将光标移动到该位置 + DataColumns.NOTE_ID + "=?", new String[] { + String.valueOf(mNoteId) + }, null); //如果找到的信息不为空,就把内容反馈给用户 + + + if (cursor != null) { //光标存在时,将光标移动到便签的起始位置 + if (cursor.moveToFirst()) { //通过判断cursor.moveToFirst()的值为true或false来确定查询结果是否为空 + do { + String type = cursor.getString(DATA_MIME_TYPE_COLUMN); + if (DataConstants.NOTE.equals(type)) { + mContent = cursor.getString(DATA_CONTENT_COLUMN); + mMode = cursor.getInt(DATA_MODE_COLUMN); + mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); + } else if (DataConstants.CALL_NOTE.equals(type)) { + mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); + } else { + Log.d(TAG, "Wrong note type with type:" + type); + } + } while (cursor.moveToNext()); + } + cursor.close(); + } else { //否则说明不存在这个便签,加载错误 + Log.e(TAG, "No data with id:" + mNoteId); //未能找到此note,返回异常 + throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); //抛出异常,找不到NoteID + } + } + + public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, //创建一个新便签的构造函数 + int widgetType, int defaultBgColorId) { + WorkingNote note = new WorkingNote(context, folderId); //创建一个新的包含文件ID和内容的便签 + note.setBgColorId(defaultBgColorId); //设置背景颜色 + note.setWidgetId(widgetId); // 设定布局 + note.setWidgetType(widgetType); //设置窗口类型 + return note; + } + + public static WorkingNote load(Context context, long id) { //导入一个新的正在写入的便签 + return new WorkingNote(context, id, 0); //返回便签 + } + + public synchronized boolean saveNote() { //保存便签,成功保存返回true,否则返回false + if (isWorthSaving()) { //判断是否有价值去保存 + if (!existInDatabase()) { //判断是否存在数据库中 + if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { //没有成功创建便签则记录异常日志 + Log.e(TAG, "Create new note fail with id:" + mNoteId); + return false; + } + } + + mNote.syncNote(mContext, mNoteId); //同步便签内容及便签id + + /** + * Update widget content if there exist any widget of this note + */ + if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID //判断窗口大小是否变化,如果变化也要保存这个变化 + && mWidgetType != Notes.TYPE_WIDGET_INVALIDE + && mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onWidgetChanged(); + } + return true; + } else { + return false; + } + } + + public boolean existInDatabase() { //判断便签是否已经存在于数据库中,mNoteID >0时存在,返回true,否则返回false + return mNoteId > 0; + } + + private boolean isWorthSaving() { //判断是否有保存的必要性 + if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) //已被删除或者不在数据库中但是是空便签或者已经在数据库中但本地没有修改过,都不保存 + || (existInDatabase() && !mNote.isLocalModified())) { + return false; + } else { + return true; //其余情况,要保存,返回true + } + } + + public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { //设置监听“设置状态改变” + mNoteSettingStatusListener = l; + } + + public void setAlertDate(long date, boolean set) { //设置提醒日期 + if (date != mAlertDate) { //若 mAlertDate与data不同,则更改mAlertDate并设定NoteValue + mAlertDate = date; //为设置的日期打标签 + mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); + } + if (mNoteSettingStatusListener != null) { //判断是否为空 + mNoteSettingStatusListener.onClockAlertChanged(date, set); + } + } + + public void markDeleted(boolean mark) { //判断是否为空 + mIsDeleted = mark; //设定标记 + if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID + && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onWidgetChanged(); //调用mNoteSettingStatusListener的 onWidgetChanged方法 + } + } //调用mNoteSettingStatusListener的 onWidgetChanged方法 + + public void setBgColorId(int id) { //设定背景颜色 + if (id != mBgColorId) { //判断并更新背景颜色 + mBgColorId = id; + if (mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onBackgroundColorChanged(); + } + mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); + } + } + + public void setCheckListMode(int mode) { //设置检查列表模式 + if (mMode != mode) { //.当mMode和mode不相同时进行设定 + if (mNoteSettingStatusListener != null) { + mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); //设定之后更改mMode + } + mMode = mode; + mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); //储存mode记录的文本数据 + } + } + + public void setWidgetType(int type) { //设置窗口类型 + if (type != mWidgetType) { + mWidgetType = type; //调用Note的setNoteValue方法更改WidgetType + mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); + } + } + + public void setWidgetId(int id) { //设置窗口编号 + if (id != mWidgetId) { //判断传入是否与当前id一样,否则更改为传入id + mWidgetId = id; + mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); + } //调用Note的setNoteValue方法更改WidgetId + } + + public void setWorkingText(String text) { //设定WorkingText + if (!TextUtils.equals(mContent, text)) { // 判断文本内容是否相同,否则更新文本 + mContent = text; //调用Note的setTextData方法更改WorkingText + mNote.setTextData(DataColumns.CONTENT, mContent); + } + } + + public void convertToCallNote(String phoneNumber, long callDate) { //转换成电话提醒的便签 + mNote.setCallData(CallNote.CALL_DATE, String.valueOf(callDate)); + mNote.setCallData(CallNote.PHONE_NUMBER, phoneNumber); + mNote.setNoteValue(NoteColumns.PARENT_ID, String.valueOf(Notes.ID_CALL_RECORD_FOLDER)); + } + + public boolean hasClockAlert() { //检测是否有时钟提醒,mAlertDate > 0返回真,否则返回假 + return (mAlertDate > 0 ? true : false); + } + + public String getContent() { //获取便签内容 + return mContent; + } + + public long getAlertDate() { //获取待提醒日期 + return mAlertDate; + } + + public long getModifiedDate() { //获取修改之后的日期 + return mModifiedDate; + } + + public int getBgColorResId() { //获取背景颜色id + return NoteBgResources.getNoteBgResource(mBgColorId); + } + + public int getBgColorId() { //获取背景颜色id + return mBgColorId; + } + + public int getTitleBgResId() { //获取标题背景颜色id + return NoteBgResources.getNoteTitleBgResource(mBgColorId); + } + + public int getCheckListMode() { //获取检查列表模式 + return mMode; + } + + public long getNoteId() { //获取便签编号 + return mNoteId; + } + + public long getFolderId() { //获取所在文件夹编号 + return mFolderId; + } + + public int getWidgetId() { //获取窗口编号 + return mWidgetId; + } + + public int getWidgetType() { //创建接口 NoteSettingChangedListener,便签更新监视; +为NoteEditActivity提供接口 + return mWidgetType; + } + + public interface NoteSettingChangedListener { //监听便签设置是否改变 + /** + * Called when the background color of current note has just changed + */ + void onBackgroundColorChanged(); //背景颜色改变按钮 + + /** + * Called when user set clock + */ + void onClockAlertChanged(long date, boolean set); //提醒时间按钮,可进行时间的更改和提醒的开关 + + /** + * Call when user create note from widget + */ + void onWidgetChanged(); //窗口改变 + + /** + * Call when switch between check list mode and normal mode + * @param oldMode is previous mode before change + * @param newMode is new mode + */ + void onCheckListModeChanged(int oldMode, int newMode); //列表检查模式改变 + } +}