diff --git a/cwj-daimafenxi.docx b/cwj-daimafenxi.docx deleted file mode 100644 index bf64f6e..0000000 Binary files a/cwj-daimafenxi.docx and /dev/null differ diff --git a/doc/小米便签开源代码的泛读报告.docx b/doc/小米便签开源代码的泛读报告.docx new file mode 100644 index 0000000..5e10332 Binary files /dev/null and b/doc/小米便签开源代码的泛读报告.docx differ diff --git a/doc/小米便签开源代码的质量分析.docx b/doc/小米便签开源代码的质量分析.docx new file mode 100644 index 0000000..22f6f91 Binary files /dev/null and b/doc/小米便签开源代码的质量分析.docx differ diff --git a/gtask.data.Node&Sqldata.txt b/gtask.data.Node&Sqldata.txt deleted file mode 100644 index ee02c0e..0000000 --- a/gtask.data.Node&Sqldata.txt +++ /dev/null @@ -1,284 +0,0 @@ -这段代码主要是定义了一个节点类 Node,其中包含了一些常量、成员变量和方法,用于表示节点的属性和同步操作。 - -package net.micode.notes.gtask.data; //指定了该类所在的java包为gtask.data - -import android.database.Cursor; //导入了 Android 框架中的 Cursor 类,用于在数据库中进行数据检索。 - -import org.json.JSONObject; //导入了 JSON 库中的 JSONObject 类,用于处理 JSON 数据。 - - -public abstract class Node { //定义了一个抽象类 Node,表示一个节点。 - public static final int SYNC_ACTION_NONE = 0; -//定义了一个名为 SYNC_ACTION_NONE 的常量,值为 0,表示同步操作为无。 - - public static final int SYNC_ACTION_ADD_REMOTE = 1; //定义常量,表示远程添加同步操作。 - - public static final int SYNC_ACTION_ADD_LOCAL = 2; //表示本地添加同步操作。 - - public static final int SYNC_ACTION_DEL_REMOTE = 3;//表示远程删除同步操作。 - - public static final int SYNC_ACTION_DEL_LOCAL = 4; //表示本地删除同步操作。 - - public static final int SYNC_ACTION_UPDATE_REMOTE = 5; //表示远程更新同步操作。 - - public static final int SYNC_ACTION_UPDATE_LOCAL = 6; //表示本地更新同步操作。 - - public static final int SYNC_ACTION_UPDATE_CONFLICT = 7; //表示更新冲突同步操作。 - - public static final int SYNC_ACTION_ERROR = 8; //表示同步操作错误。 - - private String mGid; //声明了一个私有成员变量 mGid,用于存储节点的全局唯一标识符。 - - private String mName; //声明了一个私有成员变量 mName,用于存储节点的名称。 - - private long mLastModified; //声明了一个私有成员变量 mLastModified,用于存储节点的最后修改时间。 - - private boolean mDeleted; //声明了一个私有成员变量 mDeleted,用于表示节点是否被删除。 - - public Node() { //定义了 Node 类的构造函数,初始化成员变量。 - mGid = null; - mName = ""; - mLastModified = 0; - mDeleted = false; - } - - public abstract JSONObject getCreateAction(int actionId); -//声明了一个抽象方法 getCreateAction(),用于获取创建节点的同步操作。 - - public abstract JSONObject getUpdateAction(int actionId); -//声明 getUpdateAction(),用于获取更新节点的同步操作。 - - public abstract void setContentByRemoteJSON(JSONObject js); -//声明 setContentByRemoteJSON(),用于根据远程 JSON 数据设置节点内容。 - - public abstract void setContentByLocalJSON(JSONObject js); -//声明了 setContentByLocalJSON(),用于根据本地 JSON 数据设置节点内容。 - - public abstract JSONObject getLocalJSONFromContent(); -//声明了一个抽象方法 getLocalJSONFromContent(),用于从节点内容获取本地 JSON 数据。 - - public abstract int getSyncAction(Cursor c); -//声明了一个抽象方法 getSyncAction(),用于从 Cursor 中获取同步操作。 - - public void setGid(String gid) { //定义了一个公有方法 setGid(),用于设置节点的全局唯一标识符。 - this.mGid = gid; - } - - public void setName(String name) { //定义了一个公有方法 setName(),用于设置节点的名称。 - this.mName = name; - } - - public void setLastModified(long lastModified) { //定义了一个公有方法 setLastModified(),用于设置节点的最后修改时间。 - this.mLastModified = lastModified; - } - - public void setDeleted(boolean deleted) { //定义了一个公有方法 setDeleted(),用于设置节点是否被删除。 - this.mDeleted = deleted; - } - - public String getGid() { //定义了一个公有方法 getGid(),用于获取节点的全局唯一标识符。 - return this.mGid; - } - - public String getName() { //定义了一个公有方法 getName(),用于获取节点的名称。 - return this.mName; - } - - public long getLastModified() { //定义了一个公有方法 getLastModified(),用于获取节点的最后修改时间。 - return this.mLastModified; - } - - public boolean getDeleted() { //定义了一个公有方法 getDeleted(),用于获取节点是否被删除。 - return this.mDeleted; - } - -} - - - - - - - - - -package net.micode.notes.gtask.data; - -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.util.Log; - -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 net.micode.notes.data.NotesDatabaseHelper.TABLE; -import net.micode.notes.gtask.exception.ActionFailureException; - -import org.json.JSONException; -import org.json.JSONObject; -//以上import导入了所需的Android类和自定义异常,以及用于处理JSON数据的类。 - -public class SqlData { //定义了一个名为 SqlData 的类。 -private static final String TAG = SqlData.class.getSimpleName(); -//声明了一个私有静态常量 TAG,用于在日志中标识类的名称。 - - private static final int INVALID_ID = -99999; -//声明了一个私有静态常量 INVALID_ID,用于表示无效的ID值。 - - public static final String[] PROJECTION_DATA = new String[] { - DataColumns.ID, DataColumns.MIME_TYPE, DataColumns.CONTENT, DataColumns.DATA1, - DataColumns.DATA3 - }; //这是一个字符串数组 PROJECTION_DATA,用于指定要在查询数据时返回的列。 - - public static final int DATA_ID_COLUMN = 0; - - public static final int DATA_MIME_TYPE_COLUMN = 1; - - public static final int DATA_CONTENT_COLUMN = 2; - - public static final int DATA_CONTENT_DATA_1_COLUMN = 3; - - public static final int DATA_CONTENT_DATA_3_COLUMN = 4; -//以上声明了一组公有静态常量,表示数据列在查询结果中的索引。 - - private ContentResolver mContentResolver; - - private boolean mIsCreate; - - private long mDataId; - - private String mDataMimeType; - - private String mDataContent; - - private long mDataContentData1; - - private String mDataContentData3; - - private ContentValues mDiffDataValues; //声明了一些私有成员变量,用于存储数据的相关信息。 - - public SqlData(Context context) { //定义了 SqlData 类的构造函数,接受一个 Context 参数。 - mContentResolver = context.getContentResolver(); - mIsCreate = true; - mDataId = INVALID_ID; - mDataMimeType = DataConstants.NOTE; - mDataContent = ""; - mDataContentData1 = 0; - mDataContentData3 = ""; - mDiffDataValues = new ContentValues(); - } //在构造函数中对成员变量进行初始化 - - public SqlData(Context context, Cursor c) { //定义了另一个构造函数,接受一个 Context 和一个 Cursor 参数。 - mContentResolver = context.getContentResolver(); - mIsCreate = false; - loadFromCursor(c); - mDiffDataValues = new ContentValues(); - } //在第二个构造函数中对成员变量进行初始化,并调用 loadFromCursor() 方法加载数据。 - - private void loadFromCursor(Cursor c) { //定义了一个私有方法 loadFromCursor(),接受一个 Cursor 参数。 - mDataId = c.getLong(DATA_ID_COLUMN); - mDataMimeType = c.getString(DATA_MIME_TYPE_COLUMN); - mDataContent = c.getString(DATA_CONTENT_COLUMN); - mDataContentData1 = c.getLong(DATA_CONTENT_DATA_1_COLUMN); - mDataContentData3 = c.getString(DATA_CONTENT_DATA_3_COLUMN); - } //从 Cursor 中读取数据,并将其存储到相应的成员变量中。 - - public void setContent(JSONObject js) throws JSONException { - //定义了一个公有方法 setContent(),接受一个 JSONObject 参数,并可能抛出 JSONException 异常。 - - long dataId = js.has(DataColumns.ID) ? js.getLong(DataColumns.ID) : INVALID_ID; - if (mIsCreate || mDataId != dataId) { - mDiffDataValues.put(DataColumns.ID, dataId); - } - mDataId = dataId; - //从 JSON 对象中读取数据,并将其存储到相应的成员变量中。 - - String dataMimeType = js.has(DataColumns.MIME_TYPE) ? js.getString(DataColumns.MIME_TYPE) - : DataConstants.NOTE; - if (mIsCreate || !mDataMimeType.equals(dataMimeType)) { - mDiffDataValues.put(DataColumns.MIME_TYPE, dataMimeType); - } - mDataMimeType = dataMimeType; - - String dataContent = js.has(DataColumns.CONTENT) ? js.getString(DataColumns.CONTENT) : ""; - if (mIsCreate || !mDataContent.equals(dataContent)) { - mDiffDataValues.put(DataColumns.CONTENT, dataContent); - } - mDataContent = dataContent; - - long dataContentData1 = js.has(DataColumns.DATA1) ? js.getLong(DataColumns.DATA1) : 0; - if (mIsCreate || mDataContentData1 != dataContentData1) { - mDiffDataValues.put(DataColumns.DATA1, dataContentData1); - } - mDataContentData1 = dataContentData1; - - String dataContentData3 = js.has(DataColumns.DATA3) ? js.getString(DataColumns.DATA3) : ""; - if (mIsCreate || !mDataContentData3.equals(dataContentData3)) { - mDiffDataValues.put(DataColumns.DATA3, dataContentData3); - } - mDataContentData3 = dataContentData3; - } //从 JSON 对象中读取数据,并将其存储到相应的成员变量中。 - - public JSONObject getContent() throws JSONException { //定义了一个公有方法 getContent(),可能抛出 JSONException 异常。 - if (mIsCreate) { - Log.e(TAG, "it seems that we haven't created this in database yet"); - return null; - } - JSONObject js = new JSONObject(); - js.put(DataColumns.ID, mDataId); - js.put(DataColumns.MIME_TYPE, mDataMimeType); - js.put(DataColumns.CONTENT, mDataContent); - js.put(DataColumns.DATA1, mDataContentData1); - js.put(DataColumns.DATA3, mDataContentData3); - return js; - } //根据成员变量的值创建一个 JSON 对象,并返回 - - public void commit(long noteId, boolean validateVersion, long version) { //定义了一个公有方法 commit(),接受三个参数。 - - if (mIsCreate) { - if (mDataId == INVALID_ID && mDiffDataValues.containsKey(DataColumns.ID)) { - mDiffDataValues.remove(DataColumns.ID); - } - - mDiffDataValues.put(DataColumns.NOTE_ID, noteId); - Uri uri = mContentResolver.insert(Notes.CONTENT_DATA_URI, mDiffDataValues); - try { - mDataId = Long.valueOf(uri.getPathSegments().get(1)); - } catch (NumberFormatException e) { - Log.e(TAG, "Get note id error :" + e.toString()); - throw new ActionFailureException("create note failed"); - } - } else { - if (mDiffDataValues.size() > 0) { - int result = 0; - if (!validateVersion) { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, null, null); - } else { - result = mContentResolver.update(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mDataId), mDiffDataValues, - " ? in (SELECT " + NoteColumns.ID + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.VERSION + "=?)", new String[] { - String.valueOf(noteId), String.valueOf(version) - }); - } - if (result == 0) { - Log.w(TAG, "there is no update. maybe user updates note when syncing"); - } - } - } -//根据条件执行插入或更新操作。 - mDiffDataValues.clear(); - mIsCreate = false; - } -//清除变更数据并将 mIsCreate 设置为 false。 - public long getId() { - return mDataId; - } -} - diff --git a/gtask.data.txt b/gtask.data.txt deleted file mode 100644 index 9762a8b..0000000 --- a/gtask.data.txt +++ /dev/null @@ -1,96 +0,0 @@ -**********************MetaData*********** -/* - * 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.gtask.data; //包 - -//导入所需的类 -import android.database.Cursor; //处理数据库查询的Cursor类 -import android.util.Log; //日志记录类Log - -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONException; -import org.json.JSONObject; - - -public class MetaData extends Task //声明MetaData类,这个类extends了Task类,即继承了Task类的所有属性和方法 -{ - private final static String TAG = MetaData.class.getSimpleName(); - //定义了一个私有静态常量字符串 TAG,用于标识日志记录的来源。TAG 的值是 MetaData 类的简单名称 - - private String mRelatedGid = null; - //声明了一个私有字符串变量 mRelatedGid,用于存储关联的 GID(Google 任务 ID) - - public void setMeta(String gid, JSONObject metaInfo) { - //定义了一个公共方法 setMeta,接受两个参数:一个字符串 gid 和一个 JSONObject metaInfo - try { - metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); - } catch (JSONException e) { - Log.e(TAG, "failed to put related gid"); - } - //通过调用 JSONObject 的 put 方法,将 GID 存储到传入的 metaInfo 中。如果出现 JSON 解析异常,则记录错误日志,failed to put related gid - - setNotes(metaInfo.toString()); - setName(GTaskStringUtils.META_NOTE_NAME); - } - //然后,将转换后的 metaInfo 对象转换为字符串,并将其设置为任务的注释(notes),同时设置任务的名称为预定义的 META_NOTE_NAME。 - - public String getRelatedGid() { - return mRelatedGid; //定义公共方法 getRelatedGid,用于获取关联的 GID - } - - @Override - public boolean isWorthSaving() { - return getNotes() != null; - } - //重写了父类的方法 isWorthSaving,用于判断任务是否值得保存。如果任务的注释不为 null,则返回 true - - @Override - public void setContentByRemoteJSON(JSONObject js) { - //重写了父类的方法 setContentByRemoteJSON,用于从远程 JSON 数据设置任务的内容 - - super.setContentByRemoteJSON(js); //首先调用父类的方法来设置任务的内容 - if (getNotes() != null) { - try { - JSONObject metaInfo = new JSONObject(getNotes().trim()); - mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); - } catch (JSONException e) { - Log.w(TAG, "failed to get related gid"); - mRelatedGid = null; - } - } //然后,从任务的注释中提取关联的 GID,如果提取失败则记录警告日志"failed to get related gid" - } - - @Override - public void setContentByLocalJSON(JSONObject js) { - // this function should not be called - throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); - } - //重写了父类的方法 setContentByLocalJSON,但是抛出了一个非法访问错误,表示这个方法不应该被调用 - - @Override - public JSONObject getLocalJSONFromContent() { - throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); - } -//重写了父类的方法 getLocalJSONFromContent,也抛出了一个非法访问错误。 - - @Override - public int getSyncAction(Cursor c) { - throw new IllegalAccessError("MetaData:getSyncAction should not be called"); - } -//重写了父类的方法 getSyncAction,同样抛出了一个非法访问错误。 -} diff --git a/gtask.data前三个文件夹代码修改及类图.docx b/gtask.data前三个文件夹代码修改及类图.docx deleted file mode 100644 index e220841..0000000 Binary files a/gtask.data前三个文件夹代码修改及类图.docx and /dev/null differ diff --git a/src/123.puml b/src/123.puml deleted file mode 100644 index ca249b2..0000000 --- a/src/123.puml +++ /dev/null @@ -1,68 +0,0 @@ -@startuml -'https://plantuml.com/class-diagram - -public class Contact { - - // 缓存联系人信息,键为电话 号码,值为联系人姓名 - private static HashMap sContactCache; - private static final String TAG = "Contact"; - - // 定义字符串CALLER_ID_SELECTION - // 用于查询联系人信息的选择条件 - 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(); - } - - // 如果缓存中已包含该电话号码对应的联系人姓名,则直接返回姓名 - if(sContactCache.containsKey(phoneNumber)) { - return sContactCache.get(phoneNumber); - } - - // 构建查询条件 - String selection = CALLER_ID_SELECTION.replace("+", - PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); - - // 查询联系人信息 - Cursor cursor = context.getContentResolver().query( - Data.CONTENT_URI, - new String [] { Phone.DISPLAY_NAME }, - selection, - new String[] { phoneNumber }, - null); - - // 处理查询结果 - // moveToFirst()返回第一条 - 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; - } - } -} - -@enduml \ No newline at end of file diff --git a/untitled.iml b/untitled.iml deleted file mode 100644 index 9e40e9e..0000000 --- a/untitled.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/小米标签及案例/SE0.2 Git介绍及使用.pptx b/小米标签及案例/SE0.2 Git介绍及使用.pptx deleted file mode 100644 index 584f717..0000000 Binary files a/小米标签及案例/SE0.2 Git介绍及使用.pptx and /dev/null differ diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/Contact.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/Contact.java index e5bda02..a68fd3b 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/Contact.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/Contact.java @@ -14,10 +14,11 @@ * limitations under the License. */ -package net.micode.notes.data; +package net.micode.notes.data;//包 -import android.content.Context; -import android.database.Cursor; +//导入所需的类 +import android.database.Cursor; //处理数据库查询的Cursor类 +import android.util.Log; //日志记录类Log import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Data; import android.telephony.PhoneNumberUtils; diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/NotesProvider.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/NotesProvider.java index ee8701f..2a24bce 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/NotesProvider.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/data/NotesProvider.java @@ -16,7 +16,6 @@ package net.micode.notes.data; - import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentUris; @@ -33,17 +32,21 @@ import net.micode.notes.R; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.NotesDatabaseHelper.TABLE; - - +//为存储和获取数据提供接口。可以在不同的应用程序之间共享数据 +//ContentProvider提供的方法 +//query:查询 +//insert:插入 +//update:更新 +//delete:删除 +//getType:得到数据类型 public class NotesProvider extends ContentProvider { + // UriMatcher用于匹配Uri private static final UriMatcher mMatcher; private NotesDatabaseHelper mHelper; private static final String TAG = "NotesProvider"; - private static final String URL = "Unknown URI "; - private static final int URI_NOTE = 1; private static final int URI_NOTE_ITEM = 2; private static final int URI_DATA = 3; @@ -53,7 +56,9 @@ public class NotesProvider extends ContentProvider { private static final int URI_SEARCH_SUGGEST = 6; static { + // 创建UriMatcher时,调用UriMatcher(UriMatcher.NO_MATCH)表示不匹配任何路径的返回码 mMatcher = new UriMatcher(UriMatcher.NO_MATCH); + // 把需要匹配Uri路径全部给注册上 mMatcher.addURI(Notes.AUTHORITY, "note", URI_NOTE); mMatcher.addURI(Notes.AUTHORITY, "note/#", URI_NOTE_ITEM); mMatcher.addURI(Notes.AUTHORITY, "data", URI_DATA); @@ -67,33 +72,40 @@ public class NotesProvider extends ContentProvider { * x'0A' represents the '\n' character in sqlite. For title and content in the search result, * we will trim '\n' and white space in order to show more information. */ + // 声明 NOTES_SEARCH_PROJECTION private static final String NOTES_SEARCH_PROJECTION = NoteColumns.ID + "," - + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," - + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," - + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," - + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," - + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; - + + NoteColumns.ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA + "," + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_1 + "," + + "TRIM(REPLACE(" + NoteColumns.SNIPPET + ", x'0A','')) AS " + SearchManager.SUGGEST_COLUMN_TEXT_2 + "," + + R.drawable.search_result + " AS " + SearchManager.SUGGEST_COLUMN_ICON_1 + "," + + "'" + Intent.ACTION_VIEW + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_ACTION + "," + + "'" + Notes.TextNote.CONTENT_TYPE + "' AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA; + // 声明NOTES_SNIPPET_SEARCH_QUERY private static String NOTES_SNIPPET_SEARCH_QUERY = "SELECT " + NOTES_SEARCH_PROJECTION - + " FROM " + TABLE.NOTE - + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" - + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER - + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; + + " FROM " + TABLE.NOTE + + " WHERE " + NoteColumns.SNIPPET + " LIKE ?" + + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE; @Override + // Context只有在onCreate()中才被初始化 + // 对mHelper进行实例化 public boolean onCreate() { mHelper = NotesDatabaseHelper.getInstance(getContext()); return true; } @Override + // 查询uri在数据库中对应的位置 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, - String sortOrder) { + String sortOrder) { Cursor c = null; + // 获取可读数据库 SQLiteDatabase db = mHelper.getReadableDatabase(); String id = null; + // 匹配查找uri switch (mMatcher.match(uri)) { + // 对于不同的匹配值,在数据库中查找相应的条目 case URI_NOTE: c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, sortOrder); @@ -115,6 +127,7 @@ public class NotesProvider extends ContentProvider { case URI_SEARCH: case URI_SEARCH_SUGGEST: if (sortOrder != null || projection != null) { + // 不合法的参数异常 throw new IllegalArgumentException( "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); } @@ -122,6 +135,8 @@ public class NotesProvider extends ContentProvider { String searchString = null; if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { if (uri.getPathSegments().size() > 1) { + // getPathSegments()方法得到一个String的List, + // 在uri.getPathSegments().get(1)为第2个元素 searchString = uri.getPathSegments().get(1); } } else { @@ -141,7 +156,8 @@ public class NotesProvider extends ContentProvider { } break; default: - throw new IllegalArgumentException(URL+ uri); + // 抛出异常 + throw new IllegalArgumentException("Unknown URI " + uri); } if (c != null) { c.setNotificationUri(getContext().getContentResolver(), uri); @@ -150,13 +166,17 @@ public class NotesProvider extends ContentProvider { } @Override + // 插入一个uri public Uri insert(Uri uri, ContentValues values) { + // 获得可写的数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); long dataId = 0, noteId = 0, insertedId = 0; switch (mMatcher.match(uri)) { + // 新增一个条目 case URI_NOTE: insertedId = noteId = db.insert(TABLE.NOTE, null, values); break; + // 如果存在,查找NOTE_ID case URI_DATA: if (values.containsKey(DataColumns.NOTE_ID)) { noteId = values.getAsLong(DataColumns.NOTE_ID); @@ -166,9 +186,10 @@ public class NotesProvider extends ContentProvider { insertedId = dataId = db.insert(TABLE.DATA, null, values); break; default: - throw new IllegalArgumentException(URL + uri); + throw new IllegalArgumentException("Unknown URI " + uri); } // Notify the note uri + // notifyChange获得一个ContextResolver对象并且更新里面的内容 if (noteId > 0) { getContext().getContentResolver().notifyChange( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); @@ -180,13 +201,17 @@ public class NotesProvider extends ContentProvider { ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); } + // 返回插入的uri的路径 return ContentUris.withAppendedId(uri, insertedId); } @Override + // 删除一个uri public int delete(Uri uri, String selection, String[] selectionArgs) { + //Uri代表要操作的数据,Android上可用的每种资源 -包括 图像、视频片段、音频资源等都可以用Uri来表示。 int count = 0; String id = null; + // 获得可写的数据库 SQLiteDatabase db = mHelper.getWritableDatabase(); boolean deleteData = false; switch (mMatcher.match(uri)) { @@ -230,6 +255,7 @@ public class NotesProvider extends ContentProvider { } @Override + // 更新一个uri public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { int count = 0; String id = null; @@ -269,10 +295,12 @@ public class NotesProvider extends ContentProvider { return count; } + // 将字符串解析成规定格式 private String parseSelection(String selection) { return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); } + //增加一个noteVersion private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { StringBuilder sql = new StringBuilder(120); sql.append("UPDATE "); @@ -285,7 +313,7 @@ public class NotesProvider extends ContentProvider { sql.append(" WHERE "); } if (id > 0) { - sql.append(NoteColumns.ID + "=" + id); + sql.append(NoteColumns.ID + "=" + String.valueOf(id)); } if (!TextUtils.isEmpty(selection)) { String selectString = id > 0 ? parseSelection(selection) : selection; @@ -295,6 +323,7 @@ public class NotesProvider extends ContentProvider { sql.append(selectString); } + // execSQL()方法可以执行insert、delete、update和CREATE TABLE之类有更改行为的SQL语句 mHelper.getWritableDatabase().execSQL(sql.toString()); } @@ -304,4 +333,4 @@ public class NotesProvider extends ContentProvider { return null; } -} +} \ No newline at end of file diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/data/MetaData.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/data/MetaData.java index 8e7d3d4..47a86c5 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/data/MetaData.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/data/MetaData.java @@ -16,19 +16,22 @@ package net.micode.notes.gtask.data; -import android.database.Cursor; -import android.util.Log; +//导入所需的类 +import android.database.Cursor; //处理数据库查询的Cursor类 +import android.util.Log; //日志记录类Log import net.micode.notes.tool.GTaskStringUtils; import org.json.JSONException; import org.json.JSONObject; - +//声明MetaData类,这个类extends了Task类,即继承了Task类的所有属性和方法 public class MetaData extends Task { - private static final String TAG = MetaData.class.getSimpleName(); + private final static String TAG = MetaData.class.getSimpleName(); + //定义了一个私有静态常量字符串 TAG,用于标识日志记录的来源。TAG 的值是 MetaData 类的简单名称 private String mRelatedGid = null; + //声明了一个私有字符串变量 mRelatedGid,用于存储关联的 GID(Google 任务 ID) public void setMeta(String gid, JSONObject metaInfo) { try { diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java index b3b61e7..692f5f5 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskASyncTask.java @@ -16,7 +16,7 @@ */ package net.micode.notes.gtask.remote; - +//异步操作类,实现GTask的异步操作过程 import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -56,13 +56,13 @@ public class GTaskASyncTask extends AsyncTask { public void cancelSync() { mTaskManager.cancelSync(); } - + // 发布进度单位,系统将会调用onProgressUpdate()方法更新这些值 public void publishProgess(String message) { publishProgress(new String[] { message }); } - + //向用户提示当前同步的状态,是一个用于交互的方法 private void showNotification(int tickerId, String content) { Notification notification = new Notification(R.drawable.notification, mContext .getString(tickerId), System.currentTimeMillis()); @@ -72,32 +72,32 @@ public class GTaskASyncTask extends AsyncTask { if (tickerId != R.string.ticker_success) { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesPreferenceActivity.class), 0); - +// 调用系统自带灯光 } else { pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(mContext, NotesListActivity.class), 0); - } + }// 点击清除按钮或点击通知后会自动消失 notification.setLatestEventInfo(mContext, mContext.getString(R.string.app_name), content, pendingIntent); mNotifiManager.notify(GTASK_SYNC_NOTIFICATION_ID, notification); } - + //一个描述了想要启动一个Activity、Broadcast或是Service的意图 @Override protected Integer doInBackground(Void... unused) { publishProgess(mContext.getString(R.string.sync_progress_login, NotesPreferenceActivity .getSyncAccountName(mContext))); return mTaskManager.sync(mContext, this); } - + //用于在执行完后台任务后更新UI,显示结果 @Override protected void onProgressUpdate(String... progress) { showNotification(R.string.ticker_syncing, progress[0]); - if (mContext instanceof GTaskSyncService) { + if (mContext instanceof GTaskSyncService) {//设置最新同步的时间 ((GTaskSyncService) mContext).sendBroadcast(progress[0]); } } - - @Override + //如果同步不成功,那么从系统取得一个用于启动一个NotesPreferenceActivity的PendingIntent对象 + @Override//几种不同情况下的结果显示 protected void onPostExecute(Integer result) { if (result == GTaskManager.STATE_SUCCESS) { showNotification(R.string.ticker_success, mContext.getString( @@ -110,11 +110,11 @@ public class GTaskASyncTask extends AsyncTask { } else if (result == GTaskManager.STATE_SYNC_CANCELLED) { showNotification(R.string.ticker_cancel, mContext .getString(R.string.error_sync_cancelled)); - } + }//这里好像是方法内的一个线程,但是并不太懂什么意思 if (mOnCompleteListener != null) { new Thread(new Runnable() { - public void run() { + public void run() {//完成后的操作,使用onComplete()将所有值都重新初始化,相当于完成一次操作 mOnCompleteListener.onComplete(); } }).start(); diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java index f5979a1..4209749 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskClient.java @@ -1,70 +1,13 @@ -/* - * 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.gtask.remote; -import android.accounts.Account; -import android.accounts.AccountManager; -import android.accounts.AccountManagerFuture; -import android.app.Activity; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.gtask.data.Node; -import net.micode.notes.gtask.data.Task; -import net.micode.notes.gtask.data.TaskList; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.gtask.exception.NetworkFailureException; -import net.micode.notes.tool.GTaskStringUtils; -import net.micode.notes.ui.NotesPreferenceActivity; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.LinkedList; -import java.util.List; -import java.util.zip.GZIPInputStream; -import java.util.zip.Inflater; -import java.util.zip.InflaterInputStream; - - +/* + * 主要功能:实现GTASK的登录操作,进行GTASK任务的创建,创建任务列表,从网络上获取任务和任务列表的内容 + * 主要使用类或技术:accountManager JSONObject HttpParams authToken Gid + */ public class GTaskClient { private static final String TAG = GTaskClient.class.getSimpleName(); - private static final String GTASK_URL = "https://mail.google.com/tasks/"; + private static final String GTASK_URL = "https://mail.google.com/tasks/"; //这个是指定的URL private static final String GTASK_GET_URL = "https://mail.google.com/tasks/ig"; @@ -102,6 +45,10 @@ public class GTaskClient { mUpdateArray = null; } + /*用来获取的实例化对象 + * 使用 getInstance() + * 返回mInstance这个实例化对象 + */ public static synchronized GTaskClient getInstance() { if (mInstance == null) { mInstance = new GTaskClient(); @@ -109,42 +56,50 @@ public class GTaskClient { return mInstance; } + /*用来实现登录操作的函数,传入的参数是一个Activity + * 设置登录操作限制时间,如果超时则需要重新登录 + * 有两种登录方式,使用用户自己的URL登录或者使用谷歌官方的URL登录 + * 返回true或者false,即最后是否登陆成功 + */ public boolean login(Activity activity) { // we suppose that the cookie would expire after 5 minutes // then we need to re-login - final long interval = 1000 * 60 * 5; + //判断距离最后一次登录操作是否超过5分钟 + final long interval = 1000 * 60 * 5; //1000毫秒×60×5 if (mLastLoginTime + interval < System.currentTimeMillis()) { mLoggedin = false; } - // need to re-login after account switch + // need to re-login after account switch 重新登录操作 if (mLoggedin && !TextUtils.equals(getSyncAccount().name, NotesPreferenceActivity - .getSyncAccountName(activity))) { + .getSyncAccountName(activity))) { mLoggedin = false; } + //如果没超过时间,则不需要重新登录 if (mLoggedin) { Log.d(TAG, "already logged in"); return true; } - mLastLoginTime = System.currentTimeMillis(); - String authToken = loginGoogleAccount(activity, false); + mLastLoginTime = System.currentTimeMillis();//更新最后登录时间,改为系统当前的时间 + String authToken = loginGoogleAccount(activity, false);//判断是否登录到谷歌账户 if (authToken == null) { Log.e(TAG, "login google account failed"); return false; } // login with custom domain if necessary - if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() + //尝试使用用户自己的域名登录 + if (!(mAccount.name.toLowerCase().endsWith("gmail.com") || mAccount.name.toLowerCase() //将用户账号名改为统一格式(小写)后判断是否为一个谷歌账号地址 .endsWith("googlemail.com"))) { StringBuilder url = new StringBuilder(GTASK_URL).append("a/"); int index = mAccount.name.indexOf('@') + 1; String suffix = mAccount.name.substring(index); url.append(suffix + "/"); - mGetUrl = url.toString() + "ig"; - mPostUrl = url.toString() + "r/ig"; + mGetUrl = url.toString() + "ig"; //设置用户对应的getUrl + mPostUrl = url.toString() + "r/ig"; //设置用户对应的postUrl if (tryToLoginGtask(activity, authToken)) { mLoggedin = true; @@ -152,6 +107,7 @@ public class GTaskClient { } // try to login with google official url + //如果用户账户无法登录,则使用谷歌官方的URI进行登录 if (!mLoggedin) { mGetUrl = GTASK_GET_URL; mPostUrl = GTASK_POST_URL; @@ -164,10 +120,15 @@ public class GTaskClient { return true; } + /*具体实现登录谷歌账户的方法 + * 使用令牌机制 + * 使用AccountManager来管理注册账号 + * 返回值是账号的令牌 + */ private String loginGoogleAccount(Activity activity, boolean invalidateToken) { - String authToken; - AccountManager accountManager = AccountManager.get(activity); - Account[] accounts = accountManager.getAccountsByType("com.google"); + String authToken; //令牌,是登录操作保证安全性的一个方法 + AccountManager accountManager = AccountManager.get(activity);//AccountManager这个类给用户提供了集中注册账号的接口 + Account[] accounts = accountManager.getAccountsByType("com.google");//获取全部以com.google结尾的account if (accounts.length == 0) { Log.e(TAG, "there is no available google account"); @@ -176,6 +137,7 @@ public class GTaskClient { String accountName = NotesPreferenceActivity.getSyncAccountName(activity); Account account = null; + //遍历获得的accounts信息,寻找已经记录过的账户信息 for (Account a : accounts) { if (a.name.equals(accountName)) { account = a; @@ -190,11 +152,13 @@ public class GTaskClient { } // get the token now + //获取选中账号的令牌 AccountManagerFuture accountManagerFuture = accountManager.getAuthToken(account, "goanna_mobile", null, activity, null, null); try { Bundle authTokenBundle = accountManagerFuture.getResult(); authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN); + //如果是invalidateToken,那么需要调用invalidateAuthToken(String, String)方法废除这个无效token if (invalidateToken) { accountManager.invalidateAuthToken("com.google", authToken); loginGoogleAccount(activity, false); @@ -207,10 +171,12 @@ public class GTaskClient { return authToken; } + //尝试登陆Gtask,这只是一个预先判断令牌是否是有效以及是否能登上GTask的方法,而不是具体实现登陆的方法 private boolean tryToLoginGtask(Activity activity, String authToken) { if (!loginGtask(authToken)) { - // maybe the auth token is out of date, now let's invalidate the + // maybe the auth token is out of authTokedate, now let's invalidate the // token and try again + //删除过一个无效的authToken,申请一个新的后再次尝试登陆 authToken = loginGoogleAccount(activity, true); if (authToken == null) { Log.e(TAG, "login google account failed"); @@ -225,25 +191,27 @@ public class GTaskClient { return true; } + //实现登录GTask的具体操作 private boolean loginGtask(String authToken) { int timeoutConnection = 10000; - int timeoutSocket = 15000; - HttpParams httpParameters = new BasicHttpParams(); - HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection); - HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket); + int timeoutSocket = 15000; //socket是一种通信连接实现数据的交换的端口 + HttpParams httpParameters = new BasicHttpParams(); //实例化一个新的HTTP参数类 + HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);//设置连接超时时间 + HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);//设置设置端口超时时间 mHttpClient = new DefaultHttpClient(httpParameters); - BasicCookieStore localBasicCookieStore = new BasicCookieStore(); + BasicCookieStore localBasicCookieStore = new BasicCookieStore(); //设置本地cookie mHttpClient.setCookieStore(localBasicCookieStore); HttpProtocolParams.setUseExpectContinue(mHttpClient.getParams(), false); // login gtask try { - String loginUrl = mGetUrl + "?auth=" + authToken; - HttpGet httpGet = new HttpGet(loginUrl); + String loginUrl = mGetUrl + "?auth=" + authToken; //设置登录的url + HttpGet httpGet = new HttpGet(loginUrl); //通过登录的uri实例化网页上资源的查找 HttpResponse response = null; response = mHttpClient.execute(httpGet); // get the cookie now + //获取CookieStore里存放的cookie,看如果存有“GTL(不知道什么意思)”,则说明有验证成功的有效的cookie List cookies = mHttpClient.getCookieStore().getCookies(); boolean hasAuthCookie = false; for (Cookie cookie : cookies) { @@ -256,6 +224,7 @@ public class GTaskClient { } // get the client version + //获取client的内容,具体操作是在返回的Content中截取从_setup(开始到)}中间的字符串内容,也就是gtask_url的内容 String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -284,6 +253,10 @@ public class GTaskClient { return mActionId++; } + /*实例化创建一个用于向网络传输数据的对象 + * 使用HttpPost类 + * 返回一个httpPost实例化对象,但里面还没有内容 + */ private HttpPost createHttpPost() { HttpPost httpPost = new HttpPost(mPostUrl); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"); @@ -291,29 +264,30 @@ public class GTaskClient { return httpPost; } + /*通过URL获取响应后返回的数据,也就是网络上的数据和资源 + * 使用getContentEncoding()获取网络上的资源和数据 + * 返回值就是获取到的资源 + */ private String getResponseContent(HttpEntity entity) throws IOException { String contentEncoding = null; - if (entity.getContentEncoding() != null) { + if (entity.getContentEncoding() != null) {//通过URL得到HttpEntity对象,如果不为空则使用getContent()方法创建一个流将数据从网络都过来 contentEncoding = entity.getContentEncoding().getValue(); Log.d(TAG, "encoding: " + contentEncoding); } - InputStream input = entity.getContent(); - - if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) { + if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {//GZIP是使用DEFLATE进行压缩数据的另一个压缩库 input = new GZIPInputStream(entity.getContent()); - } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) { + } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {//DEFLATE是一个无专利的压缩算法,它可以实现无损数据压缩 Inflater inflater = new Inflater(true); input = new InflaterInputStream(entity.getContent(), inflater); } - + try { InputStreamReader isr = new InputStreamReader(input); - BufferedReader br = new BufferedReader(isr); + BufferedReader br = new BufferedReader(isr);//是一个包装类,它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了时候,再读入内存,是为了提供读的效率而设计的 StringBuilder sb = new StringBuilder(); - try { while (true) { String buff = br.readLine(); if (buff == null) { @@ -326,20 +300,28 @@ public class GTaskClient { } } + /*通过JSON发送请求 + * 请求的具体内容在json的实例化对象js中然后传入 + * 利用UrlEncodedFormEntity entity和httpPost.setEntity(entity)方法把js中的内容放置到httpPost中 + * 执行请求后使用getResponseContent方法得到返回的数据和资源 + * 将资源再次放入json后返回 + */ private JSONObject postRequest(JSONObject js) throws NetworkFailureException { - if (!mLoggedin) { + if (!mLoggedin) {//未登录 Log.e(TAG, "please login first"); throw new ActionFailureException("not logged in"); } + //实例化一个httpPost的对象用来向服务器传输数据,在这里就是发送请求,而请求的内容在js里 HttpPost httpPost = createHttpPost(); try { - LinkedList list = new LinkedList<>(); + LinkedList list = new LinkedList(); list.add(new BasicNameValuePair("r", js.toString())); - UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); + UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, "UTF-8"); //UrlEncodedFormEntity()的形式比较单一,是普通的键值对 httpPost.setEntity(entity); // execute the post + //执行这个请求 HttpResponse response = mHttpClient.execute(httpPost); String jsString = getResponseContent(response.getEntity()); return new JSONObject(jsString); @@ -363,6 +345,12 @@ public class GTaskClient { } } + /*创建单个任务 + * 传入参数是一个.gtask.data.Task包里Task类的对象 + * 利用json获取Task里的内容,并且创建相应的jsPost + * 利用postRequest得到任务的返回信息 + * 使用task.setGid设置task的new_ID + */ public void createTask(Task task) throws NetworkFailureException { commitUpdate(); try { @@ -389,6 +377,9 @@ public class GTaskClient { } } + /* + * 创建一个任务列表,与createTask几乎一样,区别就是最后设置的是tasklist的gid + */ public void createTaskList(TaskList tasklist) throws NetworkFailureException { commitUpdate(); try { @@ -415,6 +406,11 @@ public class GTaskClient { } } + /* + * 同步更新操作 + * 使用JSONObject进行数据存储,使用jsPost.put,Put的信息包括UpdateArray和ClientVersion + * 使用postRequest发送这个jspost,进行处理 + */ public void commitUpdate() throws NetworkFailureException { if (mUpdateArray != null) { try { @@ -436,6 +432,10 @@ public class GTaskClient { } } + /* + * 添加更新的事项 + * 调用commitUpdate()实现 + */ public void addUpdateNode(Node node) throws NetworkFailureException { if (node != null) { // too many update items may result in an error @@ -450,6 +450,12 @@ public class GTaskClient { } } + /* + * 移动task,比如讲task移动到不同的task列表中去 + * 通过getGid获取task所属列表的gid + * 通过JSONObject.put(String name, Object value)函数设置移动后的task的相关属性值,从而达到移动的目的 + * 最后还是通过postRequest进行更新后的发送 + */ public void moveTask(Task task, TaskList preParent, TaskList curParent) throws NetworkFailureException { commitUpdate(); @@ -466,15 +472,17 @@ public class GTaskClient { if (preParent == curParent && task.getPriorSibling() != null) { // put prioring_sibing_id only if moving within the tasklist and // it is not the first one + //设置优先级ID,只有当移动是发生在文件中 action.put(GTaskStringUtils.GTASK_JSON_PRIOR_SIBLING_ID, task.getPriorSibling()); } - action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); - action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); + action.put(GTaskStringUtils.GTASK_JSON_SOURCE_LIST, preParent.getGid()); //设置移动前所属列表 + action.put(GTaskStringUtils.GTASK_JSON_DEST_PARENT, curParent.getGid()); //设置当前所属列表 if (preParent != curParent) { // put the dest_list only if moving between tasklists action.put(GTaskStringUtils.GTASK_JSON_DEST_LIST, curParent.getGid()); } actionList.put(action); + //最后将ACTION_LIST加入到jsPost中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // client_version @@ -489,6 +497,11 @@ public class GTaskClient { } } + /* + * 删除操作节点 + * 还是利用JSON + * 删除过后使用postRequest发送删除后的结果 + */ public void deleteNode(Node node) throws NetworkFailureException { commitUpdate(); try { @@ -497,7 +510,7 @@ public class GTaskClient { // action_list node.setDeleted(true); - actionList.put(node.getUpdateAction(getActionId())); + actionList.put(node.getUpdateAction(getActionId())); //这里会获取到删除操作的ID,加入到actionLiast中 jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); // client_version @@ -512,6 +525,11 @@ public class GTaskClient { } } + /* + * 获取任务列表 + * 首先通过GetURI使用getResponseContent从网上获取数据 + * 然后筛选出"_setup("到)}的部分,并且从中获取GTASK_JSON_LISTS的内容返回 + */ public JSONArray getTaskLists() throws NetworkFailureException { if (!mLoggedin) { Log.e(TAG, "please login first"); @@ -524,6 +542,7 @@ public class GTaskClient { response = mHttpClient.execute(httpGet); // get the task list + //筛选工作,把筛选出的字符串放入jsString String resString = getResponseContent(response.getEntity()); String jsBegin = "_setup("; String jsEnd = ")}"; @@ -534,6 +553,7 @@ public class GTaskClient { jsString = resString.substring(begin + jsBegin.length(), end); } JSONObject js = new JSONObject(jsString); + //获取GTASK_JSON_LISTS return js.getJSONObject("t").getJSONArray(GTaskStringUtils.GTASK_JSON_LISTS); } catch (ClientProtocolException e) { Log.e(TAG, e.toString()); @@ -550,6 +570,9 @@ public class GTaskClient { } } + /* + * 通过传入的TASKList的gid,从网络上获取相应属于这个任务列表的任务 + */ public JSONArray getTaskList(String listGid) throws NetworkFailureException { commitUpdate(); try { @@ -561,7 +584,7 @@ public class GTaskClient { action.put(GTaskStringUtils.GTASK_JSON_ACTION_TYPE, GTaskStringUtils.GTASK_JSON_ACTION_TYPE_GETALL); action.put(GTaskStringUtils.GTASK_JSON_ACTION_ID, getActionId()); - action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); + action.put(GTaskStringUtils.GTASK_JSON_LIST_ID, listGid); //这里设置为传入的listGid action.put(GTaskStringUtils.GTASK_JSON_GET_DELETED, false); actionList.put(action); jsPost.put(GTaskStringUtils.GTASK_JSON_ACTION_LIST, actionList); @@ -582,7 +605,8 @@ public class GTaskClient { return mAccount; } + //重置更新的内容 public void resetUpdateArray() { mUpdateArray = null; } -} +} \ No newline at end of file diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java index 055a95e..7bf1d62 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskManager.java @@ -1,119 +1,73 @@ -/* - * 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.gtask.remote; -import android.app.Activity; -import android.content.ContentResolver; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.util.Log; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.gtask.data.MetaData; -import net.micode.notes.gtask.data.Node; -import net.micode.notes.gtask.data.SqlNote; -import net.micode.notes.gtask.data.Task; -import net.micode.notes.gtask.data.TaskList; -import net.micode.notes.gtask.exception.ActionFailureException; -import net.micode.notes.gtask.exception.NetworkFailureException; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.GTaskStringUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; - - public class GTaskManager { private static final String TAG = GTaskManager.class.getSimpleName(); - public static final int STATE_SUCCESS = 0; - public static final int STATE_NETWORK_ERROR = 1; - public static final int STATE_INTERNAL_ERROR = 2; - public static final int STATE_SYNC_IN_PROGRESS = 3; - public static final int STATE_SYNC_CANCELLED = 4; - private static GTaskManager mInstance = null; private Activity mActivity; - private Context mContext; - private ContentResolver mContentResolver; - private boolean mSyncing; - private boolean mCancelled; - private HashMap mGTaskListHashMap; - private HashMap mGTaskHashMap; - private HashMap mMetaHashMap; - private TaskList mMetaList; - private HashSet mLocalDeleteIdMap; - private HashMap mGidToNid; - private HashMap mNidToGid; - private GTaskManager() { - mSyncing = false; - mCancelled = false; - mGTaskListHashMap = new HashMap<>(); - mGTaskHashMap = new HashMap<>(); - mMetaHashMap = new HashMap<>(); + private GTaskManager() { //对象初始化函数 + mSyncing = false; //正在同步,flase代表未执行 + mCancelled = false; //全局标识,flase代表可以执行 + mGTaskListHashMap = new HashMap(); //<>代表Java的泛型,就是创建一个用类型作为参数的类。 + mGTaskHashMap = new HashMap(); + mMetaHashMap = new HashMap(); mMetaList = null; - mLocalDeleteIdMap = new HashSet<>(); - mGidToNid = new HashMap<>(); - mNidToGid = new HashMap<>(); + mLocalDeleteIdMap = new HashSet(); + mGidToNid = new HashMap(); //GoogleID to NodeID?? + mNidToGid = new HashMap(); //NodeID to GoogleID???通过hashmap散列表建立映射 } - public static synchronized GTaskManager getInstance() { + /** + * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。 + * 功能:类初始化函数 + * @author TTS + * @return GtaskManger + */ + public static synchronized GTaskManager getInstance() { //可能运行在多线程环境下,使用语言级同步--synchronized if (mInstance == null) { mInstance = new GTaskManager(); } return mInstance; } + /** + * 包含关键字synchronized,语言级同步,指明该函数可能运行在多线程的环境下。 + * @author TTS + * @param activity + */ public synchronized void setActivityContext(Activity activity) { - // used for getting authtoken + // used for getting auth token mActivity = activity; } - public int sync(Context context, GTaskASyncTask asyncTask) { + /** + * 核心函数 + * 功能:实现了本地同步操作和远端同步操作 + * @author TTS + * @param context-----获取上下文 + * @param asyncTask-------用于同步的异步操作类 + * @return int + */ + public int sync(Context context, GTaskASyncTask asyncTask) { //核心函数 if (mSyncing) { - Log.d(TAG, "Sync is in progress"); + Log.d(TAG, "Sync is in progress"); //创建日志文件(调试信息),debug return STATE_SYNC_IN_PROGRESS; } mContext = context; @@ -128,26 +82,27 @@ public class GTaskManager { mNidToGid.clear(); try { - GTaskClient client = GTaskClient.getInstance(); - client.resetUpdateArray(); + GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client--客户机 + client.resetUpdateArray(); //JSONArray类型,reset即置为NULL // login google task - - if (!mCancelled&&!client.login(mActivity)) { + if (!mCancelled) { + if (!client.login(mActivity)) { throw new NetworkFailureException("login google task failed"); } + } // get the task list from google asyncTask.publishProgess(mContext.getString(R.string.sync_progress_init_list)); - initGTaskList(); + initGTaskList(); //获取Google上的JSONtasklist转为本地TaskList // do content sync work asyncTask.publishProgess(mContext.getString(R.string.sync_progress_syncing)); syncContent(); - } catch (NetworkFailureException e) { - Log.e(TAG, e.toString()); + } catch (NetworkFailureException e) { //分为两种异常,此类异常为网络异常 + Log.e(TAG, e.toString()); //创建日志文件(调试信息),error return STATE_NETWORK_ERROR; - } catch (ActionFailureException e) { + } catch (ActionFailureException e) { //此类异常为操作异常 Log.e(TAG, e.toString()); return STATE_INTERNAL_ERROR; } catch (Exception e) { @@ -167,32 +122,41 @@ public class GTaskManager { return mCancelled ? STATE_SYNC_CANCELLED : STATE_SUCCESS; } + /** + *功能:初始化GtaskList,获取Google上的JSONtasklist转为本地TaskList。 + *获得的数据存储在mMetaList,mGTaskListHashMap,mGTaskHashMap + *@author TTS + *@exception NetworkFailureException + *@return void + */ private void initGTaskList() throws NetworkFailureException { if (mCancelled) return; - GTaskClient client = GTaskClient.getInstance(); + GTaskClient client = GTaskClient.getInstance(); //getInstance即为创建一个实例,client应指远端客户机 try { - JSONArray jsTaskLists = client.getTaskLists(); + //Json对象是Name Value对(即子元素)的无序集合,相当于一个Map对象。JsonObject类是bantouyan-json库对Json对象的抽象,提供操纵Json对象的各种方法。 + //其格式为{"key1":value1,"key2",value2....};key 必须是字符串。 + //因为ajax请求不刷新页面,但配合js可以实现局部刷新,因此json常常被用来作为异步请求的返回对象使用。 + JSONArray jsTaskLists = client.getTaskLists(); //原注释为get task list - // init meta list first - mMetaList = null; + // init meta list first初始化 + mMetaList = null; //TaskList类型 for (int i = 0; i < jsTaskLists.length(); i++) { - JSONObject object = jsTaskLists.getJSONObject(i); + JSONObject object = jsTaskLists.getJSONObject(i); //JSONObject与JSONArray一个为对象,一个为数组。此处取出单个JASONObject String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); - if (name - .equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { - mMetaList = new TaskList(); - mMetaList.setContentByRemoteJSON(object); + if (name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_META)) { + mMetaList = new TaskList(); //MetaList意为元表,Tasklist类型,此处为初始化 + mMetaList.setContentByRemoteJSON(object); //将JSON中部分数据复制到自己定义的对象中相对应的数据:name->mname... // load meta data - JSONArray jsMetas = client.getTaskList(gid); + JSONArray jsMetas = client.getTaskList(gid); //原注释为get action_list for (int j = 0; j < jsMetas.length(); j++) { object = (JSONObject) jsMetas.getJSONObject(j); - MetaData metaData = new MetaData(); + MetaData metaData = new MetaData(); //继承自Node metaData.setContentByRemoteJSON(object); - if (metaData.isWorthSaving()) { + if (metaData.isWorthSaving()) { //if not worth to save,metadata将不加入mMetaList 判断是否存入 mMetaList.addChildTask(metaData); if (metaData.getGid() != null) { mMetaHashMap.put(metaData.getRelatedGid(), metaData); @@ -210,21 +174,20 @@ public class GTaskManager { GTaskClient.getInstance().createTaskList(mMetaList); } - // init task list + // init task list初始化 for (int i = 0; i < jsTaskLists.length(); i++) { JSONObject object = jsTaskLists.getJSONObject(i); - String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); + String gid = object.getString(GTaskStringUtils.GTASK_JSON_ID); //通过getString函数传入本地某个标志数据的名称,获取其在远端的名称。 String name = object.getString(GTaskStringUtils.GTASK_JSON_NAME); if (name.startsWith(GTaskStringUtils.MIUI_FOLDER_PREFFIX) && !name.equals(GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_META)) { - TaskList tasklist = new TaskList(); + + GTaskStringUtils.FOLDER_META)) { + TaskList tasklist = new TaskList(); //继承自Node tasklist.setContentByRemoteJSON(object); mGTaskListHashMap.put(gid, tasklist); mGTaskHashMap.put(gid, tasklist); - - // load tasks + // load tasks加载 JSONArray jsTasks = client.getTaskList(gid); for (int j = 0; j < jsTasks.length(); j++) { object = (JSONObject) jsTasks.getJSONObject(j); @@ -244,556 +207,635 @@ public class GTaskManager { e.printStackTrace(); throw new ActionFailureException("initGTaskList: handing JSONObject failed"); } - } - - private void syncContent() throws NetworkFailureException { - int syncType; - String DESC = " DESC"; - Cursor c = null; - String gid; - Node node; - - mLocalDeleteIdMap.clear(); + /** + * 功能:本地内容同步操作 + * @throws NetworkFailureException + * @return 无返回值 + */ + private void syncContent() throws NetworkFailureException { //本地内容同步操作 + int syncType; + Cursor c = null; //数据库指针 + String gid; //GoogleID + Node node; //Node包含Sync_Action的不同类型 + + mLocalDeleteIdMap.clear(); //HashSet类型 + + if (mCancelled) { + return; + } - if (mCancelled) { - return; - } + // for local deleted note + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type<>? AND parent_id=?)", new String[] { + String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) + }, null); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); + } - // for local deleted note - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id=?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, null); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_DEL_REMOTE, node, c); + mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); } - - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); + } else { + Log.w(TAG, "failed to query trash folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; } - } else { - Log.w(TAG, "failed to query trash folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; } - } - // sync folder first - syncFolder(); + // sync folder first + syncFolder(); - // for note existing in database - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + DESC); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add - syncType = Node.SYNC_ACTION_ADD_REMOTE; + // for note existing in database + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type=? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_NOTE), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); //通过hashmap建立联系 + mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); //通过hashmap建立联系 + syncType = node.getSyncAction(c); } else { - // remote delete - syncType = Node.SYNC_ACTION_DEL_LOCAL; + if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { + // local add + syncType = Node.SYNC_ACTION_ADD_REMOTE; + } else { + // remote delete + syncType = Node.SYNC_ACTION_DEL_LOCAL; + } } + doContentSync(syncType, node, c); } - doContentSync(syncType, node, c); + } else { + Log.w(TAG, "failed to query existing note in database"); } - } else { - Log.w(TAG, "failed to query existing note in database"); - } - } finally { - if (c != null) { - c.close(); - c = null; + } finally { + if (c != null) { + c.close(); + c = null; + } } - } - - // go through remaining items - Iterator> iter = mGTaskHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - node = entry.getValue(); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); - } - - // mCancelled can be set by another thread, so we neet to check one by - // one - // clear local delete table - if (!mCancelled&&!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { - throw new ActionFailureException("failed to batch-delete local deleted notes"); + // go through remaining items + Iterator> iter = mGTaskHashMap.entrySet().iterator(); //Iterator迭代器 + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + node = entry.getValue(); + doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); } - // refresh local sync id - if (!mCancelled) { - GTaskClient.getInstance().commitUpdate(); - refreshLocalSyncId(); - } - - } + // mCancelled can be set by another thread, so we neet to check one by //thread----线程 + // one + // clear local delete table + if (!mCancelled) { + if (!DataUtils.batchDeleteNotes(mContentResolver, mLocalDeleteIdMap)) { + throw new ActionFailureException("failed to batch-delete local deleted notes"); + } + } - private void syncFolder() throws NetworkFailureException { - Cursor c = null; - String gid; - Node node; - int syncType; + // refresh local sync id + if (!mCancelled) { + GTaskClient.getInstance().commitUpdate(); + refreshLocalSyncId(); + } - if (mCancelled) { - return; } - // for root folder - try { - c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); - if (c != null) { - c.moveToNext(); - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); - mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); - // for system folder, only update remote name if necessary - if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) - doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); - } else { - doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); - } - } else { - Log.w(TAG, "failed to query root folder"); + /** + * 功能: + * @author TTS + * @throws NetworkFailureException + */ + private void syncFolder() throws NetworkFailureException { + Cursor c = null; + String gid; + Node node; + int syncType; + + if (mCancelled) { + return; } - } finally { - if (c != null) { - c.close(); - c = null; - } - } - // for call-note folder - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", - new String[] { - String.valueOf(Notes.ID_CALL_RECORD_FOLDER) - }, null); - if (c != null) { - if (c.moveToNext()) { + // for root folder + try { + c = mContentResolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, + Notes.ID_ROOT_FOLDER), SqlNote.PROJECTION_NOTE, null, null, null); + if (c != null) { + c.moveToNext(); gid = c.getString(SqlNote.GTASK_ID_COLUMN); node = mGTaskHashMap.get(gid); if (node != null) { mGTaskHashMap.remove(gid); - mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); - mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); - // for system folder, only update remote name if - // necessary + mGidToNid.put(gid, (long) Notes.ID_ROOT_FOLDER); + mNidToGid.put((long) Notes.ID_ROOT_FOLDER, gid); + // for system folder, only update remote name if necessary if (!node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX - + GTaskStringUtils.FOLDER_CALL_NOTE)) + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); } else { doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); } + } else { + Log.w(TAG, "failed to query root folder"); //查询根文件夹失败 + } + } finally { + if (c != null) { + c.close(); + c = null; } - } else { - Log.w(TAG, "failed to query call note folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; } - } - // for local existing folders - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type=? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - gid = c.getString(SqlNote.GTASK_ID_COLUMN); - node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); - mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); - syncType = node.getSyncAction(c); - } else { - if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { - // local add - syncType = Node.SYNC_ACTION_ADD_REMOTE; + // for call-note folder + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, "(_id=?)", + new String[] { + String.valueOf(Notes.ID_CALL_RECORD_FOLDER) + }, null); + if (c != null) { + if (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, (long) Notes.ID_CALL_RECORD_FOLDER); + mNidToGid.put((long) Notes.ID_CALL_RECORD_FOLDER, gid); + // for system folder, only update remote name if + // necessary + if (!node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + + GTaskStringUtils.FOLDER_CALL_NOTE)) + doContentSync(Node.SYNC_ACTION_UPDATE_REMOTE, node, c); } else { - // remote delete - syncType = Node.SYNC_ACTION_DEL_LOCAL; + doContentSync(Node.SYNC_ACTION_ADD_REMOTE, node, c); } } - doContentSync(syncType, node, c); + } else { + Log.w(TAG, "failed to query call note folder"); //查询失败 + } + } finally { + if (c != null) { + c.close(); + c = null; } - } else { - Log.w(TAG, "failed to query existing folder"); - } - } finally { - if (c != null) { - c.close(); - c = null; } - } - // for remote add folders - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - gid = entry.getKey(); - node = entry.getValue(); - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); - doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); + // for local existing folders //对本地已存在 + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type=? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); + if (c != null) { + while (c.moveToNext()) { + gid = c.getString(SqlNote.GTASK_ID_COLUMN); + node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + mGidToNid.put(gid, c.getLong(SqlNote.ID_COLUMN)); + mNidToGid.put(c.getLong(SqlNote.ID_COLUMN), gid); + syncType = node.getSyncAction(c); + } else { + if (c.getString(SqlNote.GTASK_ID_COLUMN).trim().length() == 0) { + // local add + syncType = Node.SYNC_ACTION_ADD_REMOTE; + } else { + // remote delete + syncType = Node.SYNC_ACTION_DEL_LOCAL; + } + } + doContentSync(syncType, node, c); + } + } else { + Log.w(TAG, "failed to query existing folder"); + } + } finally { + if (c != null) { + c.close(); + c = null; + } } - } - if (!mCancelled) - GTaskClient.getInstance().commitUpdate(); - } + // for remote add folders //用于添加远程文件夹 + Iterator> iter = mGTaskListHashMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + gid = entry.getKey(); + node = entry.getValue(); + if (mGTaskHashMap.containsKey(gid)) { + mGTaskHashMap.remove(gid); + doContentSync(Node.SYNC_ACTION_ADD_LOCAL, node, null); + } + } - private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; + if (!mCancelled) + GTaskClient.getInstance().commitUpdate(); } + /** + * 功能:syncType分类,addLocalNode,addRemoteNode,deleteNode,updateLocalNode,updateRemoteNode + * @author TTS + * @param syncType + * @param node + * @param c + * @throws NetworkFailureException + */ + private void doContentSync(int syncType, Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } - MetaData meta; - switch (syncType) { - case Node.SYNC_ACTION_ADD_LOCAL: - addLocalNode(node); - break; - case Node.SYNC_ACTION_ADD_REMOTE: - addRemoteNode(node, c); - break; - case Node.SYNC_ACTION_DEL_LOCAL: - meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); - } - mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); - break; - case Node.SYNC_ACTION_DEL_REMOTE: - meta = mMetaHashMap.get(node.getGid()); - if (meta != null) { - GTaskClient.getInstance().deleteNode(meta); - } - GTaskClient.getInstance().deleteNode(node); - break; - case Node.SYNC_ACTION_UPDATE_LOCAL: - updateLocalNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_REMOTE: - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_UPDATE_CONFLICT: - // merging both modifications maybe a good idea - // right now just use local update simply - updateRemoteNode(node, c); - break; - case Node.SYNC_ACTION_NONE: - break; - case Node.SYNC_ACTION_ERROR: - default: - throw new ActionFailureException("unkown sync action type"); + MetaData meta; + switch (syncType) { + case Node.SYNC_ACTION_ADD_LOCAL: + addLocalNode(node); + break; + case Node.SYNC_ACTION_ADD_REMOTE: + addRemoteNode(node, c); + break; + case Node.SYNC_ACTION_DEL_LOCAL: + meta = mMetaHashMap.get(c.getString(SqlNote.GTASK_ID_COLUMN)); + if (meta != null) { + GTaskClient.getInstance().deleteNode(meta); + } + mLocalDeleteIdMap.add(c.getLong(SqlNote.ID_COLUMN)); + break; + case Node.SYNC_ACTION_DEL_REMOTE: + meta = mMetaHashMap.get(node.getGid()); + if (meta != null) { + GTaskClient.getInstance().deleteNode(meta); + } + GTaskClient.getInstance().deleteNode(node); + break; + case Node.SYNC_ACTION_UPDATE_LOCAL: + updateLocalNode(node, c); + break; + case Node.SYNC_ACTION_UPDATE_REMOTE: + updateRemoteNode(node, c); + break; + case Node.SYNC_ACTION_UPDATE_CONFLICT: + // merging both modifications maybe a good idea + // right now just use local update simply + updateRemoteNode(node, c); + break; + case Node.SYNC_ACTION_NONE: + break; + case Node.SYNC_ACTION_ERROR: + default: + throw new ActionFailureException("unkown sync action type"); + } } - } - private void addLocalNode(Node node) throws NetworkFailureException { - if (mCancelled) { - return; - } + /** + * 功能:本地增加Node + * @author TTS + * @param node + * @throws NetworkFailureException + */ + private void addLocalNode(Node node) throws NetworkFailureException { + if (mCancelled) { + return; + } - SqlNote sqlNote; - if (node instanceof TaskList) { - if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { - sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); - } else if (node.getName().equals( - GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { - sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); + SqlNote sqlNote; + if (node instanceof TaskList) { + if (node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_DEFAULT)) { + sqlNote = new SqlNote(mContext, Notes.ID_ROOT_FOLDER); + } else if (node.getName().equals( + GTaskStringUtils.MIUI_FOLDER_PREFFIX + GTaskStringUtils.FOLDER_CALL_NOTE)) { + sqlNote = new SqlNote(mContext, Notes.ID_CALL_RECORD_FOLDER); + } else { + sqlNote = new SqlNote(mContext); + sqlNote.setContent(node.getLocalJSONFromContent()); + sqlNote.setParentId(Notes.ID_ROOT_FOLDER); + } } else { sqlNote = new SqlNote(mContext); - sqlNote.setContent(node.getLocalJSONFromContent()); - sqlNote.setParentId(Notes.ID_ROOT_FOLDER); - } - } else { - sqlNote = new SqlNote(mContext); - JSONObject js = node.getLocalJSONFromContent(); - try { - if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { - JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); - if (note.has(NoteColumns.ID)) { - long id = note.getLong(NoteColumns.ID); - if (DataUtils.existInNoteDatabase(mContentResolver, id)) { - // the id is not available, have to create a new one - note.remove(NoteColumns.ID); + JSONObject js = node.getLocalJSONFromContent(); + try { + if (js.has(GTaskStringUtils.META_HEAD_NOTE)) { + JSONObject note = js.getJSONObject(GTaskStringUtils.META_HEAD_NOTE); + if (note.has(NoteColumns.ID)) { + long id = note.getLong(NoteColumns.ID); + if (DataUtils.existInNoteDatabase(mContentResolver, id)) { + // the id is not available, have to create a new one + note.remove(NoteColumns.ID); + } } } - } - if (js.has(GTaskStringUtils.META_HEAD_DATA)) { - JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); - for (int i = 0; i < dataArray.length(); i++) { - JSONObject data = dataArray.getJSONObject(i); - if (data.has(DataColumns.ID)) { - long dataId = data.getLong(DataColumns.ID); - if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { - // the data id is not available, have to create - // a new one - data.remove(DataColumns.ID); + if (js.has(GTaskStringUtils.META_HEAD_DATA)) { + JSONArray dataArray = js.getJSONArray(GTaskStringUtils.META_HEAD_DATA); + for (int i = 0; i < dataArray.length(); i++) { + JSONObject data = dataArray.getJSONObject(i); + if (data.has(DataColumns.ID)) { + long dataId = data.getLong(DataColumns.ID); + if (DataUtils.existInDataDatabase(mContentResolver, dataId)) { + // the data id is not available, have to create + // a new one + data.remove(DataColumns.ID); + } } } - } + } + } catch (JSONException e) { + Log.w(TAG, e.toString()); + e.printStackTrace(); } - } catch (JSONException e) { - Log.w(TAG, e.toString()); - e.printStackTrace(); - } - sqlNote.setContent(js); + sqlNote.setContent(js); - Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot add local node"); + Long parentId = mGidToNid.get(((Task) node).getParent().getGid()); + if (parentId == null) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot add local node"); + } + sqlNote.setParentId(parentId.longValue()); } - sqlNote.setParentId(parentId.longValue()); - } - // create the local node - sqlNote.setGtaskId(node.getGid()); - sqlNote.commit(false); + // create the local node + sqlNote.setGtaskId(node.getGid()); + sqlNote.commit(false); - // update gid-nid mapping - mGidToNid.put(node.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), node.getGid()); + // update gid-nid mapping + mGidToNid.put(node.getGid(), sqlNote.getId()); + mNidToGid.put(sqlNote.getId(), node.getGid()); - // update meta - updateRemoteMeta(node.getGid(), sqlNote); - } - - private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; + // update meta + updateRemoteMeta(node.getGid(), sqlNote); } - SqlNote sqlNote; - // update the note locally - sqlNote = new SqlNote(mContext, c); - sqlNote.setContent(node.getLocalJSONFromContent()); + /** + * 功能:update本地node + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * ----Cursor + * @throws NetworkFailureException + */ + private void updateLocalNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } - Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) - : new Long(Notes.ID_ROOT_FOLDER); - if (parentId == null) { - Log.e(TAG, "cannot find task's parent id locally"); - throw new ActionFailureException("cannot update local node"); - } - sqlNote.setParentId(parentId.longValue()); - sqlNote.commit(true); + SqlNote sqlNote; + // update the note locally + sqlNote = new SqlNote(mContext, c); + sqlNote.setContent(node.getLocalJSONFromContent()); - // update meta info - updateRemoteMeta(node.getGid(), sqlNote); - } + Long parentId = (node instanceof Task) ? mGidToNid.get(((Task) node).getParent().getGid()) + : new Long(Notes.ID_ROOT_FOLDER); + if (parentId == null) { + Log.e(TAG, "cannot find task's parent id locally"); + throw new ActionFailureException("cannot update local node"); + } + sqlNote.setParentId(parentId.longValue()); + sqlNote.commit(true); - private void addRemoteNode(Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; + // update meta info + updateRemoteMeta(node.getGid(), sqlNote); } - SqlNote sqlNote = new SqlNote(mContext, c); - Node n; - - // update remotely - if (sqlNote.isNoteType()) { - Task task = new Task(); - task.setContentByLocalJSON(sqlNote.getContent()); - - String parentGid = mNidToGid.get(sqlNote.getParentId()); - if (parentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot add remote task"); + /** + * 功能:远程增加Node + * 需要updateRemoteMeta + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * --Cursor + * @throws NetworkFailureException + */ + private void addRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; } - mGTaskListHashMap.get(parentGid).addChildTask(task); - GTaskClient.getInstance().createTask(task); - n = (Node) task; + SqlNote sqlNote = new SqlNote(mContext, c); //从本地mContext中获取内容 + Node n; - // add meta - updateRemoteMeta(task.getGid(), sqlNote); - } else { - TaskList tasklist = null; + // update remotely + if (sqlNote.isNoteType()) { + Task task = new Task(); + task.setContentByLocalJSON(sqlNote.getContent()); - // we need to skip folder if it has already existed - String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; - if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) - folderName += GTaskStringUtils.FOLDER_DEFAULT; - else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) - folderName += GTaskStringUtils.FOLDER_CALL_NOTE; - else - folderName += sqlNote.getSnippet(); + String parentGid = mNidToGid.get(sqlNote.getParentId()); + if (parentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); //调试信息 + throw new ActionFailureException("cannot add remote task"); + } + mGTaskListHashMap.get(parentGid).addChildTask(task); //在本地生成的GTaskList中增加子结点 - Iterator> iter = mGTaskListHashMap.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = iter.next(); - String gid = entry.getKey(); - TaskList list = entry.getValue(); + //登录远程服务器,创建Task + GTaskClient.getInstance().createTask(task); + n = (Node) task; - if (list.getName().equals(folderName)) { - tasklist = list; - if (mGTaskHashMap.containsKey(gid)) { - mGTaskHashMap.remove(gid); + // add meta + updateRemoteMeta(task.getGid(), sqlNote); + } else { + TaskList tasklist = null; + + // we need to skip folder if it has already existed + String folderName = GTaskStringUtils.MIUI_FOLDER_PREFFIX; + if (sqlNote.getId() == Notes.ID_ROOT_FOLDER) + folderName += GTaskStringUtils.FOLDER_DEFAULT; + else if (sqlNote.getId() == Notes.ID_CALL_RECORD_FOLDER) + folderName += GTaskStringUtils.FOLDER_CALL_NOTE; + else + folderName += sqlNote.getSnippet(); + + //iterator迭代器,通过统一的接口迭代所有的map元素 + Iterator> iter = mGTaskListHashMap.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + String gid = entry.getKey(); + TaskList list = entry.getValue(); + + if (list.getName().equals(folderName)) { + tasklist = list; + if (mGTaskHashMap.containsKey(gid)) { + mGTaskHashMap.remove(gid); + } + break; } - break; } - } - // no match we can add now - if (tasklist == null) { - tasklist = new TaskList(); - tasklist.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().createTaskList(tasklist); - mGTaskListHashMap.put(tasklist.getGid(), tasklist); + // no match we can add now + if (tasklist == null) { + tasklist = new TaskList(); + tasklist.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().createTaskList(tasklist); + mGTaskListHashMap.put(tasklist.getGid(), tasklist); + } + n = (Node) tasklist; } - n = (Node) tasklist; - } - // update local note - sqlNote.setGtaskId(n.getGid()); - sqlNote.commit(false); - sqlNote.resetLocalModified(); - sqlNote.commit(true); + // update local note + sqlNote.setGtaskId(n.getGid()); + sqlNote.commit(false); + sqlNote.resetLocalModified(); + sqlNote.commit(true); - // gid-id mapping - mGidToNid.put(n.getGid(), sqlNote.getId()); - mNidToGid.put(sqlNote.getId(), n.getGid()); - } - - private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { - if (mCancelled) { - return; + // gid-id mapping //创建id间的映射 + mGidToNid.put(n.getGid(), sqlNote.getId()); + mNidToGid.put(sqlNote.getId(), n.getGid()); } + /** + * 功能:更新远端的Node,包含meta更新(updateRemoteMeta) + * @author TTS + * @param node + * ----同步操作的基础数据类型 + * @param c + * --Cursor + * @throws NetworkFailureException + */ + private void updateRemoteNode(Node node, Cursor c) throws NetworkFailureException { + if (mCancelled) { + return; + } - SqlNote sqlNote = new SqlNote(mContext, c); + SqlNote sqlNote = new SqlNote(mContext, c); - // update remotely - node.setContentByLocalJSON(sqlNote.getContent()); - GTaskClient.getInstance().addUpdateNode(node); + // update remotely + node.setContentByLocalJSON(sqlNote.getContent()); + GTaskClient.getInstance().addUpdateNode(node); //GTaskClient用途为从本地登陆远端服务器 - // update meta - updateRemoteMeta(node.getGid(), sqlNote); + // update meta + updateRemoteMeta(node.getGid(), sqlNote); - // move task if necessary - if (sqlNote.isNoteType()) { - Task task = (Task) node; - TaskList preParentList = task.getParent(); + // move task if necessary + if (sqlNote.isNoteType()) { + Task task = (Task) node; + TaskList preParentList = task.getParent(); + //preParentList为通过node获取的父节点列表 - String curParentGid = mNidToGid.get(sqlNote.getParentId()); - if (curParentGid == null) { - Log.e(TAG, "cannot find task's parent tasklist"); - throw new ActionFailureException("cannot update remote task"); - } - TaskList curParentList = mGTaskListHashMap.get(curParentGid); + String curParentGid = mNidToGid.get(sqlNote.getParentId()); + //curParentGid为通过光标在数据库中找到sqlNote的mParentId,再通过mNidToGid由long类型转为String类型的Gid + + if (curParentGid == null) { + Log.e(TAG, "cannot find task's parent tasklist"); + throw new ActionFailureException("cannot update remote task"); + } + TaskList curParentList = mGTaskListHashMap.get(curParentGid); + //通过HashMap找到对应Gid的TaskList - if (preParentList != curParentList) { - preParentList.removeChildTask(task); - curParentList.addChildTask(task); - GTaskClient.getInstance().moveTask(task, preParentList, curParentList); + if (preParentList != curParentList) { //????????????? + preParentList.removeChildTask(task); + curParentList.addChildTask(task); + GTaskClient.getInstance().moveTask(task, preParentList, curParentList); + } } - } - // clear local modified flag - sqlNote.resetLocalModified(); - sqlNote.commit(true); - } + // clear local modified flag + sqlNote.resetLocalModified(); + //commit到本地数据库 + sqlNote.commit(true); + } - private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { - if (sqlNote != null && sqlNote.isNoteType()) { - MetaData metaData = mMetaHashMap.get(gid); - if (metaData != null) { - metaData.setMeta(gid, sqlNote.getContent()); - GTaskClient.getInstance().addUpdateNode(metaData); - } else { - metaData = new MetaData(); - metaData.setMeta(gid, sqlNote.getContent()); - mMetaList.addChildTask(metaData); - mMetaHashMap.put(gid, metaData); - GTaskClient.getInstance().createTask(metaData); + /** + * 功能:升级远程meta。 meta---元数据----计算机文件系统管理数据---管理数据的数据。 + * @author TTS + * @param gid + * ---GoogleID为String类型 + * @param sqlNote + * ---同步前的数据库操作,故使用类SqlNote + * @throws NetworkFailureException + */ + private void updateRemoteMeta(String gid, SqlNote sqlNote) throws NetworkFailureException { + if (sqlNote != null && sqlNote.isNoteType()) { + MetaData metaData = mMetaHashMap.get(gid); + if (metaData != null) { + metaData.setMeta(gid, sqlNote.getContent()); + GTaskClient.getInstance().addUpdateNode(metaData); + } else { + metaData = new MetaData(); + metaData.setMeta(gid, sqlNote.getContent()); + mMetaList.addChildTask(metaData); + mMetaHashMap.put(gid, metaData); + GTaskClient.getInstance().createTask(metaData); + } } } - } - private void refreshLocalSyncId() throws NetworkFailureException { - if (mCancelled) { - return; - } + /** + * 功能:刷新本地,给sync的ID对应上最后更改过的对象 + * @author TTS + * @return void + * @throws NetworkFailureException + */ + private void refreshLocalSyncId() throws NetworkFailureException { + if (mCancelled) { + return; + } - // get the latest gtask list - mGTaskHashMap.clear(); - mGTaskListHashMap.clear(); - mMetaHashMap.clear(); - initGTaskList(); + // get the latest gtask list //获取最近的(最晚的)gtask list + mGTaskHashMap.clear(); + mGTaskListHashMap.clear(); + mMetaHashMap.clear(); + initGTaskList(); - Cursor c = null; - try { - c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, - "(type<>? AND parent_id<>?)", new String[] { - String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) - }, NoteColumns.TYPE + " DESC"); - if (c != null) { - while (c.moveToNext()) { - String gid = c.getString(SqlNote.GTASK_ID_COLUMN); - Node node = mGTaskHashMap.get(gid); - if (node != null) { - mGTaskHashMap.remove(gid); - ContentValues values = new ContentValues(); - values.put(NoteColumns.SYNC_ID, node.getLastModified()); - mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, - c.getLong(SqlNote.ID_COLUMN)), values, null, null); - } else { - Log.e(TAG, "something is missed"); - throw new ActionFailureException( - "some local items don't have gid after sync"); + Cursor c = null; + try { + c = mContentResolver.query(Notes.CONTENT_NOTE_URI, SqlNote.PROJECTION_NOTE, + "(type<>? AND parent_id<>?)", new String[] { + String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER) + }, NoteColumns.TYPE + " DESC"); //query语句:五个参数,NoteColumns.TYPE + " DESC"-----为按类型递减顺序返回查询结果。new String[] {String.valueOf(Notes.TYPE_SYSTEM), String.valueOf(Notes.ID_TRASH_FOLER)}------为选择参数。"(type<>? AND parent_id<>?)"-------指明返回行过滤器。SqlNote.PROJECTION_NOTE--------应返回的数据列的名字。Notes.CONTENT_NOTE_URI--------contentProvider包含所有数据集所对应的uri + if (c != null) { + while (c.moveToNext()) { + String gid = c.getString(SqlNote.GTASK_ID_COLUMN); + Node node = mGTaskHashMap.get(gid); + if (node != null) { + mGTaskHashMap.remove(gid); + ContentValues values = new ContentValues(); //在ContentValues中创建键值对。准备通过contentResolver写入数据 + values.put(NoteColumns.SYNC_ID, node.getLastModified()); + mContentResolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, //进行批量更改,选择参数为NULL,应该可以用insert替换,参数分别为表名和需要更新的value对象。 + c.getLong(SqlNote.ID_COLUMN)), values, null, null); + } else { + Log.e(TAG, "something is missed"); + throw new ActionFailureException( + "some local items don't have gid after sync"); + } } + } else { + Log.w(TAG, "failed to query local note to refresh sync id"); + } + } finally { + if (c != null) { + c.close(); + c = null; } - } else { - Log.w(TAG, "failed to query local note to refresh sync id"); - } - } finally { - if (c != null) { - c.close(); - c = null; } } - } - public String getSyncAccount() { - return GTaskClient.getInstance().getSyncAccount().name; - } + /** + * 功能:获取同步账号,mAccount.name + * @author TTS + * @return String + */ + public String getSyncAccount() { + return GTaskClient.getInstance().getSyncAccount().name; + } - public void cancelSync() { - mCancelled = true; + /** + * 功能:取消同步,置mCancelled为true + * @author TTS + */ + public void cancelSync() { + mCancelled = true; + } } -} diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java index fafce43..ef7b4c4 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/gtask/remote/GTaskSyncService.java @@ -1,47 +1,27 @@ -/* - * 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.gtask.remote; -import android.app.Activity; -import android.app.Service; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.IBinder; +// Service是在一段不定的时间运行在后台,不和用户交互的应用组件 public class GTaskSyncService extends Service { - public static final String ACTION_STRING_NAME = "sync_action_type"; + public final static String ACTION_STRING_NAME = "sync_action_type"; - public static final int ACTION_START_SYNC = 0; + public final static int ACTION_START_SYNC = 0; - public static final int ACTION_CANCEL_SYNC = 1; + public final static int ACTION_CANCEL_SYNC = 1; - public static final int ACTION_INVALID = 2; + public final static int ACTION_INVALID = 2; - public static final String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; + public final static String GTASK_SERVICE_BROADCAST_NAME = "net.micode.notes.gtask.remote.gtask_sync_service"; - public static final String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; + public final static String GTASK_SERVICE_BROADCAST_IS_SYNCING = "isSyncing"; - public static final String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; + public final static String GTASK_SERVICE_BROADCAST_PROGRESS_MSG = "progressMsg"; - private GTaskASyncTask mSyncTask = null; + private static GTaskASyncTask mSyncTask = null; - private String mSyncProgress = ""; + private static String mSyncProgress = ""; + //开始一个同步的工作 private void startSync() { if (mSyncTask == null) { mSyncTask = new GTaskASyncTask(this, new GTaskASyncTask.OnCompleteListener() { @@ -52,10 +32,11 @@ public class GTaskSyncService extends Service { } }); sendBroadcast(""); - mSyncTask.execute(); + mSyncTask.execute(); //这个函数让任务是以单线程队列方式或线程池队列方式运行 } } + //取消同步的方法 private void cancelSync() { if (mSyncTask != null) { mSyncTask.cancelSync(); @@ -63,15 +44,18 @@ public class GTaskSyncService extends Service { } @Override - public void onCreate() { + public void onCreate() { //初始化一个service mSyncTask = null; } + + @Override - public int onStartCommand(Intent intent, int flags, int startId) { + public int onStartCommand(Intent intent, int flags, int startId) {////service生命周期的组成部分,相当于重启service(比如在被暂停之后),而不是创建一个新的 Bundle bundle = intent.getExtras(); if (bundle != null && bundle.containsKey(ACTION_STRING_NAME)) { switch (bundle.getInt(ACTION_STRING_NAME, ACTION_INVALID)) { + //两种情况,开始同步或者取消同步 case ACTION_START_SYNC: startSync(); break; @@ -81,13 +65,14 @@ public class GTaskSyncService extends Service { default: break; } - return START_STICKY; + return START_STICKY; //等待新的intent来是这个service继续运行 } return super.onStartCommand(intent, flags, startId); } @Override - public void onLowMemory() { + public void onLowMemory() { //在没有内存的情况下如果存在service则结束掉这的service + if (mSyncTask != null) { mSyncTask.cancelSync(); } @@ -97,32 +82,33 @@ public class GTaskSyncService extends Service { return null; } - public void sendBroadcast(String msg) { + public void sendBroadcast(String msg) { //发送同步的相关通知 mSyncProgress = msg; - Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); - intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); + Intent intent = new Intent(GTASK_SERVICE_BROADCAST_NAME); //创建一个新的Intent + intent.putExtra(GTASK_SERVICE_BROADCAST_IS_SYNCING, mSyncTask != null); //附加INTENT中的相应参数的值 intent.putExtra(GTASK_SERVICE_BROADCAST_PROGRESS_MSG, msg); - sendBroadcast(intent); + sendBroadcast(intent); //发送这个通知 } - public static void startSync(Activity activity) { + public static void startSync(Activity activity) {//执行一个service,service的内容里的同步动作就是开始同步 GTaskManager.getInstance().setActivityContext(activity); Intent intent = new Intent(activity, GTaskSyncService.class); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_START_SYNC); activity.startService(intent); } - public static void cancelSync(Context context) { + public static void cancelSync(Context context) {//执行一个service,service的内容里的同步动作就是取消同步 Intent intent = new Intent(context, GTaskSyncService.class); intent.putExtra(GTaskSyncService.ACTION_STRING_NAME, GTaskSyncService.ACTION_CANCEL_SYNC); context.startService(intent); } - public static boolean isSyncing() { + public static boolean isSyncing() { //判读是否在进行同步 return mSyncTask != null; } - public static String getProgressString() { + public static String getProgressString() { // 获取当前进度的信息 + return mSyncProgress; } -} +} \ No newline at end of file diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/Note.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/Note.java index e5829f0..4d89ed9 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/Note.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/Note.java @@ -14,16 +14,15 @@ * limitations under the License. */ -package net.micode.notes.model; -import android.content.ContentProviderOperation; -import android.content.ContentProviderResult; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.content.OperationApplicationException; -import android.net.Uri; -import android.os.RemoteException; -import android.util.Log; +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;//表示待操作的数据 +import android.os.RemoteException;//远程容错 +import android.util.Log;//输出日志,比如说出错、警告等 import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.CallNote; @@ -49,16 +48,17 @@ public class Note { values.put(NoteColumns.MODIFIED_DATE, createdTime); values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); values.put(NoteColumns.LOCAL_MODIFIED, 1); - values.put(NoteColumns.PARENT_ID, folderId); - Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); + values.put(NoteColumns.PARENT_ID, folderId);//将数据写入数据库表格 + Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);//ContentResolver()主要是实现外部应用对ContentProvider中的数据 + //实现添加、删除、修改和查询操作 long noteId = 0; try { noteId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { Log.e(TAG, "Get note id error :" + e.toString()); noteId = 0; - } + }//异常处理 if (noteId == -1) { throw new IllegalStateException("Wrong note id:" + noteId); } @@ -68,37 +68,37 @@ public class Note { public Note() { mNoteDiffValues = new ContentValues(); mNoteData = new NoteData(); - } + }//定义两个变量用来存储便签的数据,一个是存储便签属性、一个是存储便签内容 public void setNoteValue(String key, String value) { mNoteDiffValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - } + }//设置数据库表格的标签属性数据 public void setTextData(String key, String value) { mNoteData.setTextData(key, value); - } + }//设置数据库表格的标签文本内容的数据 public void setTextDataId(long id) { mNoteData.setTextDataId(id); - } + }//设置文本数据的ID public long getTextDataId() { return mNoteData.mTextDataId; - } + }//得到文本数据的ID public void setCallDataId(long id) { mNoteData.setCallDataId(id); - } + }//设置电话号码数据的ID public void setCallData(String key, String value) { mNoteData.setCallData(key, value); - } + }//得到电话号码数据的ID public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); - } + }//判断是否是本地修改 public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { @@ -128,16 +128,17 @@ public class Note { } return true; - } + }//判断数据是否同步 + //定义一个基本的便签内容的数据类,包含文本数据和电话号码数据 private class NoteData { private long mTextDataId; - private ContentValues mTextDataValues; + private ContentValues mTextDataValues;//文本数据 private long mCallDataId; - private ContentValues mCallDataValues; + private ContentValues mCallDataValues;//电话号码数据 private static final String TAG = "NoteData"; @@ -147,7 +148,7 @@ public class Note { mTextDataId = 0; mCallDataId = 0; } - + //函数的具体实现 boolean isLocalModified() { return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } @@ -177,18 +178,18 @@ public class Note { mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - + //下面函数的作用是将新的数据通过Uri的操作存储到数据库 Uri pushIntoContentResolver(Context context, long noteId) { /** * Check for safety */ if (noteId <= 0) { throw new IllegalArgumentException("Wrong note id:" + noteId); - } + }//判断数据是否合法 - ArrayList operationList = new ArrayList<>(); + ArrayList operationList = new ArrayList(); + //数据库的操作列表 ContentProviderOperation.Builder builder = null; - if(mTextDataValues.size() > 0) { mTextDataValues.put(DataColumns.NOTE_ID, noteId); if (mTextDataId == 0) { @@ -209,7 +210,7 @@ public class Note { operationList.add(builder.build()); } mTextDataValues.clear(); - } + }//把文本数据存入DataColumns if(mCallDataValues.size() > 0) { mCallDataValues.put(DataColumns.NOTE_ID, noteId); @@ -231,7 +232,7 @@ public class Note { operationList.add(builder.build()); } mCallDataValues.clear(); - } + }//把电话号码数据存入DataColumns if (operationList.size() > 0) { try { @@ -246,8 +247,8 @@ public class Note { Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); return null; } - } + }//存储过程中的异常处理 return null; } } -} +} \ No newline at end of file diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/WorkingNote.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/WorkingNote.java index 22217e1..441ea30 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/WorkingNote.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/model/WorkingNote.java @@ -61,8 +61,8 @@ public class WorkingNote { private boolean mIsDeleted; private NoteSettingChangedListener mNoteSettingStatusListener; - - protected static final String[] DATA_PROJECTION = new String[] { + // 声明 DATA_PROJECTION字符串数组 + public static final String[] DATA_PROJECTION = new String[] { DataColumns.ID, DataColumns.CONTENT, DataColumns.MIME_TYPE, @@ -71,8 +71,8 @@ public class WorkingNote { DataColumns.DATA3, DataColumns.DATA4, }; - - protected static final String[] NOTE_PROJECTION = new String[] { + // 声明 NOTE_PROJECTION字符串数组 + public static final String[] NOTE_PROJECTION = new String[] { NoteColumns.PARENT_ID, NoteColumns.ALERTED_DATE, NoteColumns.BG_COLOR_ID, @@ -114,6 +114,7 @@ public class WorkingNote { mWidgetType = Notes.TYPE_WIDGET_INVALIDE; } + // WorkingNote的构造函数 // Existing note construct private WorkingNote(Context context, long noteId, long folderId) { mContext = context; @@ -124,11 +125,13 @@ public class WorkingNote { loadNote(); } + // 加载Note + // 通过数据库调用query函数找到第一个条目 private void loadNote() { Cursor cursor = mContext.getContentResolver().query( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mNoteId), NOTE_PROJECTION, null, null, null); - + //若存在,储存相应信息 if (cursor != null) { if (cursor.moveToFirst()) { mFolderId = cursor.getLong(NOTE_PARENT_ID_COLUMN); @@ -139,6 +142,7 @@ public class WorkingNote { mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); } cursor.close(); + //若不存在,报错 } else { Log.e(TAG, "No note with id:" + mNoteId); throw new IllegalArgumentException("Unable to find note with id " + mNoteId); @@ -146,14 +150,16 @@ public class WorkingNote { loadNoteData(); } + //加载NoteData private void loadNoteData() { Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) + String.valueOf(mNoteId) }, null); if (cursor != null) { - if (cursor.moveToFirst()) { + //查到信息不为空 + if (cursor.moveToFirst()) {//查看第一项是否存在 do { String type = cursor.getString(DATA_MIME_TYPE_COLUMN); if (DataConstants.NOTE.equals(type)) { @@ -165,7 +171,7 @@ public class WorkingNote { } else { Log.d(TAG, "Wrong note type with type:" + type); } - } while (cursor.moveToNext()); + } while (cursor.moveToNext());//查询所有项,直到为空 } cursor.close(); } else { @@ -173,10 +179,12 @@ public class WorkingNote { throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); } } - + //创建空的Note + //传参:context,文件夹id,widget,背景颜色 public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { + int widgetType, int defaultBgColorId) { WorkingNote note = new WorkingNote(context, folderId); + //设定相关属性 note.setBgColorId(defaultBgColorId); note.setWidgetId(widgetId); note.setWidgetType(widgetType); @@ -186,10 +194,10 @@ public class WorkingNote { public static WorkingNote load(Context context, long id) { return new WorkingNote(context, id, 0); } - + //保存Note public synchronized boolean saveNote() { - if (isWorthSaving()) { - if (!existInDatabase()) { + if (isWorthSaving()) {//是否值得保存 + if (!existInDatabase()) {//是否存在数据库中 if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { Log.e(TAG, "Create new note fail with id:" + mNoteId); return false; @@ -211,12 +219,13 @@ public class WorkingNote { return false; } } - + //是否存在数据库中 public boolean existInDatabase() { return mNoteId > 0; } - + //是否值得保存 private boolean isWorthSaving() { + //被删除,或(不在数据库中 内容为空) ,或本地已经保存过 if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) || (existInDatabase() && !mNote.isLocalModified())) { return false; @@ -224,11 +233,12 @@ public class WorkingNote { return true; } } - + //设置mNoteSettingStatuListener public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { mNoteSettingStatusListener = l; } - + //设置AlertDate + //若mAlertDate与data不同,则更改mAlertDate并设定NoteValue public void setAlertDate(long date, boolean set) { if (date != mAlertDate) { mAlertDate = date; @@ -238,17 +248,18 @@ public class WorkingNote { 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) { + if (id != mBgColorId) {//设定条件id!=mBgColorId mBgColorId = id; if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onBackgroundColorChanged(); @@ -256,9 +267,10 @@ public class WorkingNote { mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); } } - + // 设定检查列表模式 + // 参数:mode public void setCheckListMode(int mode) { - if (mMode != mode) { + if (mMode != mode) {//设定条件 if (mNoteSettingStatusListener != null) { mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); } @@ -266,82 +278,92 @@ public class WorkingNote { mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); } } - + // 设定WidgetType + // 参数:type public void setWidgetType(int type) { - if (type != mWidgetType) { + if (type != mWidgetType) {//设定条件 mWidgetType = type; mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); + // 调用Note的setNoteValue方法更改WidgetType + } } - + // 设定WidgetId + // 参数:id public void setWidgetId(int id) { - if (id != mWidgetId) { + if (id != mWidgetId) {//设定条件 mWidgetId = id; mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); + // 调用Note的setNoteValue方法更改WidgetId } } - + // 设定WorkingTex + // 参数:更改的text public void setWorkingText(String text) { if (!TextUtils.equals(mContent, text)) { mContent = text; mNote.setTextData(DataColumns.CONTENT, mContent); + // 调用Note的setTextData方法更改WorkingText } } - + // 转变mNote的CallData及CallNote信息 + // 参数:String phoneNumber, long callDate 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() { return (mAlertDate > 0 ? true : false); } - + //获取Content public String getContent() { return mContent; } - + //获取AlertDate public long getAlertDate() { return mAlertDate; } - + //获取ModifiedDate public long getModifiedDate() { return mModifiedDate; } - + //获取背景颜色来源id public int getBgColorResId() { return NoteBgResources.getNoteBgResource(mBgColorId); } - + //获取背景颜色id public int getBgColorId() { return mBgColorId; } - + //获取标题背景颜色id public int getTitleBgResId() { return NoteBgResources.getNoteTitleBgResource(mBgColorId); } - + //获取CheckListMode public int getCheckListMode() { return mMode; } - + //获取便签id public long getNoteId() { return mNoteId; } - + //获取文件夹id public long getFolderId() { return mFolderId; } - + //获取WidgetId public int getWidgetId() { return mWidgetId; } - + //获取WidgetType public int getWidgetType() { return mWidgetType; } - + // 创建接口 NoteSettingChangedListener,便签更新监视 + // 为NoteEditActivity提供接口 + // 提供函数有 public interface NoteSettingChangedListener { /** * Called when the background color of current note has just changed diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/BackupUtils.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/BackupUtils.java index 39f6ec4..5d19c61 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/BackupUtils.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/BackupUtils.java @@ -39,10 +39,13 @@ import java.io.PrintStream; public class BackupUtils { private static final String TAG = "BackupUtils"; // Singleton stuff - private static BackupUtils sInstance; - + private static BackupUtils sInstance;//类里面为什么可以定义自身类对象? + //ynchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程A) + //运行到这个方法时,都要检查有没有其它线程B(或者C、 D等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用synchronized方法的线程B(或者C 、D)运行完这个方法后再运行此线程A,没有的话,锁定调用者,然后直接运行。 + //它包括两种用法:synchronized 方法和 synchronized 块。 public static synchronized BackupUtils getInstance(Context context) { if (sInstance == null) { + //如果当前备份不存在,则新声明一个 sInstance = new BackupUtils(context); } return sInstance; @@ -52,23 +55,23 @@ public class BackupUtils { * Following states are signs to represents backup or restore * status */ - // Currently, the sdcard is not mounted + // Currently, the sdcard is not mounted SD卡没有被装入手机 public static final int STATE_SD_CARD_UNMOUONTED = 0; - // The backup file not exist + // 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 + // 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 + // Some run-time exception which causes restore or backup fails 超时异常 public static final int STATE_SYSTEM_ERROR = 3; - // Backup or restore success + // Backup or restore success 成功存储 public static final int STATE_SUCCESS = 4; private TextExport mTextExport; - + //初始化函数 private BackupUtils(Context context) { mTextExport = new TextExport(context); } - + //外部储存功能是否可用 private static boolean externalStorageAvailable() { return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()); } @@ -131,7 +134,7 @@ public class BackupUtils { mFileName = ""; mFileDirectory = ""; } - + //获取文本的组成部分 private String getFormat(int id) { return TEXT_FORMAT[id]; } @@ -140,23 +143,23 @@ public class BackupUtils { * Export the folder identified by folder id to text */ private void exportFolderToText(String folderId, PrintStream ps) { - // Query notes belong to this folder + // Query notes belong to this folder 通过查询parent id是文件夹id的note来选出制定ID文件夹下的Note Cursor notesCursor = mContext.getContentResolver().query(Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.PARENT_ID + "=?", new String[] { - folderId + folderId }, null); if (notesCursor != null) { if (notesCursor.moveToFirst()) { do { - // Print note's last modified date + // Print note's last modified date ps里面保存有这份note的日期 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()); + } while (notesCursor.moveToNext());//将文件导出到text } notesCursor.close(); } @@ -168,9 +171,9 @@ public class BackupUtils { private void exportNoteToText(String noteId, PrintStream ps) { Cursor dataCursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, DataColumns.NOTE_ID + "=?", new String[] { - noteId + noteId }, null); - + //利用光标来扫描内容,区别为callnote和note两种,靠ps.printline输出 if (dataCursor != null) { if (dataCursor.moveToFirst()) { do { @@ -180,7 +183,7 @@ public class BackupUtils { 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)); @@ -218,6 +221,7 @@ public class BackupUtils { /** * Note will be exported as text which is user readable */ + //总函数,调用上面的exportFolder和exportNote public int exportToText() { if (!externalStorageAvailable()) { Log.d(TAG, "Media was not mounted"); @@ -229,7 +233,7 @@ public class BackupUtils { Log.e(TAG, "get print stream error"); return STATE_SYSTEM_ERROR; } - // First export folder and its notes + // First export folder and its notes 导出文件夹,就是导出里面包含的便签 Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -257,7 +261,7 @@ public class BackupUtils { folderCursor.close(); } - // Export notes in root's folder + // Export notes in root's folder 将根目录里的便签导出(由于不属于任何文件夹,因此无法通过文件夹导出来实现这一部分便签的导出) Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, @@ -297,6 +301,7 @@ public class BackupUtils { PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream(file); + //将ps输出流输出到特定的文件,目的就是导出到文件,而不是直接输出 ps = new PrintStream(fos); } catch (FileNotFoundException e) { e.printStackTrace(); @@ -314,15 +319,15 @@ public class BackupUtils { */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { StringBuilder sb = new StringBuilder(); - sb.append(Environment.getExternalStorageDirectory()); - sb.append(context.getString(filePathResId)); - File filedir = new File(sb.toString()); + sb.append(Environment.getExternalStorageDirectory()); //外部(SD卡)的存储路径 + sb.append(context.getString(filePathResId)); //文件的存储路径 + File filedir = new File(sb.toString()); //filedir应该就是用来存储路径信息 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(); @@ -336,7 +341,7 @@ public class BackupUtils { } catch (IOException e) { e.printStackTrace(); } - + // try catch 异常处理 return null; } } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/DataUtils.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/DataUtils.java index 2a14982..631957d 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/DataUtils.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/DataUtils.java @@ -52,13 +52,14 @@ public class DataUtils { if(id == Notes.ID_ROOT_FOLDER) { Log.e(TAG, "Don't delete system folder root"); continue; - } + } //如果发现是根文件夹,则不删除 ContentProviderOperation.Builder builder = ContentProviderOperation .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); operationList.add(builder.build()); - } + }//将ids里包含的每一列的数据逐次加入到operationList中,等待最后的批量处理 try { ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); + //数据库事务,数据库事务是由一组数据库操作序列组成,事务作为一个整体被执行 if (results == null || results.length == 0 || results[0] == null) { Log.d(TAG, "delete notes failed, ids:" + ids.toString()); return false; @@ -81,7 +82,7 @@ public class DataUtils { } public static boolean batchMoveToFolder(ContentResolver resolver, HashSet ids, - long folderId) { + long folderId) { if (ids == null) { Log.d(TAG, "the ids is null"); return true; @@ -119,7 +120,7 @@ public class DataUtils { new String[] { "COUNT(*)" }, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, - null); + null);//筛选条件:源文件不为trash folder int count = 0; if(cursor != null) { @@ -141,11 +142,11 @@ public class DataUtils { null, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, new String [] {String.valueOf(type)}, - null); + null);//查询条件:type符合,且不属于垃圾文件夹 boolean exist = false; if (cursor != null) { - if (cursor.getCount() > 0) { + if (cursor.getCount() > 0) {//用getcount函数判断cursor是否为空 exist = true; } cursor.close(); @@ -184,9 +185,10 @@ public class DataUtils { public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + - " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + - " AND " + NoteColumns.SNIPPET + "=?", + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + + " AND " + NoteColumns.SNIPPET + "=?", new String[] { name }, null); + //通过名字查询文件是否存在 boolean exist = false; if(cursor != null) { if(cursor.getCount() > 0) { @@ -202,7 +204,7 @@ public class DataUtils { new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, NoteColumns.PARENT_ID + "=?", new String[] { String.valueOf(folderId) }, - null); + null);//查询条件:父ID是传入的folderId; HashSet set = null; if (c != null) { @@ -211,13 +213,13 @@ public class DataUtils { do { try { AppWidgetAttribute widget = new AppWidgetAttribute(); - widget.widgetId = c.getInt(0); - widget.widgetType = c.getInt(1); + 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()); + } while (c.moveToNext()); //查询下一条 } c.close(); } @@ -247,14 +249,14 @@ public class DataUtils { Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" - + CallNote.PHONE_NUMBER + ",?)", + + CallNote.PHONE_NUMBER + ",?)", new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, - null); + null);//通过数据库操作,查询条件是(callDate和phoneNumber匹配传入参数的值) if (cursor != null) { if (cursor.moveToFirst()) { try { - return cursor.getLong(0); + return cursor.getLong(0);//0对应的CallNote.NOTE_ID } catch (IndexOutOfBoundsException e) { Log.e(TAG, "Get call note id fails " + e.toString()); } @@ -269,7 +271,7 @@ public class DataUtils { new String [] { NoteColumns.SNIPPET }, NoteColumns.ID + "=?", new String [] { String.valueOf(noteId)}, - null); + null);//查询条件:noteId if (cursor != null) { String snippet = ""; @@ -282,7 +284,7 @@ public class DataUtils { throw new IllegalArgumentException("Note is not found with id: " + noteId); } - public static String getFormattedSnippet(String snippet) { + public static String getFormattedSnippet(String snippet) {//对字符串进行格式处理,将字符串两头的空格去掉,同时将换行符去掉 if (snippet != null) { snippet = snippet.trim(); int index = snippet.indexOf('\n'); diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java index 666b729..0f1ffa7 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/GTaskStringUtils.java @@ -13,9 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - +//简介:定义了很多的静态字符串,目的就是为了提供jsonObject中相应字符串的"key"。把这些静态的定义单独写到了一个类里面,这是非常好的编程规范 package net.micode.notes.tool; - +//这个类就是定义了一堆static string,实际就是为jsonObject提供Key,把这些定义全部写到一个类里,方便查看管理,是一个非常好的编程习惯 public class GTaskStringUtils { public final static String GTASK_JSON_ACTION_ID = "action_id"; diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/ResourceParser.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/ResourceParser.java index 1ad3ad6..b03ae23 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/ResourceParser.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/tool/ResourceParser.java @@ -16,6 +16,20 @@ package net.micode.notes.tool; +/*简介:字面意义是资源分析器,实际上就是获取资源并且在程序中使用,比如颜色图片等 + * 实现方法:主要利用R.java这个类,其中包括 + * R.id 组件资源引用 + * R.drawable 图片资源 (被使用) + * R.layout 布局资源 + * R.menu 菜单资源 + * R.String 文字资源 + * R.style 主题资源 (被使用) + * 在按顺序设置好相应的id后,就可以编写简单的getXXX函数获取需要的资源 + * + * 特殊的变量 : + * @BG_DEFAULT_COLOR 默认背景颜色(黄) + * BG_DEFAULT_FONT_SIZE 默认文本大小(中) + */ import android.content.Context; import android.preference.PreferenceManager; @@ -41,19 +55,19 @@ public class ResourceParser { 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 + 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 + 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) { @@ -64,7 +78,7 @@ public class ResourceParser { return BG_EDIT_TITLE_RESOURCES[id]; } } - + //直接获取默认的背景颜色。 public static int getDefaultBgId(Context context) { if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { @@ -76,35 +90,35 @@ public class ResourceParser { public static class NoteItemBgResources { private final static int [] BG_FIRST_RESOURCES = new int [] { - 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 + 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 + 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, + 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 + 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 }; public static int getNoteBgFirstRes(int id) { @@ -130,11 +144,11 @@ public class ResourceParser { public static class WidgetBgResources { private final static int [] BG_2X_RESOURCES = new int [] { - 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, + 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) { @@ -142,11 +156,11 @@ public class ResourceParser { } private final static int [] BG_4X_RESOURCES = new int [] { - 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 + 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) { @@ -156,12 +170,12 @@ public class ResourceParser { public static class TextAppearanceResources { private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { - R.style.TextAppearanceNormal, - R.style.TextAppearanceMedium, - R.style.TextAppearanceLarge, - R.style.TextAppearanceSuper + R.style.TextAppearanceNormal, + R.style.TextAppearanceMedium, + R.style.TextAppearanceLarge, + R.style.TextAppearanceSuper }; - + //这里有一个容错的函数,防止输入的id大于资源总量,若如此,则自动返回默认的设置结果 public static int getTexAppearanceResource(int id) { /** * HACKME: Fix bug of store the resource id in shared preference. diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java index 85723be..bad1150 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmAlertActivity.java @@ -39,7 +39,7 @@ import net.micode.notes.tool.DataUtils; import java.io.IOException; - +// 派生自Activity类,并实现OnClickListener和OnDismissListener接口 public class AlarmAlertActivity extends Activity implements OnClickListener, OnDismissListener { private long mNoteId; private String mSnippet; @@ -50,11 +50,14 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); - +// 请求无标题的窗口 final Window win = getWindow(); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); +// 在锁定的情况下显示 + + + if (!isScreenOn()) {// 如果屏幕关闭,则设置一些窗口标志 - if (!isScreenOn()) { win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON @@ -65,6 +68,9 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD try { mNoteId = Long.valueOf(intent.getData().getPathSegments().get(1)); + // 从Intent中获取noteId + + // 截取文本片段并添加标识字符串 mSnippet = DataUtils.getSnippetById(this.getContentResolver(), mNoteId); mSnippet = mSnippet.length() > SNIPPET_PREW_MAX_LEN ? mSnippet.substring(0, SNIPPET_PREW_MAX_LEN) + getResources().getString(R.string.notelist_string_info) @@ -76,24 +82,25 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD mPlayer = new MediaPlayer(); if (DataUtils.visibleInNoteDatabase(getContentResolver(), mNoteId, Notes.TYPE_NOTE)) { - showActionDialog(); - playAlarmSound(); + showActionDialog();// 显示操作对话框 + + playAlarmSound();// 播放报警声音 } else { - finish(); + finish();// 关闭Activity } } private boolean isScreenOn() { PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - return pm.isScreenOn(); + return pm.isScreenOn();// 返回屏幕是否打开的状态 } - private void playAlarmSound() { + private void playAlarmSound() {// 获取默认的闹钟铃声 Uri url = RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_ALARM); - +// 获取系统静音模式下影响的流 int silentModeStreams = Settings.System.getInt(getContentResolver(), Settings.System.MODE_RINGER_STREAMS_AFFECTED, 0); - +// 根据静音模式设置音频流类型 if ((silentModeStreams & (1 << AudioManager.STREAM_ALARM)) != 0) { mPlayer.setAudioStreamType(silentModeStreams); } else { @@ -118,6 +125,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD e.printStackTrace(); } } + // 显示操作对话框 private void showActionDialog() { AlertDialog.Builder dialog = new AlertDialog.Builder(this); @@ -129,7 +137,7 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD } dialog.show().setOnDismissListener(this); } - + // 点击“进入”按钮,启动编辑笔记页面 public void onClick(DialogInterface dialog, int which) { switch (which) { case DialogInterface.BUTTON_NEGATIVE: @@ -144,12 +152,12 @@ public class AlarmAlertActivity extends Activity implements OnClickListener, OnD } public void onDismiss(DialogInterface dialog) { - stopAlarmSound(); + stopAlarmSound();// 停止报警声音 finish(); } private void stopAlarmSound() { - if (mPlayer != null) { + if (mPlayer != null) {// 停止播放报警声音 mPlayer.stop(); mPlayer.release(); mPlayer = null; diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java index f221202..079fb23 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver.java @@ -1,19 +1,3 @@ -/* - * 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; import android.app.AlarmManager; @@ -27,12 +11,11 @@ import android.database.Cursor; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; - public class AlarmInitReceiver extends BroadcastReceiver { private static final String [] PROJECTION = new String [] { - NoteColumns.ID, - NoteColumns.ALERTED_DATE + NoteColumns.ID, + NoteColumns.ALERTED_DATE }; private static final int COLUMN_ID = 0; @@ -40,7 +23,9 @@ public class AlarmInitReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + // 获取当前系统时间 long currentDate = System.currentTimeMillis(); + // 查询具有提醒日期大于当前时间且类型为Notes.TYPE_NOTE的备忘录 Cursor c = context.getContentResolver().query(Notes.CONTENT_NOTE_URI, PROJECTION, NoteColumns.ALERTED_DATE + ">? AND " + NoteColumns.TYPE + "=" + Notes.TYPE_NOTE, @@ -50,16 +35,20 @@ public class AlarmInitReceiver extends BroadcastReceiver { if (c != null) { if (c.moveToFirst()) { do { + // 获取备忘录的提醒日期 long alertDate = c.getLong(COLUMN_ALERTED_DATE); + // 创建用于启动AlarmReceiver的Intent Intent sender = new Intent(context, AlarmReceiver.class); + // 将备忘录的URI作为数据添加到sender中 sender.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, c.getLong(COLUMN_ID))); + // 创建PendingIntent以便在提醒时间到达时触发 PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, sender, 0); - AlarmManager alermManager = (AlarmManager) context - .getSystemService(Context.ALARM_SERVICE); - alermManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); + // 获取AlarmManager服务,设置提醒时间以及PendingIntent + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + alarmManager.set(AlarmManager.RTC_WAKEUP, alertDate, pendingIntent); } while (c.moveToNext()); } - c.close(); + c.close(); // 关闭查询结果的游标 } } } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver_leitu.docx b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver_leitu.docx index e69de29..3fddfe8 100644 Binary files a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver_leitu.docx and b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmInitReceiver_leitu.docx differ diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java index 54e503b..aae5874 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/AlarmReceiver.java @@ -1,18 +1,3 @@ -/* - * 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; @@ -20,11 +5,23 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +/** + * 接收闹钟广播的接收器,用于启动提醒活动。 + */ public class AlarmReceiver extends BroadcastReceiver { + + /** + * 当接收到闹钟触发的广播时调用,启动提醒活动。 + * @param context 上下文对象 + * @param intent 包含触发广播信息的意图 + */ @Override public void onReceive(Context context, Intent intent) { + // 设置意图要启动的目标活动为AlarmAlertActivity intent.setClass(context, AlarmAlertActivity.class); + // 添加标志以指示启动新任务的活动 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // 启动目标活动 context.startActivity(intent); } } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePicker.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePicker.java index 496b0cd..493f088 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePicker.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePicker.java @@ -29,7 +29,7 @@ import android.widget.FrameLayout; import android.widget.NumberPicker; public class DateTimePicker extends FrameLayout { - + // 常量定义 private static final boolean DEFAULT_ENABLE_STATE = true; private static final int HOURS_IN_HALF_DAY = 12; @@ -45,13 +45,13 @@ public class DateTimePicker extends FrameLayout { private static final int MINUT_SPINNER_MAX_VAL = 59; private static final int AMPM_SPINNER_MIN_VAL = 0; private static final int AMPM_SPINNER_MAX_VAL = 1; - + // 控件变量声明 private final NumberPicker mDateSpinner; private final NumberPicker mHourSpinner; private final NumberPicker mMinuteSpinner; private final NumberPicker mAmPmSpinner; private Calendar mDate; - + // 其他变量声明 private String[] mDateDisplayValues = new String[DAYS_IN_ALL_WEEK]; private boolean mIsAm; @@ -63,7 +63,7 @@ public class DateTimePicker extends FrameLayout { private boolean mInitialising; private OnDateTimeChangedListener mOnDateTimeChangedListener; - + // 构造方法和接口定义 private NumberPicker.OnValueChangeListener mOnDateChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { @@ -72,7 +72,7 @@ public class DateTimePicker extends FrameLayout { onDateTimeChanged(); } }; - + //初始化DateTimePicker控件,关联布局文件,并设置相关监听器: private NumberPicker.OnValueChangeListener mOnHourChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { @@ -114,7 +114,7 @@ public class DateTimePicker extends FrameLayout { } } }; - + // 初始化各个NumberPicker控件 private NumberPicker.OnValueChangeListener mOnMinuteChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { @@ -143,7 +143,7 @@ public class DateTimePicker extends FrameLayout { onDateTimeChanged(); } }; - + // 设置AmPmSpinner控件 private NumberPicker.OnValueChangeListener mOnAmPmChangedListener = new NumberPicker.OnValueChangeListener() { @Override public void onValueChange(NumberPicker picker, int oldVal, int newVal) { @@ -157,12 +157,12 @@ public class DateTimePicker extends FrameLayout { onDateTimeChanged(); } }; - + // 更新控件到初始状态 public interface OnDateTimeChangedListener { void onDateTimeChanged(DateTimePicker view, int year, int month, int dayOfMonth, int hourOfDay, int minute); } - + // 设置为当前时间 public DateTimePicker(Context context) { this(context, System.currentTimeMillis()); } @@ -213,6 +213,8 @@ public class DateTimePicker extends FrameLayout { // set the content descriptions mInitialising = false; } +//监听器实现: +// 日期变化监听器 @Override public void setEnabled(boolean enabled) { @@ -226,12 +228,12 @@ public class DateTimePicker extends FrameLayout { mAmPmSpinner.setEnabled(enabled); mIsEnabled = enabled; } - + // 处理日期变化事件 @Override public boolean isEnabled() { return mIsEnabled; } - +// 小时变化监听器 /** * Get the current date in millis * @@ -240,7 +242,7 @@ public class DateTimePicker extends FrameLayout { public long getCurrentDateInTimeMillis() { return mDate.getTimeInMillis(); } - + // 处理小时变化事件 /** * Set the current date * @@ -252,7 +254,7 @@ public class DateTimePicker extends FrameLayout { setCurrentDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)); } - +// 分钟变化监听器 /** * Set the current date * @@ -270,7 +272,7 @@ public class DateTimePicker extends FrameLayout { setCurrentHour(hourOfDay); setCurrentMinute(minute); } - +// 处理分钟变化事件 /** * Get current year * @@ -279,7 +281,7 @@ public class DateTimePicker extends FrameLayout { public int getCurrentYear() { return mDate.get(Calendar.YEAR); } - +// 上午/下午变化监听器 /** * Set current year * @@ -291,14 +293,14 @@ public class DateTimePicker extends FrameLayout { } mDate.set(Calendar.YEAR, year); updateDateControl(); - onDateTimeChanged(); + onDateTimeChanged();// 处理上午/下午变化事件 } /** * Get current month in the year * * @return The current month in the year - */ + *///其他方法实现: public int getCurrentMonth() { return mDate.get(Calendar.MONTH); } @@ -310,7 +312,7 @@ public class DateTimePicker extends FrameLayout { */ public void setCurrentMonth(int month) { if (!mInitialising && month == getCurrentMonth()) { - return; + return; // 设置控件是否可用 } mDate.set(Calendar.MONTH, month); updateDateControl(); @@ -330,7 +332,7 @@ public class DateTimePicker extends FrameLayout { * Set current day of the month * * @param dayOfMonth The day of the month - */ + */// 获取控件是否可用状态 public void setCurrentDay(int dayOfMonth) { if (!mInitialising && dayOfMonth == getCurrentDay()) { return; @@ -343,7 +345,7 @@ public class DateTimePicker extends FrameLayout { /** * Get current hour in 24 hour mode, in the range (0~23) * @return The current hour in 24 hour mode - */ + */// 获取当前日期的时间戳 public int getCurrentHourOfDay() { return mDate.get(Calendar.HOUR_OF_DAY); } @@ -360,7 +362,7 @@ public class DateTimePicker extends FrameLayout { } } } - +// 设置当前日期 /** * Set current hour in 24 hour mode, in the range (0~23) * @@ -388,7 +390,7 @@ public class DateTimePicker extends FrameLayout { mHourSpinner.setValue(hourOfDay); onDateTimeChanged(); } - +// 设置具体的年、月、日、时、分 /** * Get currentMinute * @@ -409,7 +411,7 @@ public class DateTimePicker extends FrameLayout { mDate.set(Calendar.MINUTE, minute); onDateTimeChanged(); } - +// 如果不是初始化状态,并且输入的年份与当前年份相同,则直接返回 /** * @return true if this is in 24 hour view else false. */ @@ -421,7 +423,7 @@ public class DateTimePicker extends FrameLayout { * 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) { if (mIs24HourView == is24HourView) { return; @@ -433,7 +435,7 @@ public class DateTimePicker extends FrameLayout { setCurrentHour(hour); updateAmPmControl(); } - + // 更新日期控件 private void updateDateControl() { Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(mDate.getTimeInMillis()); @@ -447,7 +449,7 @@ public class DateTimePicker extends FrameLayout { mDateSpinner.setValue(DAYS_IN_ALL_WEEK / 2); mDateSpinner.invalidate(); } - + // 触发日期时间改变回调 private void updateAmPmControl() { if (mIs24HourView) { mAmPmSpinner.setVisibility(View.GONE); diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java index 2c47ba4..31294a5 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DateTimePickerDialog.java @@ -1,19 +1,3 @@ -/* - * 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; import java.util.Calendar; @@ -29,6 +13,9 @@ import android.content.DialogInterface.OnClickListener; import android.text.format.DateFormat; import android.text.format.DateUtils; +/** + * 自定义日期时间选择对话框,继承自AlertDialog,实现OnClickListener接口。 + */ public class DateTimePickerDialog extends AlertDialog implements OnClickListener { private Calendar mDate = Calendar.getInstance(); @@ -36,17 +23,25 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener private OnDateTimeSetListener mOnDateTimeSetListener; private DateTimePicker mDateTimePicker; + /** + * 日期时间设置监听器接口,用于处理日期时间设置的回调。 + */ public interface OnDateTimeSetListener { void OnDateTimeSet(AlertDialog dialog, long date); } + /** + * 构造方法,初始化日期时间选择对话框。 + * @param context 上下文对象 + * @param date 初始日期时间 + */ public DateTimePickerDialog(Context context, long date) { super(context); mDateTimePicker = new DateTimePicker(context); setView(mDateTimePicker); mDateTimePicker.setOnDateTimeChangedListener(new OnDateTimeChangedListener() { public void onDateTimeChanged(DateTimePicker view, int year, int month, - int dayOfMonth, int hourOfDay, int minute) { + int dayOfMonth, int hourOfDay, int minute) { mDate.set(Calendar.YEAR, year); mDate.set(Calendar.MONTH, month); mDate.set(Calendar.DAY_OF_MONTH, dayOfMonth); @@ -64,27 +59,42 @@ public class DateTimePickerDialog extends AlertDialog implements OnClickListener updateTitle(mDate.getTimeInMillis()); } + /** + * 设置小时制(12小时制/24小时制)。 + * @param is24HourView 是否为24小时制 + */ public void set24HourView(boolean is24HourView) { mIs24HourView = is24HourView; } + /** + * 设置日期时间设置监听器。 + * @param callBack 日期时间设置监听器对象 + */ public void setOnDateTimeSetListener(OnDateTimeSetListener callBack) { mOnDateTimeSetListener = callBack; } + /** + * 更新对话框标题显示当前日期时间。 + * @param date 当前日期时间的时间戳 + */ private void updateTitle(long date) { int flag = - DateUtils.FORMAT_SHOW_YEAR | - DateUtils.FORMAT_SHOW_DATE | - DateUtils.FORMAT_SHOW_TIME; + DateUtils.FORMAT_SHOW_YEAR | + DateUtils.FORMAT_SHOW_DATE | + DateUtils.FORMAT_SHOW_TIME; flag |= mIs24HourView ? DateUtils.FORMAT_24HOUR : DateUtils.FORMAT_24HOUR; setTitle(DateUtils.formatDateTime(this.getContext(), date, flag)); } + /** + * 处理点击事件,执行日期时间设置回调。 + */ public void onClick(DialogInterface arg0, int arg1) { if (mOnDateTimeSetListener != null) { mOnDateTimeSetListener.OnDateTimeSet(this, mDate.getTimeInMillis()); } } -} \ No newline at end of file +} diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DropdownMenu.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DropdownMenu.java index 613dc74..d91aa75 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DropdownMenu.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/DropdownMenu.java @@ -1,19 +1,3 @@ -/* - * 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; import android.content.Context; @@ -28,33 +12,37 @@ import android.widget.PopupMenu.OnMenuItemClickListener; import net.micode.notes.R; public class DropdownMenu { - private Button mButton; - private PopupMenu mPopupMenu; - private Menu mMenu; + private Button mButton; // 按钮实例 + private PopupMenu mPopupMenu; // 弹出菜单实例 + private Menu mMenu; // 菜单实例 + // 构造函数,接受上下文Context、按钮Button和菜单资源ID作为参数 public DropdownMenu(Context context, Button button, int menuId) { mButton = button; - mButton.setBackgroundResource(R.drawable.dropdown_icon); - mPopupMenu = new PopupMenu(context, mButton); - mMenu = mPopupMenu.getMenu(); - mPopupMenu.getMenuInflater().inflate(menuId, mMenu); + mButton.setBackgroundResource(R.drawable.dropdown_icon); // 设置按钮背景图标 + mPopupMenu = new PopupMenu(context, mButton); // 创建弹出菜单对象,关联到按钮 + mMenu = mPopupMenu.getMenu(); // 获取弹出菜单的菜单对象 + mPopupMenu.getMenuInflater().inflate(menuId, mMenu); // 从指定菜单资源文件加载菜单项 mButton.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mPopupMenu.show(); + public void onClick(View v) { // 设置按钮点击监听器 + mPopupMenu.show(); // 显示弹出菜单 } }); } + // 设置下拉菜单项点击监听器 public void setOnDropdownMenuItemClickListener(OnMenuItemClickListener listener) { if (mPopupMenu != null) { mPopupMenu.setOnMenuItemClickListener(listener); } } + // 根据菜单项ID查找菜单项 public MenuItem findItem(int id) { return mMenu.findItem(id); } + // 设置按钮文本 public void setTitle(CharSequence title) { mButton.setText(title); } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java index bb9fe0d..05fc06c 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/FoldersListAdapter.java @@ -1,19 +1,3 @@ -/* - * 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; import android.content.Context; @@ -28,26 +12,29 @@ import net.micode.notes.R; import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; - public class FoldersListAdapter extends CursorAdapter { - protected static final String [] PROJECTION = { - NoteColumns.ID, - NoteColumns.SNIPPET + // 定义投影,表示从Cursor中读取的数据列 + public static final String[] PROJECTION = { + NoteColumns.ID, + NoteColumns.SNIPPET }; - public static final int ID_COLUMN = 0; + // 定义数据列的索引 + public static final int ID_COLUMN = 0; public static final int NAME_COLUMN = 1; + // 构造函数,接受上下文Context和游标Cursor作为参数 public FoldersListAdapter(Context context, Cursor c) { super(context, c); - // TODO Auto-generated constructor stub } + // 创建新的视图 @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { return new FolderListItem(context); } + // 绑定视图 @Override public void bindView(View view, Context context, Cursor cursor) { if (view instanceof FolderListItem) { @@ -57,24 +44,27 @@ public class FoldersListAdapter extends CursorAdapter { } } + // 获取文件夹名字 public String getFolderName(Context context, int position) { Cursor cursor = (Cursor) getItem(position); return (cursor.getLong(ID_COLUMN) == Notes.ID_ROOT_FOLDER) ? context .getString(R.string.menu_move_parent_folder) : cursor.getString(NAME_COLUMN); } + // 内部类,表示文件夹列表中的单个项 private class FolderListItem extends LinearLayout { private TextView mName; + // 构造函数,初始化视图 public FolderListItem(Context context) { super(context); - inflate(context, R.layout.folder_list_item, this); - mName = (TextView) findViewById(R.id.tv_folder_name); + inflate(context, R.layout.folder_list_item, this); // 填充布局 + mName = (TextView) findViewById(R.id.tv_folder_name); // 找到子视图 } + // 绑定数据到视图 public void bind(String name) { - mName.setText(name); + mName.setText(name); // 设置文件夹名字到文本视图 } } - } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java index d48148c..9b9d24c 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditActivity.java @@ -1,218 +1,74 @@ -/* - * 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; - -import android.app.Activity; -import android.app.AlarmManager; -import android.app.AlertDialog; -import android.app.PendingIntent; -import android.app.SearchManager; -import android.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Paint; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.style.BackgroundColorSpan; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.WindowManager; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.model.WorkingNote; -import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser; -import net.micode.notes.tool.ResourceParser.TextAppearanceResources; -import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; -import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; -import net.micode.notes.widget.NoteWidgetProvider_2x; -import net.micode.notes.widget.NoteWidgetProvider_4x; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - +//继承Activity类 实现点击监听 文本监听 public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { private class HeadViewHolder { + //文本框 public TextView tvModified; - + //图片 public ImageView ivAlertIcon; - + //文本框 public TextView tvAlertDate; - + //图片 public ImageView ibSetBgColor; - - public HeadViewHolder() { - } - - public HeadViewHolder(TextView tvModified, ImageView ivAlertIcon, TextView tvAlertDate, ImageView ibSetBgColor) { - this.tvModified = tvModified; - this.ivAlertIcon = ivAlertIcon; - this.tvAlertDate = tvAlertDate; - this.ibSetBgColor = ibSetBgColor; - } - - /** - * 获取 - * @return tvModified - */ - public TextView getTvModified() { - return tvModified; - } - - /** - * 设置 - * @param tvModified - */ - public void setTvModified(TextView tvModified) { - this.tvModified = tvModified; - } - - /** - * 获取 - * @return ivAlertIcon - */ - public ImageView getIvAlertIcon() { - return ivAlertIcon; - } - - /** - * 设置 - * @param ivAlertIcon - */ - public void setIvAlertIcon(ImageView ivAlertIcon) { - this.ivAlertIcon = ivAlertIcon; - } - - /** - * 获取 - * @return tvAlertDate - */ - public TextView getTvAlertDate() { - return tvAlertDate; - } - - /** - * 设置 - * @param tvAlertDate - */ - public void setTvAlertDate(TextView tvAlertDate) { - this.tvAlertDate = tvAlertDate; - } - - /** - * 获取 - * @return ibSetBgColor - */ - public ImageView getIbSetBgColor() { - return ibSetBgColor; - } - - /** - * 设置 - * @param ibSetBgColor - */ - public void setIbSetBgColor(ImageView ibSetBgColor) { - this.ibSetBgColor = ibSetBgColor; - } - - public String toString() { - return "HeadViewHolder{tvModified = " + tvModified + ", ivAlertIcon = " + ivAlertIcon + ", tvAlertDate = " + tvAlertDate + ", ibSetBgColor = " + ibSetBgColor + "}"; - } } + //实例化HashMap对象 以键值对方式存储 private static final Map sBgSelectorBtnsMap = new HashMap(); static { + //存放资源id sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); } - + //实例化HashMap对象 private static final Map sBgSelectorSelectionMap = new HashMap(); static { + //存放资源id sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); } - + //实例化HashMap对象 private static final Map sFontSizeBtnsMap = new HashMap(); static { + //存放资源id sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); } - + //实例化HashMap对象 private static final Map sFontSelectorSelectionMap = new HashMap(); static { + //存放资源id sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); } - + //定义一个静态的私密的不允许修改的TAG值 private static final String TAG = "NoteEditActivity"; - + //适配器 配合listView使用 private HeadViewHolder mNoteHeaderHolder; - + //所有控件的基类 private View mHeadViewPanel; - + //所有控件的基类 private View mNoteBgColorSelector; - + //所有控件的基类 private View mFontSizeSelector; - + //文本框 private EditText mNoteEditor; - + //所有控件的基类 private View mNoteEditorPanel; - + //自定义类 private WorkingNote mWorkingNote; - + //轻量级的存储辅助类 private SharedPreferences mSharedPrefs; + // private int mFontSizeId; private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; @@ -221,21 +77,23 @@ public class NoteEditActivity extends Activity implements OnClickListener, public static final String TAG_CHECKED = String.valueOf('\u221A'); public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); - + //布局 private LinearLayout mEditTextList; private String mUserQuery; + //正则表达 private Pattern mPattern; - + //重写方法 参数是保存了activity的状态 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(R.layout.note_edit); - + //如果activity生命周期结束或者得不到intent 则销毁当前activity if (savedInstanceState == null && !initActivityState(getIntent())) { finish(); return; } + //初始化资源 initResources(); } @@ -243,12 +101,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, * Current activity may be killed when the memory is low. Once it is killed, for another time * user load this activity, we should restore the former state */ + //重写方法 @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { Intent intent = new Intent(Intent.ACTION_VIEW); + //intent中存放UID信息 intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); + //如果 if (!initActivityState(intent)) { finish(); return; @@ -256,13 +117,14 @@ public class NoteEditActivity extends Activity implements OnClickListener, Log.d(TAG, "Restoring from killed activity"); } } - + //初始化 private boolean initActivityState(Intent intent) { /** * If the user specified the {@link Intent#ACTION_VIEW} but not provided with id, * then jump to the NotesListActivity */ mWorkingNote = null; + //如果两者相等 if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); mUserQuery = ""; @@ -270,15 +132,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, /** * Starting from the searched result */ + //如果intent的传递值存在 if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); } if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { + //创建从当前页面前往NotesListActivity的intent Intent jump = new Intent(this, NotesListActivity.class); + //启动意图 startActivity(jump); + //显示提示 showToast(R.string.error_note_not_exist); + //结束当前页面生命周期 finish(); return false; } else { @@ -289,11 +156,13 @@ public class NoteEditActivity extends Activity implements OnClickListener, return false; } } + //弹出软键盘 getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { // New note + //获取intent中的信息 long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); @@ -305,7 +174,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, // Parse call-record note String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); + //callDate和phoneNumber不为空 if (callDate != 0 && phoneNumber != null) { + //判断电话是否为空 if (TextUtils.isEmpty(phoneNumber)) { Log.w(TAG, "The call record number is null"); } @@ -339,28 +210,32 @@ public class NoteEditActivity extends Activity implements OnClickListener, mWorkingNote.setOnSettingStatusChangedListener(this); return true; } - + //重写方法 @Override protected void onResume() { super.onResume(); initNoteScreen(); } - + //初始化 private void initNoteScreen() { + //AndroidTextAppearance 属性是一个特殊的属性,用于将特定的文本样式应用到你的View 组件 mNoteEditor.setTextAppearance(this, TextAppearanceResources .getTexAppearanceResource(mFontSizeId)); if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { switchToListMode(mWorkingNote.getContent()); } else { mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + //setSelection可以让ListView跳转到某个item显示 mNoteEditor.setSelection(mNoteEditor.getText().length()); } for (Integer id : sBgSelectorSelectionMap.keySet()) { + //设置可见性 findViewById(sBgSelectorSelectionMap.get(id)).setVisibility(View.GONE); } + //设置控件的背景图片 mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - + //对日期进行格式转换 mNoteHeaderHolder.tvModified.setText(DateUtils.formatDateTime(this, mWorkingNote.getModifiedDate(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE | DateUtils.FORMAT_SHOW_TIME @@ -375,13 +250,17 @@ public class NoteEditActivity extends Activity implements OnClickListener, private void showAlertHeader() { if (mWorkingNote.hasClockAlert()) { + //获取当前的总毫秒数 long time = System.currentTimeMillis(); + //如果时间大于便签的时间 if (time > mWorkingNote.getAlertDate()) { mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); } else { + //显示过去的相对时间 mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); } + //设置可见性 mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); } else { @@ -389,13 +268,13 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); }; } - + //重写方法 @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); initActivityState(intent); } - + //重写方法 @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -410,23 +289,25 @@ public class NoteEditActivity extends Activity implements OnClickListener, outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); } - + //重写方法 @Override public boolean dispatchTouchEvent(MotionEvent ev) { + //判断点击的位置是不是在指定的组件上 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mNoteBgColorSelector, ev)) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } - + //判断点击的位置是不是在指定的组件上 if (mFontSizeSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mFontSizeSelector, ev)) { mFontSizeSelector.setVisibility(View.GONE); return true; } + //触摸传递事件 return super.dispatchTouchEvent(ev); } - + //判断点击的位置是不是在指定的组件上 private boolean inRangeOfView(View view, MotionEvent ev) { int []location = new int[2]; view.getLocationOnScreen(location); @@ -436,14 +317,16 @@ public class NoteEditActivity extends Activity implements OnClickListener, || ev.getX() > (x + view.getWidth()) || ev.getY() < y || ev.getY() > (y + view.getHeight())) { - return false; - } + return false; + } return true; } - + //初始化 private void initResources() { mHeadViewPanel = findViewById(R.id.note_title); + //为listView快速设置值 mNoteHeaderHolder = new HeadViewHolder(); + //设置对应的一系列值 mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); @@ -452,17 +335,21 @@ public class NoteEditActivity extends Activity implements OnClickListener, mNoteEditor = (EditText) findViewById(R.id.note_edit_view); mNoteEditorPanel = findViewById(R.id.sv_note_edit); mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); + //遍历key 设置图片 for (int id : sBgSelectorBtnsMap.keySet()) { ImageView iv = (ImageView) findViewById(id); iv.setOnClickListener(this); } mFontSizeSelector = findViewById(R.id.font_size_selector); + //遍历key 设置view组件 for (int id : sFontSizeBtnsMap.keySet()) { View view = findViewById(id); view.setOnClickListener(this); }; + //轻量级的存储类 mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); + //获取存储的数据 mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); /** * HACKME: Fix bug of store the resource id in shared preference. @@ -472,9 +359,10 @@ public class NoteEditActivity extends Activity implements OnClickListener, if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } + //设置LinearLayout组件 mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); } - + //重写方法 @Override protected void onPause() { super.onPause(); @@ -485,6 +373,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } private void updateWidget() { + //创建intent实例 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { intent.setClass(this, NoteWidgetProvider_2x.class); @@ -494,18 +383,20 @@ public class NoteEditActivity extends Activity implements OnClickListener, Log.e(TAG, "Unspported widget type"); return; } - + //在intent中存放信息 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - mWorkingNote.getWidgetId() + mWorkingNote.getWidgetId() }); - + //发送广播 sendBroadcast(intent); + //回传数据 setResult(RESULT_OK, intent); } public void onClick(View v) { int id = v.getId(); if (id == R.id.btn_set_bg_color) { + //设置组件可见性 mNoteBgColorSelector.setVisibility(View.VISIBLE); findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.VISIBLE); @@ -517,91 +408,113 @@ public class NoteEditActivity extends Activity implements OnClickListener, } else if (sFontSizeBtnsMap.containsKey(id)) { findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); mFontSizeId = sFontSizeBtnsMap.get(id); + //在存储类中存储信息 mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { getWorkingText(); switchToListMode(mWorkingNote.getContent()); } else { + //设置view的特定文本格式 mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); } + //设置为不可见 mFontSizeSelector.setVisibility(View.GONE); } } - + //重写方法 @Override public void onBackPressed() { if(clearSettingState()) { return; } - + //保存便签 saveNote(); super.onBackPressed(); } - + // private boolean clearSettingState() { + //如果mNoteBgColorSelector为visible则设置为GONE 不占据空间 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { mNoteBgColorSelector.setVisibility(View.GONE); return true; + //同上 } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { mFontSizeSelector.setVisibility(View.GONE); return true; } return false; } - + //背景颜色变化 public void onBackgroundColorChanged() { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); + //设置背景资源 mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); + //设置背景资源 mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } - + //重写方法 @Override public boolean onPrepareOptionsMenu(Menu menu) { if (isFinishing()) { return true; } clearSettingState(); + //清理菜单 menu.clear(); if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { + //将xml定义的一个布局找出来 getMenuInflater().inflate(R.menu.call_note_edit, menu); } else { + //将xml定义的一个布局找出来 getMenuInflater().inflate(R.menu.note_edit, menu); } if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + //通过id来得到munu item组件 menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); } else { + //通过id来得到munu item组件 menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); } if (mWorkingNote.hasClockAlert()) { + //通过id来得到munu item组件 menu.findItem(R.id.menu_alert).setVisible(false); } else { + //通过id来得到munu item组件 menu.findItem(R.id.menu_delete_remind).setVisible(false); } return true; } - + //重写方法 @Override public boolean onOptionsItemSelected(MenuItem item) { + //根据itemid来分情况运行 switch (item.getItemId()) { case R.id.menu_new_note: + //创建新便签 createNewNote(); break; case R.id.menu_delete: + //创建对话框 AlertDialog.Builder builder = new AlertDialog.Builder(this); + //设置对话框基本信息 builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(getString(R.string.alert_message_delete_note)); + //设置确认按钮点击事件 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { + //删除便签 deleteCurrentNote(); + //退出当前页面 finish(); } }); builder.setNegativeButton(android.R.string.cancel, null); + //显示对话框 builder.show(); break; case R.id.menu_font_size: @@ -632,12 +545,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, } private void setReminder() { + //日期时间选择控件 DateTimePickerDialog d = new DateTimePickerDialog(this, System.currentTimeMillis()); + //点击事件 d.setOnDateTimeSetListener(new OnDateTimeSetListener() { public void OnDateTimeSet(AlertDialog dialog, long date) { mWorkingNote.setAlertDate(date , true); } }); + //显示控件 d.show(); } @@ -646,46 +562,57 @@ public class NoteEditActivity extends Activity implements OnClickListener, * and {@text/plain} type */ private void sendTo(Context context, String info) { + //创建意图 Intent intent = new Intent(Intent.ACTION_SEND); + //传递数据 intent.putExtra(Intent.EXTRA_TEXT, info); intent.setType("text/plain"); + //启动 context.startActivity(intent); } - + //创建新便签 private void createNewNote() { // Firstly, save current editing notes saveNote(); // For safety, start a new NoteEditActivity finish(); + //创建意图 Intent intent = new Intent(this, NoteEditActivity.class); + //设置行为 intent.setAction(Intent.ACTION_INSERT_OR_EDIT); + //存放信息 intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); + //启动 startActivity(intent); } - + //删除 private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { HashSet ids = new HashSet(); + //获取NoteId long id = mWorkingNote.getNoteId(); if (id != Notes.ID_ROOT_FOLDER) { ids.add(id); } else { + //日志打印 Log.d(TAG, "Wrong note id, should not happen"); } if (!isSyncMode()) { if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { + //日志打印 Log.e(TAG, "Delete Note error"); } } else { if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { + //日志打印 Log.e(TAG, "Move notes to trash folder error, should not happens"); } } } mWorkingNote.markDeleted(true); } - + // private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } @@ -698,15 +625,22 @@ public class NoteEditActivity extends Activity implements OnClickListener, if (!mWorkingNote.existInDatabase()) { saveNote(); } + //如果便签存在 if (mWorkingNote.getNoteId() > 0) { + //创建意图 Intent intent = new Intent(this, AlarmReceiver.class); + //设置信息 intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); + //本质是intent的封装 PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); + //定时任务 AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); showAlertHeader(); if(!set) { + //如果没有设置则取消意图 alarmManager.cancel(pendingIntent); } else { + //设置定时 alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); } } else { @@ -716,6 +650,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, * should input something */ Log.e(TAG, "Clock alert setting error"); + //显示提示框 showToast(R.string.error_note_empty_for_clock); } } @@ -723,18 +658,18 @@ public class NoteEditActivity extends Activity implements OnClickListener, public void onWidgetChanged() { updateWidget(); } - + //删除编辑文本框 public void onEditTextDelete(int index, String text) { int childCount = mEditTextList.getChildCount(); if (childCount == 1) { return; } - + //遍历 设置index for (int i = index + 1; i < childCount; i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) .setIndex(i - 1); } - + //移除子控件 mEditTextList.removeViewAt(index); NoteEditText edit = null; if(index == 0) { @@ -745,7 +680,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, R.id.et_edit_text); } int length = edit.length(); + //添加文本 edit.append(text); + //获取聚焦 edit.requestFocus(); edit.setSelection(length); } @@ -754,14 +691,18 @@ public class NoteEditActivity extends Activity implements OnClickListener, /** * Should not happen, check for debug */ + //如果index超出了现有的数量则报错 if(index > mEditTextList.getChildCount()) { Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); } - + //获取对应的view组件 View view = getListItem(text, index); + //动态添加view mEditTextList.addView(view, index); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + //请求获取焦点 edit.requestFocus(); + //让list跳转到第一个组件显示 edit.setSelection(0); for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) @@ -770,6 +711,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, } private void switchToListMode(String text) { + mEditTextList.removeAllViews(); String[] items = text.split("\n"); int index = 0; @@ -779,17 +721,21 @@ public class NoteEditActivity extends Activity implements OnClickListener, index++; } } + //添加子控件 mEditTextList.addView(getListItem("", index)); mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - + //设置可见性 mNoteEditor.setVisibility(View.GONE); mEditTextList.setVisibility(View.VISIBLE); } private Spannable getHighlightQueryResult(String fullText, String userQuery) { + //可以在字符序列基础上对指定的字符进行润饰 SpannableString spannable = new SpannableString(fullText == null ? "" : fullText); + //如果userQuery不为空 if (!TextUtils.isEmpty(userQuery)) { mPattern = Pattern.compile(userQuery); + //Matcher提供了对正则表达式的匹配 Matcher m = mPattern.matcher(fullText); int start = 0; while (m.find(start)) { @@ -802,22 +748,25 @@ public class NoteEditActivity extends Activity implements OnClickListener, } return spannable; } - + //根据item index获取子控件 private View getListItem(String item, int index) { View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + //设置指定样式 edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); + //监听复选框状态变化 cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { + //设置删除线 edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); } else { edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); } } }); - + //判断是否以指定字符串开头 if (item.startsWith(TAG_CHECKED)) { cb.setChecked(true); edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); @@ -827,18 +776,21 @@ public class NoteEditActivity extends Activity implements OnClickListener, edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); } - + //设置监听事件 edit.setOnTextViewChangeListener(this); + //设置相关属性 edit.setIndex(index); edit.setText(getHighlightQueryResult(item, mUserQuery)); return view; } - + //改变文本 public void onTextChange(int index, boolean hasText) { + //判断index是否合法 if (index >= mEditTextList.getChildCount()) { Log.e(TAG, "Wrong index, should not happen"); return; } + //如果存在文本 就获取相应的子控件 if(hasText) { mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); } else { @@ -854,7 +806,9 @@ public class NoteEditActivity extends Activity implements OnClickListener, mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", "")); } + //设置文本 mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); + //设置可见性 mEditTextList.setVisibility(View.GONE); mNoteEditor.setVisibility(View.VISIBLE); } @@ -863,12 +817,15 @@ public class NoteEditActivity extends Activity implements OnClickListener, private boolean getWorkingText() { boolean hasChecked = false; if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { + //字符串类 StringBuilder sb = new StringBuilder(); for (int i = 0; i < mEditTextList.getChildCount(); i++) { View view = mEditTextList.getChildAt(i); NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); + //判断是否为空 if (!TextUtils.isEmpty(edit.getText())) { if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { + //添加 sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); hasChecked = true; } else { @@ -894,6 +851,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, * new node requires to the top of the list. This code * {@link #RESULT_OK} is used to identify the create/edit state */ + //传回数据 setResult(RESULT_OK); } return saved; @@ -906,13 +864,17 @@ public class NoteEditActivity extends Activity implements OnClickListener, * save it */ if (!mWorkingNote.existInDatabase()) { + //保存便签 saveNote(); } if (mWorkingNote.getNoteId() > 0) { + //创建意图 Intent sender = new Intent(); Intent shortcutIntent = new Intent(this, NoteEditActivity.class); + //设置启动对象 shortcutIntent.setAction(Intent.ACTION_VIEW); + //存放数据 shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, @@ -930,6 +892,7 @@ public class NoteEditActivity extends Activity implements OnClickListener, * should input something */ Log.e(TAG, "Send to desktop error"); + //显示消息提示框 showToast(R.string.error_note_empty_for_send_to_desktop); } } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditText.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditText.java index 2afe2a8..3bfcc39 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditText.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteEditText.java @@ -1,18 +1,3 @@ -/* - * 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; @@ -48,35 +33,35 @@ public class NoteEditText extends EditText { private static final Map sSchemaActionResMap = new HashMap(); static { + // 不同的schema对应不同的操作提示 sSchemaActionResMap.put(SCHEME_TEL, R.string.note_link_tel); sSchemaActionResMap.put(SCHEME_HTTP, R.string.note_link_web); sSchemaActionResMap.put(SCHEME_EMAIL, R.string.note_link_email); } /** - * Call by the {@link NoteEditActivity} to delete or add edit text + * 由 {@link NoteEditActivity} 调用,用于删除或添加编辑文本 */ public interface OnTextViewChangeListener { /** - * Delete current edit text when {@link KeyEvent#KEYCODE_DEL} happens - * and the text is null + * 当发生 {@link KeyEvent#KEYCODE_DEL} 并且文本为null时,删除当前编辑文本 */ void onEditTextDelete(int index, String text); /** - * Add edit text after current edit text when {@link KeyEvent#KEYCODE_ENTER} - * happen + * 在发生 {@link KeyEvent#KEYCODE_ENTER} 时,在当前编辑文本后添加编辑文本 */ void onEditTextEnter(int index, String text); /** - * Hide or show item option when text change + * 当文本改变时,隐藏或显示项目选项 */ void onTextChange(int index, boolean hasText); } private OnTextViewChangeListener mOnTextViewChangeListener; + // 构造函数 public NoteEditText(Context context) { super(context, null); mIndex = 0; @@ -90,13 +75,14 @@ public class NoteEditText extends EditText { mOnTextViewChangeListener = listener; } + // 构造函数 public NoteEditText(Context context, AttributeSet attrs) { super(context, attrs, android.R.attr.editTextStyle); } + // 构造函数 public NoteEditText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - // TODO Auto-generated constructor stub } @Override @@ -114,7 +100,7 @@ public class NoteEditText extends EditText { Layout layout = getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); - Selection.setSelection(getText(), off); + Selection.setSelection(getText(), off); // 设置选中文本位置 break; } @@ -148,7 +134,7 @@ public class NoteEditText extends EditText { return true; } } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); + Log.d(TAG, "OnTextViewChangeListener was not set"); } break; case KeyEvent.KEYCODE_ENTER: @@ -158,7 +144,7 @@ public class NoteEditText extends EditText { setText(getText().subSequence(0, selectionStart)); mOnTextViewChangeListener.onEditTextEnter(mIndex + 1, text); } else { - Log.d(TAG, "OnTextViewChangeListener was not seted"); + Log.d(TAG, "OnTextViewChangeListener was not set"); } break; default: @@ -205,7 +191,7 @@ public class NoteEditText extends EditText { menu.add(0, 0, 0, defaultResId).setOnMenuItemClickListener( new OnMenuItemClickListener() { public boolean onMenuItemClick(MenuItem item) { - // goto a new intent + // 转到新的意图 urls[0].onClick(NoteEditText.this); return true; } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteItemData.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteItemData.java index 0f5a878..e5ce9b8 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteItemData.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NoteItemData.java @@ -1,19 +1,3 @@ -/* - * 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; import android.content.Context; @@ -25,23 +9,25 @@ import net.micode.notes.data.Notes; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.tool.DataUtils; - +// 笔记项数据类 public class NoteItemData { + // 查询列数组 static final String [] PROJECTION = new String [] { - NoteColumns.ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.CREATED_DATE, - NoteColumns.HAS_ATTACHMENT, - NoteColumns.MODIFIED_DATE, - NoteColumns.NOTES_COUNT, - NoteColumns.PARENT_ID, - NoteColumns.SNIPPET, - NoteColumns.TYPE, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, + NoteColumns.ID, + NoteColumns.ALERTED_DATE, + NoteColumns.BG_COLOR_ID, + NoteColumns.CREATED_DATE, + NoteColumns.HAS_ATTACHMENT, + 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; @@ -76,6 +62,7 @@ public class NoteItemData { private boolean mIsOneNoteFollowingFolder; private boolean mIsMultiNotesFollowingFolder; + // 构造方法 public NoteItemData(Context context, Cursor cursor) { mId = cursor.getLong(ID_COLUMN); mAlertDate = cursor.getLong(ALERTED_DATE_COLUMN); @@ -109,6 +96,7 @@ public class NoteItemData { checkPostion(cursor); } + // 检查位置方法 private void checkPostion(Cursor cursor) { mIsLastItem = cursor.isLast() ? true : false; mIsFirstItem = cursor.isFirst() ? true : false; @@ -134,90 +122,112 @@ public class NoteItemData { } } + // 是否跟随文件夹中有一个笔记 public boolean isOneFollowingFolder() { return mIsOneNoteFollowingFolder; } + // 是否跟随文件夹中有多个笔记 public boolean isMultiFollowingFolder() { return mIsMultiNotesFollowingFolder; } + // 是否最后一个 public boolean isLast() { return mIsLastItem; } + // 获取通话联系人名字 public String getCallName() { return mName; } + // 是否第一个 public boolean isFirst() { return mIsFirstItem; } + // 是否仅为单个 public boolean isSingle() { return mIsOnlyOneItem; } + // 获取笔记项 ID public long getId() { return mId; } + // 获取提醒日期 public long getAlertDate() { return mAlertDate; } + // 获取创建日期 public long getCreatedDate() { return mCreatedDate; } + // 是否有附件 public boolean hasAttachment() { return mHasAttachment; } + // 获取最近修改日期 public long getModifiedDate() { return mModifiedDate; } + // 获取背景颜色 ID public int getBgColorId() { return mBgColorId; } + // 获取父项 ID public long getParentId() { return mParentId; } + // 获取笔记数 public int getNotesCount() { return mNotesCount; } + // 获取文件夹 ID public long getFolderId () { return mParentId; } + // 获取类型 public int getType() { return mType; } + // 获取小部件类型 public int getWidgetType() { return mWidgetType; } + // 获取小部件 ID public int getWidgetId() { return mWidgetId; } + // 获取摘要 public String getSnippet() { return mSnippet; } + // 是否有提醒 public boolean hasAlert() { return (mAlertDate > 0); } + // 是否为通话记录 public boolean isCallRecord() { return (mParentId == Notes.ID_CALL_RECORD_FOLDER && !TextUtils.isEmpty(mPhoneNumber)); } + // 根据游标获取笔记类型 public static int getNoteType(Cursor cursor) { return cursor.getInt(TYPE_COLUMN); } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListActivity.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListActivity.java index e843aec..4055184 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListActivity.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListActivity.java @@ -77,8 +77,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashSet; - -public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { +//主界面,一进入就是这个界面 +/** + * @author k + * + */ +public class NotesListActivity extends Activity implements OnClickListener, OnItemLongClickListener { //没有用特定的标签加注释。。。感觉没有什么用 private static final int FOLDER_NOTE_LIST_QUERY_TOKEN = 0; private static final int FOLDER_LIST_QUERY_TOKEN = 1; @@ -89,7 +93,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt private static final int MENU_FOLDER_CHANGE_NAME = 2; - private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; + private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction"; //单行超过80个字符 private enum ListEditState { NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER @@ -136,8 +140,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt private final static int REQUEST_CODE_NEW_NODE = 103; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + // 创建类 + protected void onCreate(final Bundle savedInstanceState) { //需要是final类型 根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。 + // final类不能被继承,没有子类,final类中的方法默认是final的。 + //final方法不能被子类的方法覆盖,但可以被继承。 + //final成员变量表示常量,只能被赋值一次,赋值后值不再改变。 + //final不能用于修饰构造方法。 + super.onCreate(savedInstanceState); // 调用父类的onCreate函数 setContentView(R.layout.note_list); initResources(); @@ -148,26 +157,32 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } @Override + // 返回一些子模块完成的数据交给主Activity处理 protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // 结果值 和 要求值 符合要求 if (resultCode == RESULT_OK && (requestCode == REQUEST_CODE_OPEN_NODE || requestCode == REQUEST_CODE_NEW_NODE)) { mNotesListAdapter.changeCursor(null); } else { super.onActivityResult(requestCode, resultCode, data); + // 调用 Activity 的onActivityResult() } } private void setAppInfoFromRawRes() { + // Android平台给我们提供了一个SharedPreferences类,它是一个轻量级的存储类,特别适合用于保存软件配置参数。 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) { StringBuilder sb = new StringBuilder(); InputStream in = null; try { - in = getResources().openRawResource(R.raw.introduction); + // 把资源文件放到应用程序的/raw/raw下,那么就可以在应用中使用getResources获取资源后, + // 以openRawResource方法(不带后缀的资源文件名)打开这个文件。 + in = getResources().openRawResource(R.raw.introduction); if (in != null) { InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr); - char [] buf = new char[1024]; + char [] buf = new char[1024]; // 自行定义的数值,使用者不知道有什么意义 int len = 0; while ((len = br.read(buf)) > 0) { sb.append(buf, 0, len); @@ -180,7 +195,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt e.printStackTrace(); return; } finally { - if(in != null) { + if (in != null) { try { in.close(); } catch (IOException e) { @@ -190,11 +205,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } } + // 创建空的WorkingNote WorkingNote note = WorkingNote.createEmptyNote(this, Notes.ID_ROOT_FOLDER, AppWidgetManager.INVALID_APPWIDGET_ID, Notes.TYPE_WIDGET_INVALIDE, ResourceParser.RED); note.setWorkingText(sb.toString()); if (note.saveNote()) { + // 更新保存note的信息 sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit(); } else { Log.e(TAG, "Save introduction note error"); @@ -209,18 +226,21 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt startAsyncNotesListQuery(); } + // 初始化资源 private void initResources() { - mContentResolver = this.getContentResolver(); + mContentResolver = this.getContentResolver(); // 获取应用程序的数据,得到类似数据表的东西 mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver()); mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mNotesListView = (ListView) findViewById(R.id.notes_list); + + // findViewById 是安卓编程的定位函数,主要是引用.R文件里的引用名 + mNotesListView = (ListView) findViewById(R.id.notes_list); // 绑定XML中的ListView,作为Item的容器 mNotesListView.addFooterView(LayoutInflater.from(this).inflate(R.layout.note_list_footer, null), null, false); mNotesListView.setOnItemClickListener(new OnListItemClickListener()); mNotesListView.setOnItemLongClickListener(this); mNotesListAdapter = new NotesListAdapter(this); mNotesListView.setAdapter(mNotesListAdapter); - mAddNewNote = (Button) findViewById(R.id.btn_new_note); + mAddNewNote = (Button) findViewById(R.id.btn_new_note);// 在activity中要获取该按钮 mAddNewNote.setOnClickListener(this); mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener()); mDispatch = false; @@ -231,6 +251,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt mModeCallBack = new ModeCallback(); } + // 继承自ListView.MultiChoiceModeListener 和 OnMenuItemClickListener private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { private DropdownMenu mDropDownMenu; private ActionMode mActionMode; @@ -259,7 +280,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt (Button) customView.findViewById(R.id.selection_menu), R.menu.note_list_dropdown); mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){ - public boolean onMenuItemClick(MenuItem item) { + public boolean onMenuItemClick(final MenuItem item) { mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected()); updateMenu(); return true; @@ -269,11 +290,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } + // 更新菜单 private void updateMenu() { int selectedCount = mNotesListAdapter.getSelectedCount(); // Update dropdown menu String format = getResources().getString(R.string.menu_select_title, selectedCount); - mDropDownMenu.setTitle(format); + mDropDownMenu.setTitle(format); // 更改标题 MenuItem item = mDropDownMenu.findItem(R.id.action_select_all); if (item != null) { if (mNotesListAdapter.isAllSelected()) { @@ -307,7 +329,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { + boolean checked) { mNotesListAdapter.setCheckedItem(position, checked); updateMenu(); } @@ -325,14 +347,14 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(getString(R.string.alert_message_delete_notes, - mNotesListAdapter.getSelectedCount())); + mNotesListAdapter.getSelectedCount())); builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, - int which) { - batchDelete(); - } - }); + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + batchDelete(); + } + }); builder.setNegativeButton(android.R.string.cancel, null); builder.show(); break; @@ -366,7 +388,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt /** * HACKME:When click the transparent part of "New Note" button, dispatch * the event to the list view behind this button. The transparent part of - * "New Note" button could be expressed by formula y=-0.12x+94(Unit:pixel) + * "New Note" button could be expressed by formula y=-0.12x+94锛圲nit:pixel锛� * and the line top of the button. The coordinate based on left of the "New * Note" button. The 94 represents maximum height of the transparent part. * Notice that, if the background of the button changes, the formula should @@ -413,7 +435,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt : NORMAL_SELECTION; mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] { - String.valueOf(mCurrentFolderId) + String.valueOf(mCurrentFolderId) }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); } @@ -624,7 +646,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt values.put(NoteColumns.LOCAL_MODIFIED, 1); mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID + "=?", new String[] { - String.valueOf(mFocusNoteDataItem.getId()) + String.valueOf(mFocusNoteDataItem.getId()) }); } } else if (!TextUtils.isEmpty(name)) { @@ -664,30 +686,38 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }); } + /* (non-Javadoc) + * @see android.app.Activity#onBackPressed() + * 按返回键时根据情况更改类中的数据 + */ @Override - public void onBackPressed() { - switch (mState) { - case SUB_FOLDER: - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mState = ListEditState.NOTE_LIST; - startAsyncNotesListQuery(); - mTitleBar.setVisibility(View.GONE); - break; - case CALL_RECORD_FOLDER: - mCurrentFolderId = Notes.ID_ROOT_FOLDER; - mState = ListEditState.NOTE_LIST; - mAddNewNote.setVisibility(View.VISIBLE); - mTitleBar.setVisibility(View.GONE); - startAsyncNotesListQuery(); - break; - case NOTE_LIST: - super.onBackPressed(); - break; - default: - break; - } + public void onBackPressed() { switch (mState) { + case SUB_FOLDER: + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + mState = ListEditState.NOTE_LIST; + startAsyncNotesListQuery(); + mTitleBar.setVisibility(View.GONE); + break; + case CALL_RECORD_FOLDER: + mCurrentFolderId = Notes.ID_ROOT_FOLDER; + mState = ListEditState.NOTE_LIST; + mAddNewNote.setVisibility(View.VISIBLE); + mTitleBar.setVisibility(View.GONE); + startAsyncNotesListQuery(); + break; + case NOTE_LIST: + super.onBackPressed(); + break; + default: + break; + } } + /** + * @param appWidgetId + * @param appWidgetType + * 根据不同类型的widget更新插件,通过intent传送数据 + */ private void updateWidget(int appWidgetId, int appWidgetType) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); if (appWidgetType == Notes.TYPE_WIDGET_2X) { @@ -700,13 +730,16 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - appWidgetId + appWidgetId }); sendBroadcast(intent); setResult(RESULT_OK, intent); } + /** + * 声明监听器,建立菜单,包括名称,视图,删除操作,更改名称操作; + */ private final OnCreateContextMenuListener mFolderOnCreateContextMenuListener = new OnCreateContextMenuListener() { public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { if (mFocusNoteDataItem != null) { @@ -726,6 +759,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt super.onContextMenuClosed(menu); } + /* (non-Javadoc) + * @see android.app.Activity#onContextItemSelected(android.view.MenuItem) + * 针对menu中不同的选择进行不同的处理,里面详细注释 + */ @Override public boolean onContextItemSelected(MenuItem item) { if (mFocusNoteDataItem == null) { @@ -734,10 +771,10 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } switch (item.getItemId()) { case MENU_FOLDER_VIEW: - openFolder(mFocusNoteDataItem); + openFolder(mFocusNoteDataItem);//打开对应文件 break; case MENU_FOLDER_DELETE: - AlertDialog.Builder builder = new AlertDialog.Builder(this); + AlertDialog.Builder builder = new AlertDialog.Builder(this);//设置确认是否删除的对话框 builder.setTitle(getString(R.string.alert_title_delete)); builder.setIcon(android.R.drawable.ic_dialog_alert); builder.setMessage(getString(R.string.alert_message_delete_folder)); @@ -748,7 +785,7 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } }); builder.setNegativeButton(android.R.string.cancel, null); - builder.show(); + builder.show();//显示对话框 break; case MENU_FOLDER_CHANGE_NAME: showCreateOrModifyFolderDialog(false); @@ -818,12 +855,19 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return true; } + /* (non-Javadoc) + * @see android.app.Activity#onSearchRequested() + * 直接调用startSearch函数 + */ @Override public boolean onSearchRequested() { startSearch(null, false, null /* appData */, false); return true; } + /** + * 函数功能:实现将便签导出到文本功能 + */ private void exportNoteToText() { final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this); new AsyncTask() { @@ -866,16 +910,27 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt }.execute(); } + /** + * @return + * 功能:判断是否正在同步 + */ private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } + /** + * 功能:跳转到PreferenceActivity界面 + */ private void startPreferenceActivity() { Activity from = getParent() != null ? getParent() : this; Intent intent = new Intent(from, NotesPreferenceActivity.class); from.startActivityIfNeeded(intent, -1); } + /** + * @author k + * 函数功能:实现对便签列表项的点击事件(短按) + */ private class OnListItemClickListener implements OnItemClickListener { public void onItemClick(AdapterView parent, View view, int position, long id) { @@ -917,10 +972,13 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt } + /** + * 查询目标文件 + */ private void startQueryDestinationFolders() { String selection = NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>? AND " + NoteColumns.ID + "<>?"; selection = (mState == ListEditState.NOTE_LIST) ? selection: - "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; + "(" + selection + ") OR (" + NoteColumns.ID + "=" + Notes.ID_ROOT_FOLDER + ")"; mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN, null, @@ -935,6 +993,12 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt NoteColumns.MODIFIED_DATE + " DESC"); } + /* (non-Javadoc) + * @see android.widget.AdapterView.OnItemLongClickListener#onItemLongClick(android.widget.AdapterView, android.view.View, int, long) + * 长按某一项时进行的操作 + * 如果长按的是便签,则通过ActionMode菜单实现;如果长按的是文件夹,则通过ContextMenu菜单实现; + * 具体ActionMOde菜单和ContextMenu菜单的详细见精度笔记 + */ public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { if (view instanceof NotesListItem) { mFocusNoteDataItem = ((NotesListItem) view).getItemData(); @@ -952,3 +1016,4 @@ public class NotesListActivity extends Activity implements OnClickListener, OnIt return false; } } + diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java index 51c9cb9..3130d85 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListAdapter.java @@ -1,19 +1,3 @@ -/* - * 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; import android.content.Context; @@ -30,19 +14,21 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; - +// 笔记列表适配器 public class NotesListAdapter extends CursorAdapter { private static final String TAG = "NotesListAdapter"; private Context mContext; - private HashMap mSelectedIndex; - private int mNotesCount; - private boolean mChoiceMode; + private HashMap mSelectedIndex; // 用于存储选中项的索引位置 + private int mNotesCount; // 笔记总数 + private boolean mChoiceMode; // 选择模式标志 + // 小部件属性类 public static class AppWidgetAttribute { public int widgetId; public int widgetType; }; + // 构造方法 public NotesListAdapter(Context context) { super(context, null); mSelectedIndex = new HashMap(); @@ -64,20 +50,24 @@ public class NotesListAdapter extends CursorAdapter { } } + // 设置指定位置的项的选中状态 public void setCheckedItem(final int position, final boolean checked) { mSelectedIndex.put(position, checked); notifyDataSetChanged(); } + // 是否处于选择模式 public boolean isInChoiceMode() { return mChoiceMode; } + // 设置选择模式 public void setChoiceMode(boolean mode) { mSelectedIndex.clear(); mChoiceMode = mode; } + // 选择所有项 public void selectAll(boolean checked) { Cursor cursor = getCursor(); for (int i = 0; i < getCount(); i++) { @@ -89,13 +79,14 @@ public class NotesListAdapter extends CursorAdapter { } } + // 获取选中项的ID集合 public HashSet getSelectedItemIds() { HashSet itemSet = new HashSet(); for (Integer position : mSelectedIndex.keySet()) { if (mSelectedIndex.get(position) == true) { Long id = getItemId(position); if (id == Notes.ID_ROOT_FOLDER) { - Log.d(TAG, "Wrong item id, should not happen"); + Log.d(TAG, "错误的项ID,不应该发生"); } else { itemSet.add(id); } @@ -105,6 +96,7 @@ public class NotesListAdapter extends CursorAdapter { return itemSet; } + // 获取选中的小部件集合 public HashSet getSelectedWidget() { HashSet itemSet = new HashSet(); for (Integer position : mSelectedIndex.keySet()) { @@ -116,11 +108,8 @@ public class NotesListAdapter extends CursorAdapter { widget.widgetId = item.getWidgetId(); widget.widgetType = item.getWidgetType(); itemSet.add(widget); - /** - * Don't close cursor here, only the adapter could close it - */ } else { - Log.e(TAG, "Invalid cursor"); + Log.e(TAG, "无效的游标"); return null; } } @@ -128,6 +117,7 @@ public class NotesListAdapter extends CursorAdapter { return itemSet; } + // 获取选中项数量 public int getSelectedCount() { Collection values = mSelectedIndex.values(); if (null == values) { @@ -143,11 +133,13 @@ public class NotesListAdapter extends CursorAdapter { return count; } + // 是否全部选中 public boolean isAllSelected() { int checkedCount = getSelectedCount(); return (checkedCount != 0 && checkedCount == mNotesCount); } + // 判断指定位置的项是否被选中 public boolean isSelectedItem(final int position) { if (null == mSelectedIndex.get(position)) { return false; @@ -167,6 +159,7 @@ public class NotesListAdapter extends CursorAdapter { calcNotesCount(); } + // 计算笔记总数 private void calcNotesCount() { mNotesCount = 0; for (int i = 0; i < getCount(); i++) { @@ -176,7 +169,7 @@ public class NotesListAdapter extends CursorAdapter { mNotesCount++; } } else { - Log.e(TAG, "Invalid cursor"); + Log.e(TAG, "无效的游标"); return; } } diff --git a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListItem.java b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListItem.java index 1221e80..3130d85 100644 --- a/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListItem.java +++ b/小米标签及案例/源程序代码-小米便签-Notes-master/Notes-master/src/net/micode/notes/ui/NotesListItem.java @@ -1,122 +1,177 @@ -/* - * 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; import android.content.Context; -import android.text.format.DateUtils; +import android.database.Cursor; +import android.util.Log; import android.view.View; -import android.widget.CheckBox; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; +import android.view.ViewGroup; +import android.widget.CursorAdapter; -import net.micode.notes.R; import net.micode.notes.data.Notes; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser.NoteItemBgResources; - - -public class NotesListItem extends LinearLayout { - private ImageView mAlert; - private TextView mTitle; - private TextView mTime; - private TextView mCallName; - private NoteItemData mItemData; - private CheckBox mCheckBox; - - public NotesListItem(Context context) { - super(context); - inflate(context, R.layout.note_item, this); - mAlert = (ImageView) findViewById(R.id.iv_alert_icon); - mTitle = (TextView) findViewById(R.id.tv_title); - mTime = (TextView) findViewById(R.id.tv_time); - mCallName = (TextView) findViewById(R.id.tv_name); - mCheckBox = (CheckBox) findViewById(android.R.id.checkbox); + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +// 笔记列表适配器 +public class NotesListAdapter extends CursorAdapter { + private static final String TAG = "NotesListAdapter"; + private Context mContext; + private HashMap mSelectedIndex; // 用于存储选中项的索引位置 + private int mNotesCount; // 笔记总数 + private boolean mChoiceMode; // 选择模式标志 + + // 小部件属性类 + public static class AppWidgetAttribute { + public int widgetId; + public int widgetType; + }; + + // 构造方法 + public NotesListAdapter(Context context) { + super(context, null); + mSelectedIndex = new HashMap(); + mContext = context; + mNotesCount = 0; } - public void bind(Context context, NoteItemData data, boolean choiceMode, boolean checked) { - if (choiceMode && data.getType() == Notes.TYPE_NOTE) { - mCheckBox.setVisibility(View.VISIBLE); - mCheckBox.setChecked(checked); - } else { - mCheckBox.setVisibility(View.GONE); + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return new NotesListItem(context); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + if (view instanceof NotesListItem) { + NoteItemData itemData = new NoteItemData(context, cursor); + ((NotesListItem) view).bind(context, itemData, mChoiceMode, + isSelectedItem(cursor.getPosition())); } + } - mItemData = data; - if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) { - mCallName.setVisibility(View.GONE); - mAlert.setVisibility(View.VISIBLE); - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); - mTitle.setText(context.getString(R.string.call_record_folder_name) - + context.getString(R.string.format_folder_files_count, data.getNotesCount())); - mAlert.setImageResource(R.drawable.call_record); - } else if (data.getParentId() == Notes.ID_CALL_RECORD_FOLDER) { - mCallName.setVisibility(View.VISIBLE); - mCallName.setText(data.getCallName()); - mTitle.setTextAppearance(context,R.style.TextAppearanceSecondaryItem); - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); - if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock); - mAlert.setVisibility(View.VISIBLE); - } else { - mAlert.setVisibility(View.GONE); + // 设置指定位置的项的选中状态 + public void setCheckedItem(final int position, final boolean checked) { + mSelectedIndex.put(position, checked); + notifyDataSetChanged(); + } + + // 是否处于选择模式 + public boolean isInChoiceMode() { + return mChoiceMode; + } + + // 设置选择模式 + public void setChoiceMode(boolean mode) { + mSelectedIndex.clear(); + mChoiceMode = mode; + } + + // 选择所有项 + public void selectAll(boolean checked) { + Cursor cursor = getCursor(); + for (int i = 0; i < getCount(); i++) { + if (cursor.moveToPosition(i)) { + if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) { + setCheckedItem(i, checked); + } } - } else { - mCallName.setVisibility(View.GONE); - mTitle.setTextAppearance(context, R.style.TextAppearancePrimaryItem); - - if (data.getType() == Notes.TYPE_FOLDER) { - mTitle.setText(data.getSnippet() - + context.getString(R.string.format_folder_files_count, - data.getNotesCount())); - mAlert.setVisibility(View.GONE); - } else { - mTitle.setText(DataUtils.getFormattedSnippet(data.getSnippet())); - if (data.hasAlert()) { - mAlert.setImageResource(R.drawable.clock); - mAlert.setVisibility(View.VISIBLE); + } + } + + // 获取选中项的ID集合 + public HashSet getSelectedItemIds() { + HashSet itemSet = new HashSet(); + for (Integer position : mSelectedIndex.keySet()) { + if (mSelectedIndex.get(position) == true) { + Long id = getItemId(position); + if (id == Notes.ID_ROOT_FOLDER) { + Log.d(TAG, "错误的项ID,不应该发生"); } else { - mAlert.setVisibility(View.GONE); + itemSet.add(id); } } } - mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate())); - setBackground(data); + return itemSet; } - private void setBackground(NoteItemData data) { - int id = data.getBgColorId(); - if (data.getType() == Notes.TYPE_NOTE) { - if (data.isSingle() || data.isOneFollowingFolder()) { - setBackgroundResource(NoteItemBgResources.getNoteBgSingleRes(id)); - } else if (data.isLast()) { - setBackgroundResource(NoteItemBgResources.getNoteBgLastRes(id)); - } else if (data.isFirst() || data.isMultiFollowingFolder()) { - setBackgroundResource(NoteItemBgResources.getNoteBgFirstRes(id)); - } else { - setBackgroundResource(NoteItemBgResources.getNoteBgNormalRes(id)); + // 获取选中的小部件集合 + public HashSet getSelectedWidget() { + HashSet itemSet = new HashSet(); + for (Integer position : mSelectedIndex.keySet()) { + if (mSelectedIndex.get(position) == true) { + Cursor c = (Cursor) getItem(position); + if (c != null) { + AppWidgetAttribute widget = new AppWidgetAttribute(); + NoteItemData item = new NoteItemData(mContext, c); + widget.widgetId = item.getWidgetId(); + widget.widgetType = item.getWidgetType(); + itemSet.add(widget); + } else { + Log.e(TAG, "无效的游标"); + return null; + } + } + } + return itemSet; + } + + // 获取选中项数量 + public int getSelectedCount() { + Collection values = mSelectedIndex.values(); + if (null == values) { + return 0; + } + Iterator iter = values.iterator(); + int count = 0; + while (iter.hasNext()) { + if (true == iter.next()) { + count++; } - } else { - setBackgroundResource(NoteItemBgResources.getFolderBgRes()); } + return count; + } + + // 是否全部选中 + public boolean isAllSelected() { + int checkedCount = getSelectedCount(); + return (checkedCount != 0 && checkedCount == mNotesCount); + } + + // 判断指定位置的项是否被选中 + public boolean isSelectedItem(final int position) { + if (null == mSelectedIndex.get(position)) { + return false; + } + return mSelectedIndex.get(position); + } + + @Override + protected void onContentChanged() { + super.onContentChanged(); + calcNotesCount(); + } + + @Override + public void changeCursor(Cursor cursor) { + super.changeCursor(cursor); + calcNotesCount(); } - public NoteItemData getItemData() { - return mItemData; + // 计算笔记总数 + private void calcNotesCount() { + mNotesCount = 0; + for (int i = 0; i < getCount(); i++) { + Cursor c = (Cursor) getItem(i); + if (c != null) { + if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) { + mNotesCount++; + } + } else { + Log.e(TAG, "无效的游标"); + return; + } + } } } diff --git a/小米标签及案例/示例:小米便签开源代码的泛读报告.docx b/小米标签及案例/示例:小米便签开源代码的泛读报告.docx deleted file mode 100644 index 551815c..0000000 Binary files a/小米标签及案例/示例:小米便签开源代码的泛读报告.docx and /dev/null differ diff --git a/小米标签及案例/示例:小米便签开源代码的质量分析报告.docx b/小米标签及案例/示例:小米便签开源代码的质量分析报告.docx deleted file mode 100644 index 590c1cb..0000000 Binary files a/小米标签及案例/示例:小米便签开源代码的质量分析报告.docx and /dev/null differ