From eae89cb84b629fd6892b2a4c90f071771dec075f Mon Sep 17 00:00:00 2001
From: lh <1648870916@qq.com>
Date: Wed, 6 May 2026 19:02:55 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=95=B4=E8=A6=86=E7=9B=96?=
=?UTF-8?q?=E4=B8=8A=E4=BC=A0src=E7=9B=AE=E5=BD=95=EF=BC=8C=E5=90=8C?=
=?UTF-8?q?=E6=AD=A5=E6=89=80=E6=9C=89=E6=96=87=E4=BB=B6=E5=92=8C=E7=9B=AE?=
=?UTF-8?q?=E5=BD=95=E7=BB=93=E6=9E=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/Note.java | 391 ------
src/NoteEditActivity.java | 1030 ----------------
src/WorkingNote.java | 498 --------
.../NotesListActivity.java | 1043 -----------------
.../SEARCH_FEATURE_IMPROVEMENT.md | 264 -----
src/小米便签搜索功能/note_list.xml | 93 --
.../note_list_with_search.xml | 85 --
src/小米便签搜索功能/strings.xml | 139 ---
8 files changed, 3543 deletions(-)
delete mode 100644 src/Note.java
delete mode 100644 src/NoteEditActivity.java
delete mode 100644 src/WorkingNote.java
delete mode 100644 src/小米便签搜索功能/NotesListActivity.java
delete mode 100644 src/小米便签搜索功能/SEARCH_FEATURE_IMPROVEMENT.md
delete mode 100644 src/小米便签搜索功能/note_list.xml
delete mode 100644 src/小米便签搜索功能/note_list_with_search.xml
delete mode 100644 src/小米便签搜索功能/strings.xml
diff --git a/src/Note.java b/src/Note.java
deleted file mode 100644
index e29c3fe..0000000
--- a/src/Note.java
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.micode.notes.model;
-// 导入内容提供者操作相关类,用于批量操作数据库
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-// 用于在URI后面追加ID
-import android.content.ContentUris;
-// 用于存储键值对数据,类似于Map
-import android.content.ContentValues;
-// Android上下文类,用于访问系统资源
-import android.content.Context;
-// 操作应用异常,批量操作时可能抛出
-import android.content.OperationApplicationException;
-// URI类,用于标识数据资源
-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;
-import net.micode.notes.data.Notes.DataColumns;
-import net.micode.notes.data.Notes.NoteColumns;
-import net.micode.notes.data.Notes.TextNote;
-
-// ArrayList列表类
-import java.util.ArrayList;
-
-
-// Note类:表示一个便签的数据模型,负责管理便签的属性和关联数据
-public class Note {
- // 存储便签本身的属性差异值(修改后的值)
- private ContentValues mNoteDiffValues;
- // 存储便签关联的数据(文本数据和通话数据)
- private NoteData mNoteData;
- // 日志标签
- private static final String TAG = "Note";
- /**
- * 创建一个新的便签ID,用于向数据库中添加新便签
- * @param context Android上下文
- * @param folderId 便签所属的文件夹ID
- * @return 新创建的便签ID
- */
- public static synchronized long getNewNoteId(Context context, long folderId) {
- // 在数据库中创建一个新的便签记录
- // ContentValues用于存储要插入的键值对
- ContentValues values = new ContentValues();
- // 获取当前时间作为创建时间
- long createdTime = System.currentTimeMillis();
- // 设置创建时间
- values.put(NoteColumns.CREATED_DATE, createdTime);
- // 设置修改时间(刚创建时与创建时间相同)
- values.put(NoteColumns.MODIFIED_DATE, createdTime);
- // 设置类型为便签(非文件夹、非系统类型)
- values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
- // 标记为本地已修改
- values.put(NoteColumns.LOCAL_MODIFIED, 1);
- // 设置父文件夹ID
- values.put(NoteColumns.PARENT_ID, folderId);
- // 通过内容解析器插入到数据库,返回新记录的URI
- Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
-
- // 初始化便签ID为0
- long noteId = 0;
- try {
- // 从URI路径中解析出ID(路径格式通常为 content://authority/note/123)
- // getPathSegments().get(1) 获取路径的第二个部分(ID)
- noteId = Long.valueOf(uri.getPathSegments().get(1));
- } catch (NumberFormatException e) {
- // 如果URI格式不正确,记录错误日志
- Log.e(TAG, "Get note id error :" + e.toString());
- noteId = 0;
- }
- // 如果ID为-1,说明出现错误,抛出异常
- if (noteId == -1) {
- throw new IllegalStateException("Wrong note id:" + noteId);
- }
- // 返回新创建的便签ID
- return noteId;
- }
-
- // 构造函数:初始化Note对象
- public Note() {
- // 初始化便签属性差异值容器
- mNoteDiffValues = new ContentValues();
- // 初始化便签数据对象
- mNoteData = new NoteData();
- }
-
- // 设置便签的属性值(如标题、背景色等)
- // @param key 属性键名
- // @param value 属性值
- public void setNoteValue(String key, String value) {
- // 将键值对存入差异值容器
- mNoteDiffValues.put(key, value);
- // 标记为本地已修改
- mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
- // 更新修改时间为当前时间
- mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
- }
-
- // 设置文本数据的属性值
- // @param key 属性键名
- // @param value 属性值
- public void setTextData(String key, String value) {
- mNoteData.setTextData(key, value);
- }
-
- // 设置文本数据的ID
- // @param id 文本数据在数据库中的ID
- public void setTextDataId(long id) {
- mNoteData.setTextDataId(id);
- }
-
- // 获取文本数据的ID
- // @return 文本数据ID
- public long getTextDataId() {
- return mNoteData.mTextDataId;
- }
-
- // 设置通话记录数据的ID
- // @param id 通话数据在数据库中的ID
- public void setCallDataId(long id) {
- mNoteData.setCallDataId(id);
- }
-
- // 设置通话记录数据的属性值
- // @param key 属性键名
- // @param value 属性值
- public void setCallData(String key, String value) {
- mNoteData.setCallData(key, value);
- }
-
- // 检查本地是否有修改
- // @return true表示有修改,false表示无修改
- public boolean isLocalModified() {
- // 便签属性有修改 或 便签数据有修改,返回true
- return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
- }
-
- // 同步便签到数据库
- // @param context Android上下文
- // @param noteId 便签ID
- // @return true表示同步成功,false表示失败
- public boolean syncNote(Context context, long noteId) {
- // 检查便签ID是否有效
- if (noteId <= 0) {
- throw new IllegalArgumentException("Wrong note id:" + noteId);
- }
-
- // 如果本地没有修改,直接返回成功
- if (!isLocalModified()) {
- return true;
- }
-
- /**
- * 理论上,一旦数据发生变化,便签应该在NoteColumns.LOCAL_MODIFIED和NoteColumns.MODIFIED_DATE上更新
- * 为了数据安全,即使更新便签失败,我们也会更新便签数据信息
- */
- // 更新便签属性到数据库
- // ContentUris.withAppendedId 将noteId附加到URI后面,形成完整的资源路径
- if (context.getContentResolver().update(
- ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
- null) == 0) {
- // 如果更新失败,记录错误日志
- Log.e(TAG, "Update note error, should not happen");
- // 不返回,继续执行(为了数据安全)
- }
- // 清除已同步的差异值
- mNoteDiffValues.clear();
-
- // 如果便签数据有修改,尝试推送到数据库
- if (mNoteData.isLocalModified()
- && (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
- // 如果推送失败,返回false
- return false;
- }
-
- // 所有同步操作完成,返回成功
- return true;
- }
-
- // 内部类:NoteData,用于管理便签的关联数据(文本数据和通话记录数据)
- private class NoteData {
- // 文本数据在数据库中的ID
- private long mTextDataId;
-
- // 存储文本数据的属性值
- private ContentValues mTextDataValues;
-
- // 通话记录数据在数据库中的ID
- private long mCallDataId;
-
- // 存储通话记录数据的属性值
- private ContentValues mCallDataValues;
-
- // 日志标签
- private static final String TAG = "NoteData";
-
- // 构造函数:初始化NoteData对象
- public NoteData() {
- // 初始化文本数据容器
- mTextDataValues = new ContentValues();
- // 初始化通话数据容器
- mCallDataValues = new ContentValues();
- // 初始化文本数据ID为0
- mTextDataId = 0;
- // 初始化通话数据ID为0
- mCallDataId = 0;
- }
-
- // 检查本地数据是否有修改
- // @return true表示有修改,false表示无修改
- boolean isLocalModified() {
- // 文本数据有修改 或 通话数据有修改,返回true
- return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
- }
-
- // 设置文本数据的ID
- // @param id 文本数据ID
- void setTextDataId(long id) {
- // 检查ID是否有效
- if(id <= 0) {
- throw new IllegalArgumentException("Text data id should larger than 0");
- }
- // 设置文本数据ID
- mTextDataId = id;
- }
-
- // 设置通话记录数据的ID
- // @param id 通话数据ID
- void setCallDataId(long id) {
- // 检查ID是否有效
- if (id <= 0) {
- throw new IllegalArgumentException("Call data id should larger than 0");
- }
- // 设置通话数据ID
- mCallDataId = id;
- }
-
- // 设置通话记录数据的属性值
- // @param key 属性键名
- // @param value 属性值
- void setCallData(String key, String value) {
- // 将键值对存入通话数据容器
- mCallDataValues.put(key, value);
- // 标记为本地已修改
- mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
- // 更新修改时间为当前时间
- mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
- }
-
- // 设置文本数据的属性值
- // @param key 属性键名
- // @param value 属性值
- void setTextData(String key, String value) {
- // 将键值对存入文本数据容器
- mTextDataValues.put(key, value);
- // 标记为本地已修改
- mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
- // 更新修改时间为当前时间
- mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
- }
-
- // 将数据推送到ContentResolver(数据库)
- // @param context Android上下文
- // @param noteId 便签ID
- // @return 成功返回URI,失败返回null
- Uri pushIntoContentResolver(Context context, long noteId) {
- /**
- * 安全检查:检查便签ID是否有效
- */
- if (noteId <= 0) {
- throw new IllegalArgumentException("Wrong note id:" + noteId);
- }
-
- // 创建批量操作列表
- ArrayList
- * 负责便签的创建、编辑、删除等核心功能。提供文本编辑、背景色切换、
- * 闹钟设置、字体大小调整、清单模式切换等功能。
- *
- * 主要功能:
- *
- *
- *
- * 当内存不足时当前Activity可能被系统杀死,用户再次加载时应恢复之前的编辑状态 - *
- * - * @param savedInstanceState 之前通过onSaveInstanceState保存的状态信息 - */ - @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.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); - if (!initActivityState(intent)) { - finish(); - return; - } - Log.d(TAG, "Restoring from killed activity"); - } - } - - /** - * 初始化Activity状态,根据Intent动作加载或创建便签 - *- * 支持两种Intent动作: - * 1. ACTION_VIEW: 查看/编辑现有便签 - * 2. ACTION_INSERT_OR_EDIT: 创建新便签或编辑通话记录便签 - *
- * - * @param intent 启动Activity的Intent对象 - * @return boolean 初始化是否成功 - * - true: 初始化成功,可以继续编辑 - * - false: 初始化失败,应关闭Activity - */ - private boolean initActivityState(Intent intent) { - // 清空工作便签引用 - mWorkingNote = null; - - // 判断是否为查看便签的动作 - if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { - // 从Intent中获取便签ID,默认为0 - long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); - // 清空搜索关键词 - mUserQuery = ""; - - // 检查是否从搜索结果启动,如果是则获取搜索相关的便签ID和关键词 - 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)) { - // 便签不存在,跳转到列表页并显示错误提示 - Intent jump = new Intent(this, NotesListActivity.class); - startActivity(jump); - showToast(R.string.error_note_not_exist); - finish(); - return false; - } else { - // 便签存在,从数据库加载便签内容 - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - // 加载失败,记录错误并关闭Activity - Log.e(TAG, "load note failed with note id" + noteId); - finish(); - 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())) { - // 从Intent中获取文件夹ID,默认为0(根文件夹) - long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); - // 获取小部件ID,默认为无效ID - int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - // 获取小部件类型,默认为无效类型 - int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, - Notes.TYPE_WIDGET_INVALIDE); - // 获取背景资源ID,默认为系统默认背景 - int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, - ResourceParser.getDefaultBgId(this)); - - // 处理通话记录便签 - String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); - long callDate = intent.getLongExtra(Notes.INTENT_EXTRA_CALL_DATE, 0); - // 如果提供了电话号码和通话日期,说明是通话记录便签 - if (callDate != 0 && phoneNumber != null) { - // 检查电话号码是否为空 - if (TextUtils.isEmpty(phoneNumber)) { - Log.w(TAG, "The call record number is null"); - } - long noteId = 0; - // 尝试查找是否已有该电话号码和日期的通话记录便签 - if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), - phoneNumber, callDate)) > 0) { - // 找到现有便签,加载它 - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - // 加载失败,记录错误并关闭 - Log.e(TAG, "load call note failed with note id" + noteId); - finish(); - return false; - } - } else { - // 没有找到现有便签,创建新的通话记录便签 - mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, - widgetType, bgResId); - // 将便签转换为通话记录类型 - mWorkingNote.convertToCallNote(phoneNumber, callDate); - } - } else { - // 普通便签,直接创建空便签 - mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, - bgResId); - } - - // 设置软键盘模式:窗口调整大小,初始显示键盘 - getWindow().setSoftInputMode( - WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE - | WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); - } else { - // 不支持的Intent动作,记录错误并关闭 - Log.e(TAG, "Intent not specified action, should not support"); - finish(); - return false; - } - // 设置便签状态变化监听器为当前Activity - mWorkingNote.setOnSettingStatusChangedListener(this); - return true; - } - - @Override - protected void onResume() { - super.onResume(); - initNoteScreen(); - } - - /** - * 初始化便签屏幕显示 - *- * 设置字体大小、加载便签内容、设置背景色、显示修改时间和闹钟信息 - *
- */ - private void initNoteScreen() { - // 设置文本编辑器的字体样式 - mNoteEditor.setTextAppearance(this, TextAppearanceResources - .getTexAppearanceResource(mFontSizeId)); - // 检查是否为清单模式 - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - // 切换到清单模式显示 - switchToListMode(mWorkingNote.getContent()); - } else { - // 普通模式,设置文本并高亮搜索关键词 - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - // 将光标移动到文本末尾 - 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 - | DateUtils.FORMAT_SHOW_YEAR)); - - /** - * TODO: Add the menu for setting alert. Currently disable it because the DateTimePicker - * is not ready - */ - // 显示闹钟头部信息 - showAlertHeader(); - } - - /** - * 显示闹钟头部信息 - *- * 如果便签设置了闹钟,显示闹钟时间或过期提示;否则隐藏闹钟信息 - *
- */ - private void showAlertHeader() { - // 检查便签是否有闹钟设置 - if (mWorkingNote.hasClockAlert()) { - // 获取当前时间 - long time = System.currentTimeMillis(); - // 判断闹钟是否已过期 - if (time > mWorkingNote.getAlertDate()) { - // 闹钟已过期,显示过期提示 - mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); - } else { - // 闹钟未过期,显示相对时间(如"5分钟后") - mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( - mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); - } - // 显示闹钟日期文本和图标 - mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); - mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); - } else { - // 没有闹钟设置,隐藏闹钟信息 - mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); - 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); - /** - * For new note without note id, we should firstly save it to - * generate a id. If the editing note is not worth saving, there - * is no id which is equivalent to create new note - */ - if (!mWorkingNote.existInDatabase()) { - saveNote(); - } - 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); - int x = location[0]; - int y = location[1]; - if (ev.getX() < x - || ev.getX() > (x + view.getWidth()) - || ev.getY() < y - || ev.getY() > (y + view.getHeight())) { - return false; - } - return true; - } - - private void initResources() { - mHeadViewPanel = findViewById(R.id.note_title); - 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); - mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); - mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); - mNoteEditor = (EditText) findViewById(R.id.note_edit_view); - mNoteEditorPanel = findViewById(R.id.sv_note_edit); - mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); - for (int id : sBgSelectorBtnsMap.keySet()) { - ImageView iv = (ImageView) findViewById(id); - iv.setOnClickListener(this); - } - - mFontSizeSelector = findViewById(R.id.font_size_selector); - 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. - * The id may larger than the length of resources, in this case, - * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} - */ - if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { - mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; - } - mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); - } - - @Override - protected void onPause() { - super.onPause(); - if(saveNote()) { - Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); - } - clearSettingState(); - } - - private void updateWidget() { - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { - intent.setClass(this, NoteWidgetProvider_2x.class); - } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { - intent.setClass(this, NoteWidgetProvider_4x.class); - } else { - Log.e(TAG, "Unspported widget type"); - return; - } - - intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { - 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); - } else if (sBgSelectorBtnsMap.containsKey(id)) { - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.GONE); - mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); - mNoteBgColorSelector.setVisibility(View.GONE); - } 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 { - mNoteEditor.setTextAppearance(this, - TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); - } - mFontSizeSelector.setVisibility(View.GONE); - } - } - - @Override - public void onBackPressed() { - if(clearSettingState()) { - return; - } - - saveNote(); - super.onBackPressed(); - } - - private boolean clearSettingState() { - 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) { - getMenuInflater().inflate(R.menu.call_note_edit, menu); - } else { - getMenuInflater().inflate(R.menu.note_edit, menu); - } - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); - } else { - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); - } - if (mWorkingNote.hasClockAlert()) { - menu.findItem(R.id.menu_alert).setVisible(false); - } else { - menu.findItem(R.id.menu_delete_remind).setVisible(false); - } - return true; - } - - /** - * 处理菜单项点击事件 - * - * @param item 被点击的菜单项 - * @return boolean 是否处理了该事件 - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // 获取菜单项ID - int id = item.getItemId(); - // 处理新建便签 - if (id == R.id.menu_new_note) { - createNewNote(); - } - // 处理删除便签 - else if (id == 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(); - } - // 处理字体大小设置 - else if (id == R.id.menu_font_size) { - mFontSizeSelector.setVisibility(View.VISIBLE); - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); - } - // 处理清单模式切换 - else if (id == R.id.menu_list_mode) { - mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ? - TextNote.MODE_CHECK_LIST : 0); - } - // 处理分享功能 - else if (id == R.id.menu_share) { - getWorkingText(); - sendTo(this, mWorkingNote.getContent()); - } - // 处理发送到桌面 - else if (id == R.id.menu_send_to_desktop) { - sendToDesktop(); - } - // 处理设置闹钟 - else if (id == R.id.menu_alert) { - setReminder(); - } - // 处理删除闹钟 - else if (id == R.id.menu_delete_remind) { - mWorkingNote.setAlertDate(0, false); - } - return true; - } - - 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(); - } - - /** - * Share note to apps that support {@link Intent#ACTION_SEND} action - * 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- * 获取当前编辑的文本内容,调用WorkingNote.saveNote()保存到数据库。 - * 如果保存成功,设置Activity结果为RESULT_OK,用于告知列表页回到原始位置 - *
- * - * @return boolean 保存是否成功 - */ - private boolean saveNote() { - // 获取当前编辑的文本内容 - getWorkingText(); - // 调用WorkingNote保存到数据库 - boolean saved = mWorkingNote.saveNote(); - if (saved) { - /** - * There are two modes from List view to edit view, open one note, - * create/edit a node. Opening node requires to the original - * position in the list when back from edit view, while creating a - * new node requires to the top of the list. This code - * {@link #RESULT_OK} is used to identify the create/edit state - */ - // 设置Activity结果为RESULT_OK,表示成功保存 - setResult(RESULT_OK); - } - return saved; - } - - private void sendToDesktop() { - /** - * Before send message to home, we should make sure that current - * editing note is exists in databases. So, for new note, firstly - * 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, - makeShortcutIconTitle(mWorkingNote.getContent())); - sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); - sender.putExtra("duplicate", true); - sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); - showToast(R.string.info_note_enter_desktop); - sendBroadcast(sender); - } else { - /** - * There is the condition that user has input nothing (the note is - * not worthy saving), we have no note id, remind the user that he - * should input something - */ - Log.e(TAG, "Send to desktop error"); - showToast(R.string.error_note_empty_for_send_to_desktop); - } - } - - private String makeShortcutIconTitle(String content) { - content = content.replace(TAG_CHECKED, ""); - content = content.replace(TAG_UNCHECKED, ""); - return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, - SHORTCUT_ICON_TITLE_MAX_LEN) : content; - } - - private void showToast(int resId) { - showToast(resId, Toast.LENGTH_SHORT); - } - - private void showToast(int resId, int duration) { - Toast.makeText(this, resId, duration).show(); - } -} diff --git a/src/WorkingNote.java b/src/WorkingNote.java deleted file mode 100644 index 8c7ed54..0000000 --- a/src/WorkingNote.java +++ /dev/null @@ -1,498 +0,0 @@ -package net.micode.notes.model; - -import android.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.database.Cursor; -import android.text.TextUtils; -import android.util.Log; - -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.CallNote; -import net.micode.notes.data.Notes.DataColumns; -import net.micode.notes.data.Notes.DataConstants; -import net.micode.notes.data.Notes.NoteColumns; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.tool.ResourceParser.NoteBgResources; - - -public class WorkingNote { - // 工作便签的笔记对象 - private Note mNote; - // 便签ID - private long mNoteId; - // 便签内容 - private String mContent; - // 便签模式(普通模式或清单模式) - private int mMode; - - // 提醒日期(时间戳) - private long mAlertDate; - - // 最后修改日期(时间戳) - private long mModifiedDate; - - // 背景颜色ID - private int mBgColorId; - - // 桌面小部件ID - private int mWidgetId; - - // 桌面小部件类型(2x或4x) - private int mWidgetType; - - // 所属文件夹ID - private long mFolderId; - - // Android上下文对象 - private Context mContext; - - // 日志标签 - private static final String TAG = "WorkingNote"; - - // 删除标记,表示便签是否已被删除 - private boolean mIsDeleted; - - // 便签设置变更监听器 - private NoteSettingChangedListener mNoteSettingStatusListener; - - // 数据查询投影数组 - 用于从数据库查询便签数据内容 - public static final String[] DATA_PROJECTION = new String[] { - DataColumns.ID, - DataColumns.CONTENT, - DataColumns.MIME_TYPE, - DataColumns.DATA1, - DataColumns.DATA2, - DataColumns.DATA3, - DataColumns.DATA4, - }; - - // 便签查询投影数组 - 用于从数据库查询便签基本信息 - public static final String[] NOTE_PROJECTION = new String[] { - NoteColumns.PARENT_ID, - NoteColumns.ALERTED_DATE, - NoteColumns.BG_COLOR_ID, - NoteColumns.WIDGET_ID, - NoteColumns.WIDGET_TYPE, - NoteColumns.MODIFIED_DATE - }; - - // 数据ID列在查询结果中的索引位置 - private static final int DATA_ID_COLUMN = 0; - - // 数据内容列在查询结果中的索引位置 - private static final int DATA_CONTENT_COLUMN = 1; - - // 数据类型(MIME)列在查询结果中的索引位置 - private static final int DATA_MIME_TYPE_COLUMN = 2; - - // 数据模式列在查询结果中的索引位置 - private static final int DATA_MODE_COLUMN = 3; - - // 父级文件夹ID列在查询结果中的索引位置 - private static final int NOTE_PARENT_ID_COLUMN = 0; - - // 提醒日期列在查询结果中的索引位置 - private static final int NOTE_ALERTED_DATE_COLUMN = 1; - - // 背景颜色ID列在查询结果中的索引位置 - private static final int NOTE_BG_COLOR_ID_COLUMN = 2; - - // 小部件ID列在查询结果中的索引位置 - private static final int NOTE_WIDGET_ID_COLUMN = 3; - - // 小部件类型列在查询结果中的索引位置 - private static final int NOTE_WIDGET_TYPE_COLUMN = 4; - - // 修改日期列在查询结果中的索引位置 - private static final int NOTE_MODIFIED_DATE_COLUMN = 5; - - // 新便签构造函数 - 创建一个空的新便签 - private WorkingNote(Context context, long folderId) { - mContext = context; - mAlertDate = 0; - mModifiedDate = System.currentTimeMillis(); - mFolderId = folderId; - mNote = new Note(); - mNoteId = 0; - mIsDeleted = false; - mMode = 0; - mWidgetType = Notes.TYPE_WIDGET_INVALIDE; - } - - // 现有便签构造函数 - 从数据库加载已存在的便签 - private WorkingNote(Context context, long noteId, long folderId) { - mContext = context; - mNoteId = noteId; - mFolderId = folderId; - mIsDeleted = false; - mNote = new Note(); - loadNote(); - } - - /** - * 从数据库加载便签的基本信息(背景色、小部件、提醒等) - */ - 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); - mBgColorId = cursor.getInt(NOTE_BG_COLOR_ID_COLUMN); - mWidgetId = cursor.getInt(NOTE_WIDGET_ID_COLUMN); - mWidgetType = cursor.getInt(NOTE_WIDGET_TYPE_COLUMN); - mAlertDate = cursor.getLong(NOTE_ALERTED_DATE_COLUMN); - mModifiedDate = cursor.getLong(NOTE_MODIFIED_DATE_COLUMN); - } - cursor.close(); - } else { - Log.e(TAG, "No note with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note with id " + mNoteId); - } - loadNoteData(); - } - - /** - * 从数据库加载便签的数据内容(文本内容和通话记录) - */ - private void loadNoteData() { - Cursor cursor = mContext.getContentResolver().query(Notes.CONTENT_DATA_URI, DATA_PROJECTION, - DataColumns.NOTE_ID + "=?", new String[] { - String.valueOf(mNoteId) - }, null); - - if (cursor != null) { - if (cursor.moveToFirst()) { - do { - String type = cursor.getString(DATA_MIME_TYPE_COLUMN); - if (DataConstants.NOTE.equals(type)) { - mContent = cursor.getString(DATA_CONTENT_COLUMN); - mMode = cursor.getInt(DATA_MODE_COLUMN); - mNote.setTextDataId(cursor.getLong(DATA_ID_COLUMN)); - } else if (DataConstants.CALL_NOTE.equals(type)) { - mNote.setCallDataId(cursor.getLong(DATA_ID_COLUMN)); - } else { - Log.d(TAG, "Wrong note type with type:" + type); - } - } while (cursor.moveToNext()); - } - cursor.close(); - } else { - Log.e(TAG, "No data with id:" + mNoteId); - throw new IllegalArgumentException("Unable to find note's data with id " + mNoteId); - } - } - - /** - * 创建一个新的空便签(工厂方法) - * @param context Android上下文 - * @param folderId 所属文件夹ID - * @param widgetId 桌面小部件ID - * @param widgetType 桌面小部件类型 - * @param defaultBgColorId 默认背景颜色ID - * @return 新创建的便签对象 - */ - public static WorkingNote createEmptyNote(Context context, long folderId, int widgetId, - int widgetType, int defaultBgColorId) { - WorkingNote note = new WorkingNote(context, folderId); - note.setBgColorId(defaultBgColorId); - note.setWidgetId(widgetId); - note.setWidgetType(widgetType); - return note; - } - - /** - * 从数据库加载指定ID的便签(工厂方法) - * @param context Android上下文 - * @param id 便签ID - * @return 加载的便签对象 - */ - public static WorkingNote load(Context context, long id) { - return new WorkingNote(context, id, 0); - } - - /** - * 保存便签到数据库(同步操作) - * @return 保存成功返回true,否则返回false - */ - public synchronized boolean saveNote() { - if (isWorthSaving()) { - if (!existInDatabase()) { - if ((mNoteId = Note.getNewNoteId(mContext, mFolderId)) == 0) { - Log.e(TAG, "Create new note fail with id:" + mNoteId); - return false; - } - } - - mNote.syncNote(mContext, mNoteId); - - /** - * 如果存在该便签的桌面小部件,则更新小部件内容 - */ - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE - && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } - return true; - } else { - return false; - } - } - - /** - * 检查便签是否已存在于数据库中(通过ID判断) - * @return 存在返回true,否则返回false - */ - public boolean existInDatabase() { - return mNoteId > 0; - } - - /** - * 判断便签是否值得保存(是否有实际内容或修改) - * @return 值得保存返回true,否则返回false - */ - private boolean isWorthSaving() { - if (mIsDeleted || (!existInDatabase() && TextUtils.isEmpty(mContent)) - || (existInDatabase() && !mNote.isLocalModified())) { - return false; - } else { - return true; - } - } - - /** - * 设置便签设置状态变更监听器 - * @param l 监听器对象 - */ - public void setOnSettingStatusChangedListener(NoteSettingChangedListener l) { - mNoteSettingStatusListener = l; - } - - /** - * 设置闹钟提醒日期 - * @param date 提醒日期(时间戳) - * @param set 是否设置提醒的标志 - */ - public void setAlertDate(long date, boolean set) { - if (date != mAlertDate) { - mAlertDate = date; - mNote.setNoteValue(NoteColumns.ALERTED_DATE, String.valueOf(mAlertDate)); - } - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onClockAlertChanged(date, set); - } - } - - /** - * 标记便签的删除状态 - * @param mark true表示标记为删除,false表示取消删除标记 - */ - public void markDeleted(boolean mark) { - mIsDeleted = mark; - if (mWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID - && mWidgetType != Notes.TYPE_WIDGET_INVALIDE && mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onWidgetChanged(); - } - } - - /** - * 设置便签的背景颜色 - * @param id 背景颜色ID - */ - public void setBgColorId(int id) { - if (id != mBgColorId) { - mBgColorId = id; - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onBackgroundColorChanged(); - } - mNote.setNoteValue(NoteColumns.BG_COLOR_ID, String.valueOf(id)); - } - } - - /** - * 设置便签的模式(普通文本模式或清单模式) - * @param mode 模式值(0为普通模式,1为清单模式) - */ - public void setCheckListMode(int mode) { - if (mMode != mode) { - if (mNoteSettingStatusListener != null) { - mNoteSettingStatusListener.onCheckListModeChanged(mMode, mode); - } - mMode = mode; - mNote.setTextData(TextNote.MODE, String.valueOf(mMode)); - } - } - - /** - * 设置桌面小部件的类型 - * @param type 小部件类型(2x或4x) - */ - public void setWidgetType(int type) { - if (type != mWidgetType) { - mWidgetType = type; - mNote.setNoteValue(NoteColumns.WIDGET_TYPE, String.valueOf(mWidgetType)); - } - } - - /** - * 设置桌面小部件的ID - * @param id 小部件ID - */ - public void setWidgetId(int id) { - if (id != mWidgetId) { - mWidgetId = id; - mNote.setNoteValue(NoteColumns.WIDGET_ID, String.valueOf(mWidgetId)); - } - } - - /** - * 设置便签的工作文本内容 - * @param text 便签文本内容 - */ - public void setWorkingText(String text) { - if (!TextUtils.equals(mContent, text)) { - mContent = text; - mNote.setTextData(DataColumns.CONTENT, mContent); - } - } - - /** - * 将当前便签转换为通话记录便签 - * @param phoneNumber 电话号码 - * @param 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)); - } - - /** - * 检查便签是否设置了闹钟提醒 - * @return 有提醒返回true,否则返回false - */ - public boolean hasClockAlert() { - return (mAlertDate > 0 ? true : false); - } - - /** - * 获取便签的文本内容 - * @return 便签内容字符串 - */ - public String getContent() { - return mContent; - } - - /** - * 获取闹钟提醒日期 - * @return 提醒日期(时间戳),未设置则返回0 - */ - public long getAlertDate() { - return mAlertDate; - } - - /** - * 获取便签的最后修改日期 - * @return 修改日期(时间戳) - */ - public long getModifiedDate() { - return mModifiedDate; - } - - /** - * 获取背景颜色的资源ID(用于UI显示) - * @return 背景颜色资源ID - */ - public int getBgColorResId() { - return NoteBgResources.getNoteBgResource(mBgColorId); - } - - /** - * 获取背景颜色ID - * @return 背景颜色ID - */ - public int getBgColorId() { - return mBgColorId; - } - - /** - * 获取标题栏背景颜色的资源ID(用于UI显示) - * @return 标题背景颜色资源ID - */ - public int getTitleBgResId() { - return NoteBgResources.getNoteTitleBgResource(mBgColorId); - } - - /** - * 获取便签的当前模式(普通模式或清单模式) - * @return 模式值(0为普通模式,1为清单模式) - */ - public int getCheckListMode() { - return mMode; - } - - /** - * 获取便签的ID - * @return 便签ID,新便签返回0 - */ - public long getNoteId() { - return mNoteId; - } - - /** - * 获取便签所属文件夹的ID - * @return 文件夹ID - */ - public long getFolderId() { - return mFolderId; - } - - /** - * 获取关联的桌面小部件ID - * @return 小部件ID,未关联则返回无效值 - */ - public int getWidgetId() { - return mWidgetId; - } - - /** - * 获取关联的桌面小部件类型 - * @return 小部件类型(2x或4x),未关联则返回无效值 - */ - public int getWidgetType() { - return mWidgetType; - } - - /** - * 便签设置变更监听器接口 - 用于通知UI层便签属性的变化 - */ - public interface NoteSettingChangedListener { - /** - * 当当前便签的背景颜色发生改变时调用 - */ - void onBackgroundColorChanged(); - - /** - * 当用户设置或取消闹钟提醒时调用 - * @param date 提醒日期 - * @param set true表示设置提醒,false表示取消提醒 - */ - void onClockAlertChanged(long date, boolean set); - - /** - * 当用户从小部件创建便签或小部件需要更新时调用 - */ - void onWidgetChanged(); - - /** - * 当在清单模式和普通模式之间切换时调用 - * @param oldMode 更改前的模式 - * @param newMode 更改后的新模式 - */ - void onCheckListModeChanged(int oldMode, int newMode); - } -} diff --git a/src/小米便签搜索功能/NotesListActivity.java b/src/小米便签搜索功能/NotesListActivity.java deleted file mode 100644 index 22b62a3..0000000 --- a/src/小米便签搜索功能/NotesListActivity.java +++ /dev/null @@ -1,1043 +0,0 @@ -/* - * 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.LinearLayout; -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; - - // 搜索功能相关变量 - 新增 - private LinearLayout mSearchBox; - private EditText mSearchEditText; - private Button mCancelSearchButton; - private String mSearchQuery = ""; - - @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 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); - if (in != null) { - InputStreamReader isr = new InputStreamReader(in); - BufferedReader br = new BufferedReader(isr); - char [] buf = new char[1024]; - int len = 0; - while ((len = br.read(buf)) > 0) { - sb.append(buf, 0, len); - } - } else { - Log.e(TAG, "Read introduction file error"); - return; - } - } catch (IOException e) { - e.printStackTrace(); - return; - } finally { - if(in != null) { - try { - 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; - } - } - } - - @Override - protected void 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(); - - // 初始化搜索框 - 新增 - initSearchBox(); - } - - /** - * 初始化搜索框组件 - * 设置搜索输入框的监听器和取消按钮的点击事件 - */ - private void initSearchBox() { - mSearchBox = (LinearLayout) findViewById(R.id.ll_search_box); - mSearchEditText = (EditText) findViewById(R.id.et_search); - mCancelSearchButton = (Button) findViewById(R.id.btn_cancel_search); - - // 搜索输入框监听 - 实时搜索 - mSearchEditText.addTextChangedListener(new TextWatcher() { - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - mSearchQuery = s.toString(); - // 重新查询,添加搜索过滤 - startAsyncNotesListQuery(); - } - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) {} - - @Override - public void afterTextChanged(Editable s) {} - }); - - // 取消按钮点击事件 - mCancelSearchButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - hideSearchBox(); - } - }); - } - - /** - * 显示搜索框 - * 显示搜索框容器,获取焦点并弹出软键盘 - */ - private void showSearchBox() { - mSearchBox.setVisibility(View.VISIBLE); - mSearchEditText.requestFocus(); - // 显示软键盘 - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(mSearchEditText, InputMethodManager.SHOW_IMPLICIT); - } - - /** - * 隐藏搜索框 - * 清空搜索内容,隐藏搜索框和软键盘,重新查询所有便签 - */ - private void hideSearchBox() { - mSearchBox.setVisibility(View.GONE); - mSearchEditText.setText(""); - mSearchQuery = ""; - // 隐藏软键盘 - InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(mSearchEditText.getWindowToken(), 0); - // 重新查询所有便签 - startAsyncNotesListQuery(); - } - - private class ModeCallback implements ListView.MultiChoiceModeListener, OnMenuItemClickListener { - private DropdownMenu mDropDownMenu; - private ActionMode mActionMode; - private MenuItem mMoveMenu; - - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - getMenuInflater().inflate(R.menu.note_list_options, menu); - menu.findItem(R.id.delete).setOnMenuItemClickListener(this); - mMoveMenu = menu.findItem(R.id.move); - if (mFocusNoteDataItem.getParentId() == Notes.ID_CALL_RECORD_FOLDER - || DataUtils.getUserFolderCount(mContentResolver) == 0) { - mMoveMenu.setVisible(false); - } else { - mMoveMenu.setVisible(true); - mMoveMenu.setOnMenuItemClickListener(this); - } - mActionMode = mode; - mNotesListAdapter.setChoiceMode(true); - mNotesListView.setLongClickable(false); - mAddNewNote.setVisibility(View.GONE); - - View customView = LayoutInflater.from(NotesListActivity.this).inflate( - R.layout.note_list_dropdown_menu, null); - mode.setCustomView(customView); - mDropDownMenu = new DropdownMenu(NotesListActivity.this, - (Button) customView.findViewById(R.id.selection_menu), - R.menu.note_list_dropdown); - 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; - } - - int itemId = item.getItemId(); - if (itemId == 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(); - } else if (itemId == R.id.move) { - startQueryDestinationFolders(); - } else { - 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; - 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. - */ - if (event.getY() < (event.getX() * (-0.12) + 94)) { - View view = mNotesListView.getChildAt(mNotesListView.getChildCount() - 1 - - mNotesListView.getFooterViewsCount()); - 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; - } - } - return false; - } - - }; - - /** - * 启动异步便签列表查询 - * 根据当前文件夹ID和搜索关键词查询便签列表 - */ - private void startAsyncNotesListQuery() { - String selection; - String[] selectionArgs; - - // 判断是否有搜索关键词 - if (!TextUtils.isEmpty(mSearchQuery)) { - // 有搜索关键词,添加模糊匹配条件 - if (mCurrentFolderId == Notes.ID_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)" - + " AND " + NoteColumns.SNIPPET + " LIKE ?"; - selectionArgs = new String[] { - String.valueOf(mCurrentFolderId), - "%" + mSearchQuery + "%" - }; - } else { - // 子文件夹:搜索当前文件夹 + 搜索关键词 - selection = NoteColumns.PARENT_ID + "=? AND " + NoteColumns.SNIPPET + " LIKE ?"; - selectionArgs = new String[] { - String.valueOf(mCurrentFolderId), - "%" + mSearchQuery + "%" - }; - } - } else { - // 无搜索关键词,正常查询 - selection = (mCurrentFolderId == Notes.ID_ROOT_FOLDER) ? ROOT_FOLDER_SELECTION - : NORMAL_SELECTION; - selectionArgs = new String[] { - String.valueOf(mCurrentFolderId) - }; - } - - mBackgroundQueryHandler.startQuery(FOLDER_NOTE_LIST_QUERY_TOKEN, null, - Notes.CONTENT_NOTE_URI, NoteItemData.PROJECTION, selection, selectionArgs, - NoteColumns.TYPE + " DESC," + NoteColumns.MODIFIED_DATE + " DESC"); - } - - private final class BackgroundQueryHandler extends AsyncQueryHandler { - public BackgroundQueryHandler(ContentResolver contentResolver) { - super(contentResolver); - } - - @Override - protected void onQueryComplete(int token, Object cookie, Cursor cursor) { - switch (token) { - case FOLDER_NOTE_LIST_QUERY_TOKEN: - mNotesListAdapter.changeCursor(cursor); - break; - case FOLDER_LIST_QUERY_TOKEN: - if (cursor != null && cursor.getCount() > 0) { - showFolderListMenu(cursor); - } else { - Log.e(TAG, "Query folder failed"); - } - break; - default: - return; - } - } - } - - private void showFolderListMenu(Cursor cursor) { - AlertDialog.Builder builder = new AlertDialog.Builder(NotesListActivity.this); - builder.setTitle(R.string.menu_title_select_folder); - 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(); - mModeCallBack.finishActionMode(); - } - }); - builder.show(); - } - - private void createNewNote() { - Intent intent = new Intent(this, NoteEditActivity.class); - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); - intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mCurrentFolderId); - this.startActivityForResult(intent, REQUEST_CODE_NEW_NODE); - } - - private void batchDelete() { - new AsyncTask