/*
 * 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.AlertDialog;
 import android.app.Dialog;
 import android.appwidget.AppWidgetManager;
 import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.preference.PreferenceManager;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
 import android.view.ActionMode;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnCreateContextMenuListener;
 import android.view.View.OnTouchListener;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ListView;
 import android.widget.PopupMenu;
 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.NoteColumns;
 import net.micode.notes.gtask.remote.GTaskSyncService;
 import net.micode.notes.model.WorkingNote;
 import net.micode.notes.tool.BackupUtils;
 import net.micode.notes.tool.DataUtils;
 import net.micode.notes.tool.ResourceParser;
 import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
 import net.micode.notes.widget.NoteWidgetProvider_2x;
 import net.micode.notes.widget.NoteWidgetProvider_4x;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.HashSet;
 
 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;
 
     private static final int MENU_FOLDER_DELETE = 0;
 
     private static final int MENU_FOLDER_VIEW = 1;
 
     private static final int MENU_FOLDER_CHANGE_NAME = 2;
 
     private static final String PREFERENCE_ADD_INTRODUCTION = "net.micode.notes.introduction";
 
     private enum ListEditState {
         NOTE_LIST, SUB_FOLDER, CALL_RECORD_FOLDER
     };
 
     private ListEditState mState;
 
     private BackgroundQueryHandler mBackgroundQueryHandler;
 
     private NotesListAdapter mNotesListAdapter;
 
     private ListView mNotesListView;
 
     private Button mAddNewNote;
 
     private boolean mDispatch;
 
     private int mOriginY;
 
     private int mDispatchY;
 
     private TextView mTitleBar;
 
     private long mCurrentFolderId;
 
     private ContentResolver mContentResolver;
 
     private ModeCallback mModeCallBack;
 
     private static final String TAG = "NotesListActivity";
 
     public static final int NOTES_LISTVIEW_SCROLL_RATE = 30;
 
     private NoteItemData mFocusNoteDataItem;
 
     private static final String NORMAL_SELECTION = NoteColumns.PARENT_ID + "=?";
 
     private static final String ROOT_FOLDER_SELECTION = "(" + NoteColumns.TYPE + "<>"
             + Notes.TYPE_SYSTEM + " AND " + NoteColumns.PARENT_ID + "=?)" + " OR ("
             + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER + " AND "
             + NoteColumns.NOTES_COUNT + ">0)";
 
     private final static int REQUEST_CODE_OPEN_NODE = 102;
     private final static int REQUEST_CODE_NEW_NODE  = 103;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.note_list);
         initResources();
 
         /**
          * Insert an introduction when user firstly use this application
          */
         setAppInfoFromRawRes();
     }
 
     @Override
     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);
         }
     }
 
     private void setAppInfoFromRawRes() {
         // 从SharedPreferences中获取默认的Preference
         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
         // 如果没有添加过介绍
         if (!sp.getBoolean(PREFERENCE_ADD_INTRODUCTION, false)) {
             // 创建一个StringBuilder对象
             StringBuilder sb = new StringBuilder();
             // 创建一个InputStream对象
             InputStream in = null;
             try {
                  // 打开raw资源中的introduction文件
                  in = getResources().openRawResource(R.raw.introduction);
                 // 如果文件不为空
                 if (in != null) {
                     // 创建一个InputStreamReader对象
                     InputStreamReader isr = new InputStreamReader(in);
                     // 创建一个BufferedReader对象
                     BufferedReader br = new BufferedReader(isr);
                     // 创建一个字符数组
                     char [] buf = new char[1024];
                     // 读取文件的长度
                     int len = 0;
                     // 循环读取文件内容
                     while ((len = br.read(buf)) > 0) {
                         // 将读取的内容添加到StringBuilder中
                         sb.append(buf, 0, len);
                     }
                 } else {
                     // 如果文件为空，打印错误日志
                     Log.e(TAG, "Read introduction file error");
                     return;
                 }
             } catch (IOException e) {
                 // 打印异常信息
                 e.printStackTrace();
                 return;
             } finally {
                 // 如果InputStream不为空
                 if(in != null) {
                     try {
                         // 关闭InputStream
                         in.close();
                     } catch (IOException e) {
                         // TODO Auto-generated catch block
                         e.printStackTrace();
                     }
                 }
             }
 
             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()) {
                 sp.edit().putBoolean(PREFERENCE_ADD_INTRODUCTION, true).commit();
             } else {
                 Log.e(TAG, "Save introduction note error");
                 return;
             }
         }
     }
 
     // 重写onStart方法
     @Override
     protected void onStart() {
         // 调用父类的onStart方法
         super.onStart();
         // 启动异步笔记列表查询
         startAsyncNotesListQuery();
     }
 
     private void initResources() {
         mContentResolver = this.getContentResolver();
         mBackgroundQueryHandler = new BackgroundQueryHandler(this.getContentResolver());
         mCurrentFolderId = Notes.ID_ROOT_FOLDER;
         mNotesListView = (ListView) findViewById(R.id.notes_list);
         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.setOnClickListener(this);
         mAddNewNote.setOnTouchListener(new NewNoteOnTouchListener());
         mDispatch = false;
         mDispatchY = 0;
         mOriginY = 0;
         mTitleBar = (TextView) findViewById(R.id.tv_title_bar);
         mState = ListEditState.NOTE_LIST;
         mModeCallBack = new ModeCallback();
     }
 
     private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener {
         private DropdownMenu mDropDownMenu;
         private ActionMode mActionMode;
         private MenuItem mMoveMenu;
 
         // 创建ActionMode时调用
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             // 将note_list_options菜单填充到menu中
             getMenuInflater().inflate(R.menu.note_list_options, menu);
             // 设置delete菜单项的点击事件为当前Activity
             menu.findItem(R.id.delete).setOnMenuItemClickListener(this);
             // 获取move菜单项
             mMoveMenu = menu.findItem(R.id.move);
             // 如果当前焦点笔记的父文件夹是通话记录文件夹，或者用户文件夹数量为0，则隐藏move菜单项
             if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER
                     || DataUtils.getUserFolderCount(mContentResolver) == 0) {
                 mMoveMenu.setVisible(false);
             } else {
                 // 否则显示move菜单项，并设置点击事件为当前Activity
                 mMoveMenu.setVisible(true);
                 mMoveMenu.setOnMenuItemClickListener(this);
             }
             // 设置ActionMode
             mActionMode = mode;
             // 设置NotesListAdapter为多选模式
             mNotesListAdapter.setChoiceMode(true);
             // 设置NotesListView不可长按
             mNotesListView.setLongClickable(false);
             // 隐藏添加新笔记按钮
             mAddNewNote.setVisibility(View.GONE);
 
             // 创建自定义视图
             View customView = LayoutInflater.from(NotesListActivity.this).inflate(
                     R.layout.note_list_dropdown_menu, null);
             // 设置ActionMode的自定义视图
             mode.setCustomView(customView);
             // 创建DropdownMenu
             mDropDownMenu = new DropdownMenu(NotesListActivity.this,
                     (Button) customView.findViewById(R.id.selection_menu),
                     R.menu.note_list_dropdown);
             // 设置DropdownMenu的点击事件
             mDropDownMenu.setOnDropdownMenuItemClickListener(new PopupMenu.OnMenuItemClickListener(){
                 public boolean onMenuItemClick(MenuItem item) {
                     // 全选或取消全选
                     mNotesListAdapter.selectAll(!mNotesListAdapter.isAllSelected());
                     // 更新菜单
                     updateMenu();
                     return true;
                 }
 
             });
             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);
             MenuItem item = mDropDownMenu.findItem(R.id.action_select_all);
             if (item != null) {
                 if (mNotesListAdapter.isAllSelected()) {
                     item.setChecked(true);
                     item.setTitle(R.string.menu_deselect_all);
                 } else {
                     item.setChecked(false);
                     item.setTitle(R.string.menu_select_all);
                 }
             }
         }
 
         public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
             // TODO Auto-generated method stub
             return false;
         }
 
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
             // TODO Auto-generated method stub
             return false;
         }
 
         public void onDestroyActionMode(ActionMode mode) {
             mNotesListAdapter.setChoiceMode(false);
             mNotesListView.setLongClickable(true);
             mAddNewNote.setVisibility(View.VISIBLE);
         }
 
         public void finishActionMode() {
             mActionMode.finish();
         }
 
         public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
                 boolean checked) {
             mNotesListAdapter.setCheckedItem(position, checked);
             updateMenu();
         }
 
         public boolean onMenuItemClick(MenuItem item) {
             if (mNotesListAdapter.getSelectedCount() == 0) {
                 Toast.makeText(NotesListActivity.this, getString(R.string.menu_select_none),
                         Toast.LENGTH_SHORT).show();
                 return true;
             }
 
             switch (item.getItemId()) {
                 case R.id.delete:
                     AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.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_notes,
                                              mNotesListAdapter.getSelectedCount()));
                     builder.setPositiveButton(android.R.string.ok,
                                              new DialogInterface.OnClickListener() {
                                                  public void onClick(DialogInterface dialog,
                                                          int which) {
                                                      batchDelete();
                                                  }
                                              });
                     builder.setNegativeButton(android.R.string.cancel, null);
                     builder.show();
                     break;
                 case R.id.move:
                     startQueryDestinationFolders();
                     break;
                 default:
                     return false;
             }
             return true;
         }
     }
 
     private class NewNoteOnTouchListener implements OnTouchListener {
 
         public boolean onTouch(View v, MotionEvent event) {
             // 根据触摸事件的不同类型，执行不同的操作
             switch (event.getAction()) {
                 case MotionEvent.ACTION_DOWN: {
                     // 获取屏幕的高度
                     Display display = getWindowManager().getDefaultDisplay();
                     int screenHeight = display.getHeight();
                     // 获取新增笔记视图的高度
                     int newNoteViewHeight = mAddNewNote.getHeight();
                     // 计算新增笔记视图的起始位置
                     int start = screenHeight - newNoteViewHeight;
                     // 计算触摸事件的Y坐标
                     int eventY = start + (int) event.getY();
                     /**
                      * Minus TitleBar's height
                      */
                     // 如果当前状态为子文件夹状态，则减去标题栏的高度
                     if (mState == ListEditState.SUB_FOLDER) {
                         eventY -= mTitleBar.getHeight();
                         start -= mTitleBar.getHeight();
                     }
                     /**
                      * 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）
                      * 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
                      * also change. This is very bad, just for the UI designer's strong requirement.
                      */
                     // 如果触摸事件的Y坐标小于公式y=-0.12x+94的结果，则将事件分派给列表视图
                     if (event.getY() < (event.getX() * (-0.12) + 94)) {
                         // 获取列表视图的最后一个子视图
                         View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1
                                 - mNotesListView.getFooterViewsCount());
                         // 如果子视图不为空，且子视图的底部大于起始位置，且子视图的顶部小于起始位置加上94，则将事件分派给列表视图
                         if (view != null && view.getBottom() > start
                                 && (view.getTop() < (start + 94))) {
                             mOriginY = (int) event.getY();
                             mDispatchY = eventY;
                             event.setLocation(event.getX(), mDispatchY);
                             mDispatch = true;
                             return mNotesListView.dispatchTouchEvent(event);
                         }
                     }
                     break;
                 }
                 case MotionEvent.ACTION_MOVE: {
                     // 如果事件被分派，则更新事件的位置
                     if (mDispatch) {
                         mDispatchY += (int) event.getY() - mOriginY;
                         event.setLocation(event.getX(), mDispatchY);
                         return mNotesListView.dispatchTouchEvent(event);
                     }
                     break;
                 }
                 default: {
                     // 如果事件被分派，则将事件的位置恢复，并将事件分派给列表视图
                     if (mDispatch) {
                         event.setLocation(event.getX(), mDispatchY);
                         mDispatch = false;
                         return mNotesListView.dispatchTouchEvent(event);
                     }
                     break;
                 }
             }
             // 返回false，表示事件未被处理
             return false;
         }
 
     };
 
     private void startAsyncNotesListQuery() {
         String selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION
                 : NORMAL_SELECTION;
         mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null,
                 Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, new String[] {
                     String.valueOf(mCurrentFolderId)
                 }, NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC");
     }
 
     private final class BackgroundQueryHandler extends AsyncQueryHandler {
         // 构造函数，传入ContentResolver对象
         public BackgroundQueryHandler(ContentResolver contentResolver) {
             // 调用父类的构造函数，传入ContentResolver对象
             super(contentResolver);
         }
 
         @Override
         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
             // 根据token的值，执行不同的操作
             switch (token) {
                 // 如果token的值为FOLDER_NOTE_LIST_QUERY_TOKEN，则执行以下操作
                 case FOLDER_NOTE_LIST_QUERY_TOKEN:
                     // 将查询结果传递给mNotesListAdapter
                     mNotesListAdapter.changeCursor(cursor);
                     break;
                 // 如果token的值为FOLDER_LIST_QUERY_TOKEN，则执行以下操作
                 case FOLDER_LIST_QUERY_TOKEN:
                     // 如果查询结果不为空且结果数量大于0，则执行以下操作
                     if (cursor != null && cursor.getCount() > 0) {
                         // 显示文件夹列表菜单
                         showFolderListMenu(cursor);
                     } else {
                         // 否则，输出错误日志
                         Log.e(TAG, "Query folder failed");
                     }
                     break;
                 // 如果token的值不匹配以上两种情况，则直接返回
                 default:
                     return;
             }
         }
     }
 
     // 显示文件夹列表菜单
     private void showFolderListMenu(Cursor cursor) {
         // 创建一个AlertDialog.Builder对象
         AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
         // 设置对话框标题
         builder.setTitle(R.string.menu_title_select_folder);
         // 创建一个FoldersListAdapter对象，用于显示文件夹列表
         final FoldersListAdapter adapter = new FoldersListAdapter(this, cursor);
         // 设置对话框的适配器
         builder.setAdapter(adapter, new DialogInterface.OnClickListener() {
 
             // 点击对话框中的文件夹时触发
             public void onClick(DialogInterface dialog, int which) {
                 // 批量移动选中的笔记到指定的文件夹
                 DataUtils.batchMoveToFolder(mContentResolver,
                         mNotesListAdapter.getSelectedItemIds(), adapter.getItemId(which));
                 // 显示移动成功的提示信息
                 Toast.makeText(
                         NotesListActivity.this,
                         getString(R.string.format_move_notes_to_folder,
                                 mNotesListAdapter.getSelectedCount(),
                                 adapter.getFolderName(NotesListActivity.this, which)),
                         Toast.LENGTH_SHORT).show();
                 // 结束ActionMode
                 mModeCallBack.finishActionMode();
             }
         });
         // 显示对话框
         builder.show();
     }
 
     // 创建新笔记
     private void createNewNote() {
         // 创建一个Intent对象，指定目标Activity为NoteEditActivity
         Intent intent = new Intent(this, NoteEditActivity.class);
         // 设置Intent的动作，为插入或编辑
         intent.setAction(Intent.ACTION_INSERT_OR_EDIT);
         // 将当前文件夹ID作为参数传递给目标Activity
         intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId);
         // 启动目标Activity，并设置请求码为REQUEST_CODE_NEW_NODE
         this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE);
     }
 
     private void batchDelete() {
         // 创建一个异步任务，用于批量删除
         new AsyncTask<Void, Void, HashSet<AppWidgetAttribute>>() {
             // 在后台执行批量删除操作
             protected HashSet<AppWidgetAttribute> doInBackground(Void... unused) {
                 // 获取选中的widget
                 HashSet<AppWidgetAttribute> widgets = mNotesListAdapter.getSelectedWidget();
                 // 如果不是同步模式，直接删除笔记
                 if (!isSyncMode()) {
                     // if not synced, delete notes directly
                     if (DataUtils.batchDeleteNotes(mContentResolver, mNotesListAdapter
                             .getSelectedItemIds())) {
                     } else {
                         Log.e(TAG, "Delete notes error, should not happens");
                     }
                 } else {
                     // 在同步模式下，将删除的笔记移动到垃圾桶文件夹
                     // in sync mode, we'll move the deleted note into the trash
                     // folder
                     if (!DataUtils.batchMoveToFolder(mContentResolver, mNotesListAdapter
                             .getSelectedItemIds(), Notes.ID_TRASH_FOLER)) {
                         Log.e(TAG, "Move notes to trash folder error, should not happens");
                     }
                 }
                 return widgets;
             }
 
             // 在异步任务执行完毕后更新widget
             @Override
             protected void onPostExecute(HashSet<AppWidgetAttribute> widgets) {
                 if (widgets != null) {
                     for (AppWidgetAttribute widget : widgets) {
                         if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                                 && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
                             updateWidget(widget.widgetId, widget.widgetType);
                         }
                     }
                 }
                 // 结束ActionMode
                 mModeCallBack.finishActionMode();
             }
         }.execute();
     }
 
     private void deleteFolder(long folderId) {
         // 删除文件夹
         if (folderId == Notes.ID_ROOT_FOLDER) {
             // 如果文件夹ID为根文件夹，则抛出异常
             Log.e(TAG, "Wrong folder id, should not happen " + folderId);
             return;
         }
 
         HashSet<Long> ids = new HashSet<Long>();
         // 创建一个HashSet，用于存储要删除的文件夹ID
         ids.add(folderId);
         // 将要删除的文件夹ID添加到HashSet中
         HashSet<AppWidgetAttribute> widgets = DataUtils.getFolderNoteWidget(mContentResolver,
                 folderId);
         // 获取要删除的文件夹对应的widget
         if (!isSyncMode()) {
             // if not synced, delete folder directly
             DataUtils.batchDeleteNotes(mContentResolver, ids);
         } else {
             // in sync mode, we'll move the deleted folder into the trash folder
             DataUtils.batchMoveToFolder(mContentResolver, ids, Notes.ID_TRASH_FOLER);
         }
         if (widgets != null) {
             for (AppWidgetAttribute widget : widgets) {
                 if (widget.widgetId != AppWidgetManager.INVALID_APPWIDGET_ID
                         && widget.widgetType != Notes.TYPE_WIDGET_INVALIDE) {
                     updateWidget(widget.widgetId, widget.widgetType);
                 }
             }
         }
     }
 
     // 打开节点
     private void openNode(NoteItemData data) {
         // 创建一个Intent对象，指定要启动的Activity为NoteEditActivity
         Intent intent = new Intent(this, NoteEditActivity.class);
         // 设置Intent的Action为查看
         intent.setAction(Intent.ACTION_VIEW);
         // 将节点的ID作为附加数据传递给Intent
         intent.putExtra(Intent.EXTRA_UID, data.getId());
         // 启动Activity，并指定请求码为REQUEST_CODE_OPEN_NODE
         this.startActivityForResult(intent, REQUEST_CODE_OPEN_NODE);
     }
 
     // 打开文件夹
     private void openFolder(NoteItemData data) {
         // 设置当前文件夹ID
         mCurrentFolderId = data.getId();
         // 异步查询笔记列表
         startAsyncNotesListQuery();
         // 如果打开的是通话记录文件夹
         if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
             // 设置状态为通话记录文件夹
             mState = ListEditState.CALL_RECORD_FOLDER;
             // 隐藏添加新笔记按钮
             mAddNewNote.setVisibility(View.GONE);
         } else {
             // 设置状态为子文件夹
             mState = ListEditState.SUB_FOLDER;
         }
         // 如果打开的是通话记录文件夹
         if (data.getId() == Notes.ID_CALL_RECORD_FOLDER) {
             // 设置标题栏为通话记录文件夹名称
             mTitleBar.setText(R.string.call_record_folder_name);
         } else {
             // 设置标题栏为文件夹名称
             mTitleBar.setText(data.getSnippet());
         }
         // 显示标题栏
         mTitleBar.setVisibility(View.VISIBLE);
     }
 
     // 点击事件
     public void onClick(View v) {
         // 根据点击的View的id进行判断
         switch (v.getId()) {
             // 如果点击的是新建笔记按钮
             case R.id.btn_new_note:
                 // 调用创建新笔记的方法
                 createNewNote();
                 break;
             // 默认情况
             default:
                 break;
         }
     }
 
     // 显示软键盘
     private void showSoftInput() {
         // 获取输入法管理器
         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         // 如果输入法管理器不为空
         if (inputMethodManager != null) {
             // 显示软键盘
             inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
         }
     }
 
     // 隐藏软键盘
     private void hideSoftInput(View view) {
         // 获取输入法管理器
         InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
         // 隐藏软键盘
         inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
     }
 
     private void showCreateOrModifyFolderDialog(final boolean create) {
         // 创建或修改文件夹对话框
         final AlertDialog.Builder builder = new AlertDialog.Builder(this);
         // 加载对话框布局
         View view = LayoutInflater.from(this).inflate(R.layout.dialog_edit_text, null);
         // 获取文件夹名称输入框
         final EditText etName = (EditText) view.findViewById(R.id.et_foler_name);
         // 显示软键盘
         showSoftInput();
         // 如果不是创建文件夹
         if (!create) {
             // 如果长按的数据项不为空
             if (mFocusNoteDataItem != null) {
                 // 设置文件夹名称
                 etName.setText(mFocusNoteDataItem.getSnippet());
                 // 设置对话框标题
                 builder.setTitle(getString(R.string.menu_folder_change_name));
             } else {
                 // 如果长按的数据项为空，打印错误日志
                 Log.e(TAG, "The long click data item is null");
                 return;
             }
         } else {
             // 如果是创建文件夹，设置文件夹名称为空
             etName.setText("");
             // 设置对话框标题
             builder.setTitle(this.getString(R.string.menu_create_folder));
         }
 
         // 设置对话框确定按钮
         builder.setPositiveButton(android.R.string.ok, null);
         // 设置对话框取消按钮
         builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int which) {
                 // 隐藏软键盘
                 hideSoftInput(etName);
             }
         });
 
         // 显示对话框
         final Dialog dialog = builder.setView(view).show();
         // 获取对话框确定按钮
         final Button positive = (Button)dialog.findViewById(android.R.id.button1);
         // 设置确定按钮点击事件
         positive.setOnClickListener(new OnClickListener() {
             public void onClick(View v) {
                 // 隐藏软键盘
                 hideSoftInput(etName);
                 // 获取文件夹名称
                 String name = etName.getText().toString();
                 // 如果文件夹名称已经存在，显示提示信息
                 if (DataUtils.checkVisibleFolderName(mContentResolver, name)) {
                     Toast.makeText(NotesListActivity.this, getString(R.string.folder_exist, name),
                             Toast.LENGTH_LONG).show();
                     // 设置输入框光标位置
                     etName.setSelection(0, etName.length());
                     return;
                 }
                 // 如果不是创建文件夹
                 if (!create) {
                     // 如果文件夹名称不为空
                     if (!TextUtils.isEmpty(name)) {
                         // 创建ContentValues对象
                         ContentValues values = new ContentValues();
                         // 设置文件夹名称
                         values.put(NoteColumns.SNIPPET, name);
                         // 设置文件夹类型
                         values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
                         // 设置本地修改标志
                         values.put(NoteColumns.LOCAL_MODIFIED, 1);
                         // 更新文件夹数据
                         mContentResolver.update(Notes.CONTENT_NOTE_URI, values, NoteColumns.ID
                                 + "=?", new String[] {
                             String.valueOf(mFocusNoteDataItem.getId())
                         });
                     }
                 } else if (!TextUtils.isEmpty(name)) {
                     // 如果是创建文件夹，并且文件夹名称不为空
                     ContentValues values = new ContentValues();
                     // 设置文件夹名称
                     values.put(NoteColumns.SNIPPET, name);
                     // 设置文件夹类型
                     values.put(NoteColumns.TYPE, Notes.TYPE_FOLDER);
                     // 插入文件夹数据
                     mContentResolver.insert(Notes.CONTENT_NOTE_URI, values);
                 }
                 // 关闭对话框
                 dialog.dismiss();
             }
         });
 
         // 如果文件夹名称为空，禁用确定按钮
         if (TextUtils.isEmpty(etName.getText())) {
             positive.setEnabled(false);
         }
         /**
          * When the name edit text is null, disable the positive button
          */
         etName.addTextChangedListener(new TextWatcher() {
             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
                 // TODO Auto-generated method stub
 
             }
 
             public void onTextChanged(CharSequence s, int start, int before, int count) {
                 if (TextUtils.isEmpty(etName.getText())) {
                     positive.setEnabled(false);
                 } else {
                     positive.setEnabled(true);
                 }
             }
 
             public void afterTextChanged(Editable s) {
                 // TODO Auto-generated method stub
 
             }
         });
     }
 
     @Override
     public void onBackPressed() {
         // 根据当前状态执行不同的操作
         switch (mState) {
             case SUB_FOLDER:
                 // 如果当前状态是子文件夹，则将当前文件夹ID设置为根文件夹，状态设置为笔记列表，并开始异步查询笔记列表
                 mCurrentFolderId = Notes.ID_ROOT_FOLDER;
                 mState = ListEditState.NOTE_LIST;
                 startAsyncNotesListQuery();
                 // 隐藏标题栏
                 mTitleBar.setVisibility(View.GONE);
                 break;
             case CALL_RECORD_FOLDER:
                 // 如果当前状态是通话记录文件夹，则将当前文件夹ID设置为根文件夹，状态设置为笔记列表，并开始异步查询笔记列表
                 mCurrentFolderId = Notes.ID_ROOT_FOLDER;
                 mState = ListEditState.NOTE_LIST;
                 // 显示添加新笔记按钮
                 mAddNewNote.setVisibility(View.VISIBLE);
                 // 隐藏标题栏
                 mTitleBar.setVisibility(View.GONE);
                 startAsyncNotesListQuery();
                 break;
             case NOTE_LIST:
                 // 如果当前状态是笔记列表，则调用父类的onBackPressed方法
                 super.onBackPressed();
                 break;
             default:
                 // 默认情况下，不执行任何操作
                 break;
         }
     }
 
     // 更新小部件
     private void updateWidget(int appWidgetId, int appWidgetType) {
         // 创建一个Intent，用于更新小部件
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         // 根据小部件类型，设置Intent的Class
         if (appWidgetType == Notes.TYPE_WIDGET_2X) {
             intent.setClass(this, NoteWidgetProvider_2x.class);
         } else if (appWidgetType == Notes.TYPE_WIDGET_4X) {
             intent.setClass(this, NoteWidgetProvider_4x.class);
         } else {
             // 如果小部件类型不支持，则输出错误日志并返回
             Log.e(TAG, "Unspported widget type");
             return;
         }
 
         // 将小部件ID添加到Intent中
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
             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) {
                 menu.setHeaderTitle(mFocusNoteDataItem.getSnippet());
                 menu.add(0, MENU_FOLDER_VIEW, 0, R.string.menu_folder_view);
                 menu.add(0, MENU_FOLDER_DELETE, 0, R.string.menu_folder_delete);
                 menu.add(0, MENU_FOLDER_CHANGE_NAME, 0, R.string.menu_folder_change_name);
             }
         }
     };
 
     // 重写onContextMenuClosed方法
     @Override
     public void onContextMenuClosed(Menu menu) {
         // 如果mNotesListView不为空
         if (mNotesListView != null) {
             // 将mNotesListView的onCreateContextMenuListener设置为null
             mNotesListView.setOnCreateContextMenuListener(null);
         }
         // 调用父类的onContextMenuClosed方法
         super.onContextMenuClosed(menu);
     }
 
     @Override
     public boolean onContextItemSelected(MenuItem item) {
         // 如果长按的数据项为空，则打印错误日志并返回false
         if (mFocusNoteDataItem == null) {
             Log.e(TAG, "The long click data item is null");
             return false;
         }
         // 根据菜单项的id执行相应的操作
         switch (item.getItemId()) {
             case MENU_FOLDER_VIEW:
                 // 打开文件夹
                 openFolder(mFocusNoteDataItem);
                 break;
             case MENU_FOLDER_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_folder));
                 builder.setPositiveButton(android.R.string.ok,
                         new DialogInterface.OnClickListener() {
                             public void onClick(DialogInterface dialog, int which) {
                                 // 删除文件夹
                                 deleteFolder(mFocusNoteDataItem.getId());
                             }
                         });
                 builder.setNegativeButton(android.R.string.cancel, null);
                 builder.show();
                 break;
             case MENU_FOLDER_CHANGE_NAME:
                 // 显示修改文件夹名称的对话框
                 showCreateOrModifyFolderDialog(false);
                 break;
             default:
                 break;
         }
 
         return true;
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         // 清空菜单
         // 清空菜单
         // 判断当前状态
         menu.clear();
             // 加载note_list菜单
         if (mState == ListEditState.NOTE_LIST) {
             getMenuInflater().inflate(R.menu.note_list, menu);
             // set sync or sync_cancel
             menu.findItem(R.id.menu_sync).setTitle(
                     GTaskSyncService.isSyncing() ? R.string.menu_sync_cancel : R.string.menu_sync);
         } else if (mState == ListEditState.SUB_FOLDER) {
             getMenuInflater().inflate(R.menu.sub_folder, menu);
         } else if (mState == ListEditState.CALL_RECORD_FOLDER) {
             getMenuInflater().inflate(R.menu.call_record_folder, menu);
         } else {
             Log.e(TAG, "Wrong state:" + mState);
         }
         return true;
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         // 根据菜单项的ID执行相应的操作
         switch (item.getItemId()) {
             case R.id.menu_new_folder: {
                 // 显示创建或修改文件夹对话框
                 showCreateOrModifyFolderDialog(true);
                 break;
             }
             case R.id.menu_export_text: {
                 // 导出笔记到文本
                 exportNoteToText();
                 break;
             }
             case R.id.menu_sync: {
                 // 如果是同步模式
                 if (isSyncMode()) {
                     // 如果菜单项的标题是同步，则启动同步服务
                     if (TextUtils.equals(item.getTitle(), getString(R.string.menu_sync))) {
                         GTaskSyncService.startSync(this);
                     // 否则，取消同步
                     } else {
                         GTaskSyncService.cancelSync(this);
                     }
                 // 否则，启动偏好设置活动
                 } else {
                     startPreferenceActivity();
                 }
                 break;
             }
             case R.id.menu_setting: {
                 // 启动偏好设置活动
                 startPreferenceActivity();
                 break;
             }
             case R.id.menu_new_note: {
                 // 创建新笔记
                 createNewNote();
                 break;
             }
             case R.id.menu_search:
                 // 启动搜索请求
                 onSearchRequested();
                 break;
             default:
                 break;
         }
         return true;
     }
 
     // 重写onSearchRequested()方法
     @Override
     public boolean onSearchRequested() {
         // 启动搜索，参数分别为：搜索字符串、是否显示搜索框、应用数据、是否显示搜索结果
         startSearch(null, false, null /* appData */, false);
         // 返回true，表示搜索请求已处理
         return true;
     }
 
     // 导出笔记到文本
     private void exportNoteToText() {
         // 获取BackupUtils实例
         final BackupUtils backup = BackupUtils.getInstance(NotesListActivity.this);
         // 创建异步任务
         new AsyncTask<Void, Void, Integer>() {
 
             // 在后台执行导出操作
             @Override
             protected Integer doInBackground(Void... unused) {
                 return backup.exportToText();
             }
 
             // 在主线程中处理结果
             @Override
             protected void onPostExecute(Integer result) {
                 // 如果SD卡未挂载
                 if (result == BackupUtils.STATE_SD_CARD_UNMOUONTED) {
                     AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                     builder.setTitle(NotesListActivity.this
                             .getString(R.string.failed_sdcard_export));
                     builder.setMessage(NotesListActivity.this
                             .getString(R.string.error_sdcard_unmounted));
                     builder.setPositiveButton(android.R.string.ok, null);
                     builder.show();
                 // 如果导出成功
                 } else if (result == BackupUtils.STATE_SUCCESS) {
                     AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                     builder.setTitle(NotesListActivity.this
                             .getString(R.string.success_sdcard_export));
                     builder.setMessage(NotesListActivity.this.getString(
                             R.string.format_exported_file_location, backup
                                     .getExportedTextFileName(), backup.getExportedTextFileDir()));
                     builder.setPositiveButton(android.R.string.ok, null);
                     builder.show();
                 // 如果系统错误
                 } else if (result == BackupUtils.STATE_SYSTEM_ERROR) {
                     AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this);
                     builder.setTitle(NotesListActivity.this
                             .getString(R.string.failed_sdcard_export));
                     builder.setMessage(NotesListActivity.this
                             .getString(R.string.error_sdcard_export));
                     builder.setPositiveButton(android.R.string.ok, null);
                     builder.show();
                 }
             }
 
         }.execute();
     }
 
     // 判断是否为同步模式
     private boolean isSyncMode() {
         // 获取同步账户名称，并去除首尾空格
         return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
     }
 
     // 启动设置活动
     private void startPreferenceActivity() {
         // 获取父活动，如果没有父活动则使用当前活动
         Activity from = getParent() != null ? getParent() : this;
         // 创建意图，指定要启动的活动
         Intent intent = new Intent(from, NotesPreferenceActivity.class);
         // 启动活动
         from.startActivityIfNeeded(intent, -1);
     }
 
     private class OnListItemClickListener implements OnItemClickListener {
 
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             // 判断点击的view是否为NotesListItem类型
             if (view instanceof NotesListItem) {
                 // 获取点击的item数据
                 NoteItemData item = ((NotesListItem) view).getItemData();
                 // 判断是否处于选择模式
                 if (mNotesListAdapter.isInChoiceMode()) {
                     // 判断点击的item类型是否为Notes.TYPE_NOTE
                     if (item.getType() == Notes.TYPE_NOTE) {
                         // 获取点击的item位置，减去ListView的headerViewsCount
                         position = position - mNotesListView.getHeaderViewsCount();
                         // 调用回调函数，改变item的选中状态
                         mModeCallBack.onItemCheckedStateChanged(null, position, id,
                                 !mNotesListAdapter.isSelectedItem(position));
                     }
                     return;
                 }
 
                 // 判断当前状态
                 switch (mState) {
                     // 如果当前状态为NOTE_LIST
                     case NOTE_LIST:
                         // 判断点击的item类型是否为Notes.TYPE_FOLDER或Notes.TYPE_SYSTEM
                         if (item.getType() == Notes.TYPE_FOLDER
                                 || item.getType() == Notes.TYPE_SYSTEM) {
                             // 打开文件夹
                             openFolder(item);
                         // 判断点击的item类型是否为Notes.TYPE_NOTE
                         } else if (item.getType() == Notes.TYPE_NOTE) {
                             // 打开节点
                             openNode(item);
                         // 如果点击的item类型不是Notes.TYPE_FOLDER、Notes.TYPE_SYSTEM或Notes.TYPE_NOTE，则输出错误日志
                         } else {
                             Log.e(TAG, "Wrong note type in NOTE_LIST");
                         }
                         break;
                     // 如果当前状态为SUB_FOLDER或CALL_RECORD_FOLDER
                     case SUB_FOLDER:
                     case CALL_RECORD_FOLDER:
                         // 判断点击的item类型是否为Notes.TYPE_NOTE
                         if (item.getType() == Notes.TYPE_NOTE) {
                             // 打开节点
                             openNode(item);
                         // 如果点击的item类型不是Notes.TYPE_NOTE，则输出错误日志
                         } else {
                             Log.e(TAG, "Wrong note type in SUB_FOLDER");
                         }
                         break;
                     // 默认情况
                     default:
                         break;
                 }
             }
         }
 
     }
 
     // 开始查询目标文件夹
     private void startQueryDestinationFolders() {
         // 查询条件：类型为文件夹，父ID不为垃圾桶ID，ID不为当前文件夹ID
         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 + ")";
 
         // 启动后台查询
         mBackgroundQueryHandler.startQuery(FOLDER_LIST_QUERY_TOKEN,
                 null,
                 Notes.CONTENT_NOTE_URI,
                 FoldersListAdapter.PROJECTION,
                 selection,
                 new String[] {
                         String.valueOf(Notes.TYPE_FOLDER),
                         String.valueOf(Notes.ID_TRASH_FOLER),
                         String.valueOf(mCurrentFolderId)
                 },
                 NoteColumns.MODIFIED_DATE + " DESC");
     }
 
     public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
         if (view instanceof NotesListItem) {
             mFocusNoteDataItem = ((NotesListItem) view).getItemData();
             if (mFocusNoteDataItem.getType() == Notes.TYPE_NOTE && !mNotesListAdapter.isInChoiceMode()) {
                 if (mNotesListView.startActionMode(mModeCallBack) != null) {
                     mModeCallBack.onItemCheckedStateChanged(null, position, id, true);
                     mNotesListView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
                 } else {
                     Log.e(TAG, "startActionMode fails");
                 }
             } else if (mFocusNoteDataItem.getType() == Notes.TYPE_FOLDER) {
                 mNotesListView.setOnCreateContextMenuListener(mFolderOnCreateContextMenuListener);
             }
         }
         return false;
     }
 }
 /*
 * 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.database.Cursor;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.CursorAdapter;
 
 import net.micode.notes.data.Notes;
 
 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<Integer, Boolean> mSelectedIndex;
     private int mNotesCount;
     private boolean mChoiceMode;
 
     public static class AppWidgetAttribute {
         public int widgetId;
         public int widgetType;
     };
 
     // 构造函数，用于初始化NotesListAdapter对象
     public NotesListAdapter(Context context) {
         // 调用父类的构造函数，传入上下文和null
         super(context, null);
         // 初始化mSelectedIndex，用于存储选中的索引
         mSelectedIndex = new HashMap<Integer, Boolean>();
         // 保存上下文
         mContext = context;
         // 初始化mNotesCount，用于存储笔记数量
         mNotesCount = 0;
     }
 
     // 重写newView方法，用于创建新的视图
     @Override
     public View newView(Context context, Cursor cursor, ViewGroup parent) {
         // 创建一个新的NotesListItem视图
         return new NotesListItem(context);
     }
 
     @Override
     public void bindView(View view, Context context, Cursor cursor) {
         // 判断view是否为NotesListItem类型
         if (view instanceof NotesListItem) {
             // 创建NoteItemData对象
             NoteItemData itemData = new NoteItemData(context, cursor);
             // 将NoteItemData对象绑定到NotesListItem对象上
             ((NotesListItem) view).bind(context, itemData, mChoiceMode,
                     isSelectedItem(cursor.getPosition()));
         }
     }
 
     // 设置指定位置的项是否被选中
     public void setCheckedItem(final int position, final boolean checked) {
         // 将指定位置的项设置为选中状态
         mSelectedIndex.put(position, checked);
         // 通知数据集发生变化
         notifyDataSetChanged();
     }
 
     // 判断是否处于选择模式
     public boolean isInChoiceMode() {
         // 返回mChoiceMode的值
         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);
                 }
             }
         }
     }
 
     // 获取选中的项的ID
     public HashSet<Long> getSelectedItemIds() {
         // 创建一个HashSet来存储选中的项的ID
         HashSet<Long> itemSet = new HashSet<Long>();
         // 遍历mSelectedIndex中的所有键值对
         for (Integer position : mSelectedIndex.keySet()) {
             // 如果该位置的值为true，表示该项被选中
             if (mSelectedIndex.get(position) == true) {
                 // 获取该项的ID
                 Long id = getItemId(position);
                 // 如果ID为Notes.ID_ROOT_FOLDER，表示该项为根文件夹，不应该发生
                 if (id == Notes.ID_ROOT_FOLDER) {
                     Log.d(TAG, "Wrong item id, should not happen");
                 } else {
                     // 否则，将该ID添加到itemSet中
                     itemSet.add(id);
                 }
             }
         }
 
         // 返回itemSet
         return itemSet;
     }
 
     // 获取选中的小部件
     public HashSet<AppWidgetAttribute> getSelectedWidget() {
         // 创建一个HashSet来存储选中的小部件
         HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
         // 遍历选中的小部件索引
         for (Integer position : mSelectedIndex.keySet()) {
             // 如果该小部件被选中
             if (mSelectedIndex.get(position) == true) {
                 // 获取该小部件的Cursor
                 Cursor c = (Cursor) getItem(position);
                 // 如果Cursor不为空
                 if (c != null) {
                     // 创建一个AppWidgetAttribute对象
                     AppWidgetAttribute widget = new AppWidgetAttribute();
                     // 获取NoteItemData对象
                     NoteItemData item = new NoteItemData(mContext, c);
                     // 设置小部件的ID和类型
                     widget.widgetId = item.getWidgetId();
                     widget.widgetType = item.getWidgetType();
                     // 将小部件添加到HashSet中
                     itemSet.add(widget);
                     /**
                      * Don't close cursor here, only the adapter could close it
                      */
                 } else {
                     Log.e(TAG, "Invalid cursor");
                     return null;
                 }
             }
         }
         return itemSet;
     }
 
     // 获取被选中的数量
     public int getSelectedCount() {
         // 获取被选中的索引集合
         Collection<Boolean> values = mSelectedIndex.values();
         // 如果集合为空，返回0
         if (null == values) {
             return 0;
         }
         // 获取集合的迭代器
         Iterator<Boolean> iter = values.iterator();
         // 初始化计数器
         int count = 0;
         // 遍历集合
         while (iter.hasNext()) {
             // 如果当前索引被选中，计数器加1
             if (true == iter.next()) {
                 count++;
             }
         }
         // 返回计数器的值
         return count;
     }
 
     // 判断是否所有选项都被选中
     public boolean isAllSelected() {
         // 获取被选中的选项数量
         int checkedCount = getSelectedCount();
         // 如果被选中的选项数量不为0且等于总选项数量，则返回true，否则返回false
         return (checkedCount != 0 && checkedCount == mNotesCount);
     }
 
     // 判断指定位置的项是否被选中
     public boolean isSelectedItem(final int position) {
         // 如果指定位置的项未被选中，则返回false
         if (null == mSelectedIndex.get(position)) {
             return false;
         }
         // 否则返回true
         return mSelectedIndex.get(position);
     }
 
     // 重写onContentChanged方法
     @Override
     protected void onContentChanged() {
         // 调用父类的onContentChanged方法
         super.onContentChanged();
         // 计算笔记数量
         calcNotesCount();
     }
 
     @Override
     public void changeCursor(Cursor cursor) {
         super.changeCursor(cursor);
         calcNotesCount();
     }
 
     // 计算笔记数量
     private void calcNotesCount() {
         // 初始化笔记数量为0
         mNotesCount = 0;
         // 遍历所有笔记
         for (int i = 0; i < getCount(); i++) {
             // 获取当前笔记的游标
             Cursor c = (Cursor) getItem(i);
             // 如果游标不为空
             if (c != null) {
                 // 如果笔记类型为笔记
                 if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
                     // 笔记数量加1
                     mNotesCount++;
                 }
             } else {
                 // 如果游标为空，打印错误日志并返回
                 Log.e(TAG, "Invalid cursor");
                 return;
             }
         }
     }
 }
 /*
 * 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.view.View;
 import android.widget.CheckBox;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
 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;
 
     // 构造函数，用于初始化NotesListItem对象
     public NotesListItem(Context context) {
         // 调用父类的构造函数
         super(context);
         // 使用传入的context对象加载布局文件note_item.xml，并将布局文件中的视图添加到当前视图中
         inflate(context, R.layout.note_item, this);
         // 通过findViewById方法获取布局文件中的视图，并赋值给相应的成员变量
         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);
     }
 
     // 绑定数据到视图
     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);
         }
 
         // 保存数据
         mItemData = data;
         // 如果数据ID为通话记录文件夹
         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);
         // 如果数据父ID为通话记录文件夹
         } 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);
             }
         // 否则
         } 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);
                 // 否则
                 } else {
                     // 隐藏提醒
                     mAlert.setVisibility(View.GONE);
                 }
             }
         }
         // 设置修改时间
         mTime.setText(DateUtils.getRelativeTimeSpanString(data.getModifiedDate()));
 
         // 设置背景
         setBackground(data);
     }
 
     // 设置背景颜色
     private void setBackground(NoteItemData data) {
         // 获取背景颜色id
         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));
             }
         // 其他情况
         } else {
             // 设置背景资源为文件夹的背景资源
             setBackgroundResource(NoteItemBgResources.getFolderBgRes());
         }
     }
 
     // 获取NoteItemData对象
     public NoteItemData getItemData() {
         // 返回mItemData对象
         return mItemData;
     }
 }
 /*
 * 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.accounts.Account;
 import android.accounts.AccountManager;
 import android.app.ActionBar;
 import android.app.AlertDialog;
 import android.content.BroadcastReceiver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceCategory;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.Button;
 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.NoteColumns;
 import net.micode.notes.gtask.remote.GTaskSyncService;
 
 
 public class NotesPreferenceActivity extends PreferenceActivity {
     // 定义偏好设置名称
     public static final String PREFERENCE_NAME = "notes_preferences";
 
     // 定义同步账户名称的偏好设置键
     public static final String PREFERENCE_SYNC_ACCOUNT_NAME = "pref_key_account_name";
 
     // 定义最后同步时间的偏好设置键
     public static final String PREFERENCE_LAST_SYNC_TIME = "pref_last_sync_time";
 
     // 定义设置背景颜色的偏好设置键
     public static final String PREFERENCE_SET_BG_COLOR_KEY = "pref_key_bg_random_appear";
 
     // 定义同步账户的偏好设置键
     private static final String PREFERENCE_SYNC_ACCOUNT_KEY = "pref_sync_account_key";
 
     // 定义账户类型过滤器的键
     private static final String AUTHORITIES_FILTER_KEY = "authorities";
 
     // 定义账户类别
     private PreferenceCategory mAccountCategory;
 
     // 定义广播接收器
     private GTaskReceiver mReceiver;
 
     // 定义原始账户
     private Account[] mOriAccounts;
 
     // 定义是否添加了账户的标记
     private boolean mHasAddedAccount;
 
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
         /* using the app icon for navigation */
         getActionBar().setDisplayHomeAsUpEnabled(true);
 
         // 从资源文件中添加偏好设置
         addPreferencesFromResource(R.xml.preferences);
         // 获取偏好设置中的账户类别
         mAccountCategory = (PreferenceCategory) findPreference(PREFERENCE_SYNC_ACCOUNT_KEY);
         // 创建一个广播接收器
         mReceiver = new GTaskReceiver();
         // 创建一个意图过滤器
         IntentFilter filter = new IntentFilter();
         // 添加广播接收器的动作
         filter.addAction(GTaskSyncService.GTASK_SERVICE_BROADCAST_NAME);
         // 注册广播接收器
         registerReceiver(mReceiver, filter);
 
         // 初始化原始账户
         mOriAccounts = null;
         // 从布局文件中获取头部视图
         View header = LayoutInflater.from(this).inflate(R.layout.settings_header, null);
         // 将头部视图添加到列表视图中
         getListView().addHeaderView(header, null, true);
     }
 
     @Override
     protected void onResume() {
         super.onResume();
 
         // need to set sync account automatically if user has added a new
         // account
         if (mHasAddedAccount) {
             // 获取Google账户
             Account[] accounts = getGoogleAccounts();
             // 如果原始账户不为空且新账户数量大于原始账户数量
             if (mOriAccounts != null && accounts.length > mOriAccounts.length) {
                 // 遍历新账户
                 for (Account accountNew : accounts) {
                     boolean found = false;
                     // 遍历原始账户
                     for (Account accountOld : mOriAccounts) {
                         // 如果新账户和原始账户名称相同
                         if (TextUtils.equals(accountOld.name, accountNew.name)) {
                             found = true;
                             break;
                         }
                     }
                     // 如果新账户在原始账户中未找到
                     if (!found) {
                         // 设置同步账户为新账户
                         setSyncAccount(accountNew.name);
                         break;
                     }
                 }
             }
         }
 
         // 刷新UI
         refreshUI();
     }
 
     // 重写onDestroy方法
     @Override
     protected void onDestroy() {
         // 如果mReceiver不为空，则取消注册
         if (mReceiver != null) {
             unregisterReceiver(mReceiver);
         }
         // 调用父类的onDestroy方法
         super.onDestroy();
     }
 
     // 加载账户偏好设置
     private void loadAccountPreference() {
         // 移除所有账户偏好设置
         mAccountCategory.removeAll();
 
         // 创建一个新的账户偏好设置
         Preference accountPref = new Preference(this);
         // 获取默认账户名称
         final String defaultAccount = getSyncAccountName(this);
         // 设置账户偏好设置的标题
         accountPref.setTitle(getString(R.string.preferences_account_title));
         // 设置账户偏好设置的摘要
         accountPref.setSummary(getString(R.string.preferences_account_summary));
         // 设置账户偏好设置的点击事件监听器
         accountPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
             public boolean onPreferenceClick(Preference preference) {
                 // 如果没有正在同步，则执行以下操作
                 if (!GTaskSyncService.isSyncing()) {
                     // 如果默认账户为空，则执行以下操作
                     if (TextUtils.isEmpty(defaultAccount)) {
                         // the first time to set account
                         showSelectAccountAlertDialog();
                     } else {
                         // if the account has already been set, we need to promp
                         // user about the risk
                         showChangeAccountConfirmAlertDialog();
                     }
                 } else {
                     Toast.makeText(NotesPreferenceActivity.this,
                             R.string.preferences_toast_cannot_change_account, Toast.LENGTH_SHORT)
                             .show();
                 }
                 return true;
             }
         });
 
         mAccountCategory.addPreference(accountPref);
     }
 
     private void loadSyncButton() {
         // 获取同步按钮和上次同步时间文本框
         Button syncButton = (Button) findViewById(R.id.preference_sync_button);
         TextView lastSyncTimeView = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
 
         // set button state
         if (GTaskSyncService.isSyncing()) {
             syncButton.setText(getString(R.string.preferences_button_sync_cancel));
             syncButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
                     GTaskSyncService.cancelSync(NotesPreferenceActivity.this);
                 }
             });
         } else {
             syncButton.setText(getString(R.string.preferences_button_sync_immediately));
             syncButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
                     GTaskSyncService.startSync(NotesPreferenceActivity.this);
                 }
             });
         }
         syncButton.setEnabled(!TextUtils.isEmpty(getSyncAccountName(this)));
 
         // set last sync time
         if (GTaskSyncService.isSyncing()) {
             lastSyncTimeView.setText(GTaskSyncService.getProgressString());
             lastSyncTimeView.setVisibility(View.VISIBLE);
         } else {
             long lastSyncTime = getLastSyncTime(this);
             if (lastSyncTime != 0) {
                 lastSyncTimeView.setText(getString(R.string.preferences_last_sync_time,
                         DateFormat.format(getString(R.string.preferences_last_sync_time_format),
                                 lastSyncTime)));
                 lastSyncTimeView.setVisibility(View.VISIBLE);
             } else {
                 lastSyncTimeView.setVisibility(View.GONE);
             }
         }
     }
 
     // 刷新UI
     private void refreshUI() {
         // 加载账户偏好设置
         loadAccountPreference();
         // 加载同步按钮
         loadSyncButton();
     }
 
     private void showSelectAccountAlertDialog() {
         // 创建一个AlertDialog.Builder对象
         AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
 
         // 从布局文件中加载标题视图
         View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
         // 获取标题文本视图
         TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
         // 设置标题文本
         titleTextView.setText(getString(R.string.preferences_dialog_select_account_title));
         // 获取副标题文本视图
         TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
         // 设置副标题文本
         subtitleTextView.setText(getString(R.string.preferences_dialog_select_account_tips));
 
         // 设置自定义标题
         dialogBuilder.setCustomTitle(titleView);
         // 设置确定按钮为空
         dialogBuilder.setPositiveButton(null, null);
 
         // 获取Google账户
         Account[] accounts = getGoogleAccounts();
         // 获取默认账户
         String defAccount = getSyncAccountName(this);
 
         // 保存原始账户
         mOriAccounts = accounts;
         // 标记是否添加了账户
         mHasAddedAccount = false;
 
         // 如果有账户
         if (accounts.length > 0) {
             // 创建一个字符序列数组
             CharSequence[] items = new CharSequence[accounts.length];
             // 保存字符序列数组
             final CharSequence[] itemMapping = items;
             // 默认选中项
             int checkedItem = -1;
             // 索引
             int index = 0;
             // 遍历账户
             for (Account account : accounts) {
                 // 如果账户名与默认账户名相同，则选中该项
                 if (TextUtils.equals(account.name, defAccount)) {
                     checkedItem = index;
                 }
                 // 将账户名添加到字符序列数组中
                 items[index++] = account.name;
             }
             // 设置单选列表项
             dialogBuilder.setSingleChoiceItems(items, checkedItem,
                     new DialogInterface.OnClickListener() {
                         public void onClick(DialogInterface dialog, int which) {
                             // 设置同步账户
                             setSyncAccount(itemMapping[which].toString());
                             // 关闭对话框
                             dialog.dismiss();
                             // 刷新UI
                             refreshUI();
                         }
                     });
         }
 
         // 从布局文件中加载添加账户视图
         View addAccountView = LayoutInflater.from(this).inflate(R.layout.add_account_text, null);
         // 设置对话框内容视图
         dialogBuilder.setView(addAccountView);
 
         // 显示对话框
         final AlertDialog dialog = dialogBuilder.show();
         // 添加账户视图点击事件
         addAccountView.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 // 标记已添加账户
                 mHasAddedAccount = true;
                 // 创建一个Intent对象，跳转到添加账户设置界面
                 Intent intent = new Intent("android.settings.ADD_ACCOUNT_SETTINGS");
                 // 设置账户类型过滤器
                 intent.putExtra(AUTHORITIES_FILTER_KEY, new String[] {
                     "gmail-ls"
                 });
                 // 启动Activity
                 startActivityForResult(intent, -1);
                 // 关闭对话框
                 dialog.dismiss();
             }
         });
     }
 
     // 显示更改账户确认对话框
     private void showChangeAccountConfirmAlertDialog() {
         // 创建对话框构建器
         AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);
 
         // 加载对话框标题布局
         View titleView = LayoutInflater.from(this).inflate(R.layout.account_dialog_title, null);
         // 获取标题文本视图
         TextView titleTextView = (TextView) titleView.findViewById(R.id.account_dialog_title);
         // 设置标题文本
         titleTextView.setText(getString(R.string.preferences_dialog_change_account_title,
                 getSyncAccountName(this)));
         // 获取副标题文本视图
         TextView subtitleTextView = (TextView) titleView.findViewById(R.id.account_dialog_subtitle);
         // 设置副标题文本
         subtitleTextView.setText(getString(R.string.preferences_dialog_change_account_warn_msg));
         // 设置自定义标题
         dialogBuilder.setCustomTitle(titleView);
 
         // 创建菜单项数组
         CharSequence[] menuItemArray = new CharSequence[] {
                 getString(R.string.preferences_menu_change_account),
                 getString(R.string.preferences_menu_remove_account),
                 getString(R.string.preferences_menu_cancel)
         };
         // 设置对话框菜单项
         dialogBuilder.setItems(menuItemArray, new DialogInterface.OnClickListener() {
             public void onClick(DialogInterface dialog, int which) {
                 // 如果点击了更改账户菜单项
                 if (which == 0) {
                     // 显示选择账户对话框
                     showSelectAccountAlertDialog();
                 // 如果点击了移除账户菜单项
                 } else if (which == 1) {
                     // 移除同步账户
                     removeSyncAccount();
                     // 刷新UI
                     refreshUI();
                 }
             }
         });
         // 显示对话框
         dialogBuilder.show();
     }
 
     // 获取Google账户
     private Account[] getGoogleAccounts() {
         // 获取AccountManager实例
         AccountManager accountManager = AccountManager.get(this);
         // 获取类型为com.google的账户
         return accountManager.getAccountsByType("com.google");
     }
 
     // 设置同步账户
     private void setSyncAccount(String account) {
         // 如果当前同步账户与传入的账户不一致，则进行以下操作
         if (!getSyncAccountName(this).equals(account)) {
             // 获取SharedPreferences对象
             SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
             // 获取SharedPreferences.Editor对象
             SharedPreferences.Editor editor = settings.edit();
             // 如果传入的账户不为空，则将账户名保存到SharedPreferences中
             if (account != null) {
                 editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, account);
             } else {
                 // 如果传入的账户为空，则将账户名保存为空字符串
                 editor.putString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
             }
             // 提交修改
             editor.commit();
 
             // clean up last sync time
             setLastSyncTime(this, 0);
 
             // clean up local gtask related info
             new Thread(new Runnable() {
                 public void run() {
                     ContentValues values = new ContentValues();
                     values.put(NoteColumns.GTASK_ID, "");
                     values.put(NoteColumns.SYNC_ID, 0);
                     getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
                 }
             }).start();
 
             Toast.makeText(NotesPreferenceActivity.this,
                     getString(R.string.preferences_toast_success_set_accout, account),
                     Toast.LENGTH_SHORT).show();
         }
     }
 
     // 移除同步账户
     private void removeSyncAccount() {
         // 获取SharedPreferences对象
         SharedPreferences settings = getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
         // 获取SharedPreferences.Editor对象
         SharedPreferences.Editor editor = settings.edit();
         // 如果SharedPreferences中包含PREFERENCE_SYNC_ACCOUNT_NAME键，则移除该键值对
         if (settings.contains(PREFERENCE_SYNC_ACCOUNT_NAME)) {
             editor.remove(PREFERENCE_SYNC_ACCOUNT_NAME);
         }
         // 如果SharedPreferences中包含PREFERENCE_LAST_SYNC_TIME键，则移除该键值对
         if (settings.contains(PREFERENCE_LAST_SYNC_TIME)) {
             editor.remove(PREFERENCE_LAST_SYNC_TIME);
         }
         // 提交修改
         editor.commit();
 
         // clean up local gtask related info
         new Thread(new Runnable() {
             public void run() {
                 ContentValues values = new ContentValues();
                 values.put(NoteColumns.GTASK_ID, "");
                 values.put(NoteColumns.SYNC_ID, 0);
                 getContentResolver().update(Notes.CONTENT_NOTE_URI, values, null, null);
             }
         }).start();
     }
 
     // 获取同步账户名称
     public static String getSyncAccountName(Context context) {
         // 获取SharedPreferences对象
         SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
                 Context.MODE_PRIVATE);
         // 获取同步账户名称
         return settings.getString(PREFERENCE_SYNC_ACCOUNT_NAME, "");
     }
 
     // 设置最后同步时间
     public static void setLastSyncTime(Context context, long time) {
         // 获取SharedPreferences对象
         SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
                 Context.MODE_PRIVATE);
         // 获取SharedPreferences.Editor对象
         SharedPreferences.Editor editor = settings.edit();
         // 将最后同步时间存入SharedPreferences对象
         editor.putLong(PREFERENCE_LAST_SYNC_TIME, time);
         // 提交修改
         editor.commit();
     }
 
     // 获取最后一次同步时间
     public static long getLastSyncTime(Context context) {
         // 获取SharedPreferences对象
         SharedPreferences settings = context.getSharedPreferences(PREFERENCE_NAME,
                 Context.MODE_PRIVATE);
         // 获取最后一次同步时间
         return settings.getLong(PREFERENCE_LAST_SYNC_TIME, 0);
     }
 
     private class GTaskReceiver extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
             // 刷新UI
             refreshUI();
             // 如果广播中包含同步状态
             if (intent.getBooleanExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_IS_SYNCING, false)) {
                 // 获取同步状态文本框
                 TextView syncStatus = (TextView) findViewById(R.id.prefenerece_sync_status_textview);
                 // 设置同步状态文本框的文本为广播中的进度信息
                 syncStatus.setText(intent
                         .getStringExtra(GTaskSyncService.GTASK_SERVICE_BROADCAST_PROGRESS_MSG));
             }
 
         }
     }
 
     // 处理菜单项的点击事件
     public boolean onOptionsItemSelected(MenuItem item) {
         // 根据菜单项的ID进行判断
         switch (item.getItemId()) {
             // 如果点击的是返回键
             case android.R.id.home:
                 // 创建一个新的Intent，指向NotesListActivity
                 Intent intent = new Intent(this, NotesListActivity.class);
                 // 设置Intent的标志，清除栈顶的Activity
                 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                 // 启动新的Activity
                 startActivity(intent);
                 // 返回true，表示已经处理了该菜单项
                 return true;
             // 如果点击的是其他菜单项
             default:
                 // 返回false，表示没有处理该菜单项
                 return false;
         }
     }
 }
 