From 399ff736b7aa23e49e5bfd1f87118937242d4bab Mon Sep 17 00:00:00 2001 From: zhouxs <1923828641@qq.com> Date: Mon, 30 Dec 2024 20:06:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/代码注释.txt | 1066 ------------------------------------------ 1 file changed, 1066 deletions(-) delete mode 100644 src/代码注释.txt diff --git a/src/代码注释.txt b/src/代码注释.txt deleted file mode 100644 index f8ecac4..0000000 --- a/src/代码注释.txt +++ /dev/null @@ -1,1066 +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.AlarmManager; -import android.app.AlertDialog; -import android.app.PendingIntent; -import android.app.SearchManager; -import android.appwidget.AppWidgetManager; -import android.content.ContentUris; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.graphics.Paint; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.text.style.BackgroundColorSpan; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.WindowManager; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.Toast; - -import net.micode.notes.R; -import net.micode.notes.data.Notes; -import net.micode.notes.data.Notes.TextNote; -import net.micode.notes.model.WorkingNote; -import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; -import net.micode.notes.tool.DataUtils; -import net.micode.notes.tool.ResourceParser; -import net.micode.notes.tool.ResourceParser.TextAppearanceResources; -import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; -import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; -import net.micode.notes.widget.NoteWidgetProvider_2x; -import net.micode.notes.widget.NoteWidgetProvider_4x; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -// NoteEditActivity类继承自Activity,实现了OnClickListener、NoteSettingChangedListener、OnTextViewChangeListener接口,用于笔记编辑相关的界面展示与操作逻辑处理 -public class NoteEditActivity extends Activity implements OnClickListener, - NoteSettingChangedListener, OnTextViewChangeListener { - - // 内部类,用于方便地持有笔记头部视图相关的控件引用,方便后续操作 - private class HeadViewHolder { - // 用于显示笔记修改时间的TextView控件引用 - public TextView tvModified; - // 用于显示提醒图标(如闹钟图标等)的ImageView控件引用 - public ImageView ivAlertIcon; - // 用于显示提醒时间相关信息(如具体时间、相对时间等)的TextView控件引用 - public TextView tvAlertDate; - // 用于设置笔记背景颜色的ImageView控件引用,点击它可能弹出背景颜色选择相关的操作界面 - public ImageView ibSetBgColor; - } - - // 存储背景颜色选择按钮(如不同颜色的按钮)与对应颜色资源ID的映射关系,方便根据按钮ID获取对应的颜色值 - private static final Map sBgSelectorBtnsMap = new HashMap(); - static { - sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); - sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); - sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); - sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); - sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); - } - - // 存储背景颜色与对应选中状态显示控件(可能是用于突出显示当前选中颜色的图标等)ID的映射关系,方便根据颜色值找到对应的显示控件 - private static final Map sBgSelectorSelectionMap = new HashMap(); - static { - sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); - sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); - sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); - sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); - sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); - } - - // 存储字体大小选择按钮(如大、小、正常等按钮)与对应字体大小资源ID的映射关系,便于根据按钮ID获取相应字体大小设置值 - private static final Map sFontSizeBtnsMap = new HashMap(); - static { - sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); - sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); - sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); - sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); - } - - // 存储字体大小与对应选中状态显示控件(可能是用于突出显示当前选中字体大小的图标等)ID的映射关系,方便根据字体大小值找到对应的显示控件 - private static final Map sFontSelectorSelectionMap = new HashMap(); - static { - sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); - sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); - } - - // 用于日志记录的标签,方便在Logcat中区分本类相关的日志信息 - private static final String TAG = "NoteEditActivity"; - - // 用于持有笔记头部视图相关控件的实例,通过它可以方便地操作头部视图中的各个子控件 - private HeadViewHolder mNoteHeaderHolder; - // 笔记头部视图的整体布局视图引用,包含了如修改时间、提醒相关图标等多个子控件所在的布局 - private View mHeadViewPanel; - // 笔记背景颜色选择器的视图引用,可能是一个弹出式的布局或者可切换显示的区域,用于选择笔记的背景颜色 - private View mNoteBgColorSelector; - // 字体大小选择器的视图引用,类似背景颜色选择器,用于选择笔记内容显示的字体大小 - private View mFontSizeSelector; - // 用于编辑笔记内容的EditText控件引用,用户在这里输入和修改笔记的具体文本内容 - private EditText mNoteEditor; - // 笔记编辑区域的整体布局视图引用,包含了编辑文本的EditText等相关组件所在的布局 - private View mNoteEditorPanel; - // 代表正在编辑的笔记的实例,封装了笔记的各种属性(如内容、背景颜色、提醒设置等)以及相关操作方法(如保存、设置属性等) - private WorkingNote mWorkingNote; - // 用于获取和操作应用的共享偏好设置,可用于存储和读取一些用户个性化配置(如字体大小偏好等) - private SharedPreferences mSharedPrefs; - // 当前选中的字体大小对应的资源ID,通过它来设置笔记内容的字体显示大小 - private int mFontSizeId; - - // 存储字体大小偏好设置的键名,用于在共享偏好设置中标识字体大小相关的配置项 - private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; - - // 定义快捷方式图标标题的最大长度,用于生成显示在桌面快捷方式上的简短标题,避免标题过长显示不全 - private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; - - // 定义表示已勾选状态的特殊字符,用于在处理清单模式(Check List Mode)的笔记内容中标记已勾选的项 - public static final String TAG_CHECKED = String.valueOf('\u221A'); - // 定义表示未勾选状态的特殊字符,同样用于清单模式笔记内容中标记未勾选的项 - public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); - - // 线性布局视图引用,用于在清单模式下展示笔记内容的多个条目(每个条目可能包含一个可勾选的CheckBox和编辑文本的EditText等) - private LinearLayout mEditTextList; - - // 用于存储用户搜索的查询字符串,可能用于在编辑笔记时对搜索结果相关的笔记内容进行处理(如高亮显示搜索关键词等) - private String mUserQuery; - // 用于编译用户查询字符串为正则表达式模式,以便后续在笔记内容中进行匹配查找操作(如查找搜索关键词出现的位置等) - private Pattern mPattern; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - // 设置当前Activity的布局内容,这里使用的是名为"note_edit"的布局文件来展示界面 - this.setContentView(R.layout.note_edit); - - // 如果savedInstanceState为空(即Activity首次创建,不是由于配置改变等原因重新创建), - // 并且通过initActivityState方法初始化Activity状态失败(返回false),则直接结束当前Activity,不再进行后续初始化操作 - if (savedInstanceState == null &&!initActivityState(getIntent())) { - finish(); - return; - } - // 初始化相关资源,如查找布局中的各个视图控件等操作 - initResources(); - } - - /** - * 当前Activity可能会因为内存不足被系统销毁,当用户再次进入此Activity时,需要恢复之前的状态 - */ - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - // 如果savedInstanceState不为空,并且其中包含了Intent.EXTRA_UID这个键(通常用于标识笔记的唯一ID) - if (savedInstanceState!= null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { - // 创建一个新的Intent,设置其动作为Intent.ACTION_VIEW,表示查看笔记的意图 - Intent intent = new Intent(Intent.ACTION_VIEW); - // 从savedInstanceState中获取之前保存的笔记ID,并添加到新的Intent中作为额外数据传递 - intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); - // 通过initActivityState方法尝试恢复Activity状态,如果恢复失败(返回false),则结束当前Activity,不再继续执行 - if (!initActivityState(intent)) { - finish(); - return; - } - Log.d(TAG, "Restoring from killed activity"); - } - } - - // 用于初始化Activity的状态,根据传入的Intent中的不同动作(Action)和相关数据来确定要编辑的笔记或创建新笔记等操作 - private boolean initActivityState(Intent intent) { - // 先将正在编辑的笔记实例设为null,表示初始状态下还未确定要编辑的具体笔记 - mWorkingNote = null; - // 如果传入的Intent的动作是Intent.ACTION_VIEW(表示查看、编辑已有笔记的意图) - if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { - // 从Intent中获取笔记的ID,如果没有传递则默认为0,这里获取的ID用于后续查找对应的笔记实例 - long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); - mUserQuery = ""; - - // 如果Intent中包含了SearchManager.EXTRA_DATA_KEY这个额外数据(表示是从搜索结果进入编辑页面的情况) - if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { - // 从Intent中获取搜索结果对应的笔记ID(这里可能是经过搜索处理后的特定格式的ID),并转换为long类型赋值给noteId - noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); - // 获取用户在搜索时输入的查询字符串,用于后续在笔记内容中可能的处理(如高亮显示关键词等) - mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); - } - - // 通过DataUtils工具类的visibleInNoteDatabase方法,结合内容解析器、笔记ID以及笔记类型(Notes.TYPE_NOTE)判断该笔记是否在笔记数据库中可见(即是否存在且符合相关条件) - if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { - // 如果笔记不存在,创建一个跳转到NotesListActivity的Intent,启动该Activity展示笔记列表 - Intent jump = new Intent(this, NotesListActivity.class); - startActivity(jump); - // 显示一个Toast提示用户笔记不存在,提示信息对应的字符串资源ID为R.string.error_note_not_exist - showToast(R.string.error_note_not_exist); - finish(); - return false; - } else { - // 如果笔记存在,通过WorkingNote的load方法加载对应的笔记实例,如果加载失败(返回null),则记录错误日志并结束当前Activity,返回false表示初始化失败 - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - 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的动作是Intent.ACTION_INSERT_OR_EDIT(表示创建新笔记或编辑已有笔记的意图),以下是创建新笔记的相关逻辑 - - // 从Intent中获取笔记所属文件夹的ID,如果没有传递则默认为0,该ID用于确定笔记在文件系统中的存储位置等相关操作 - long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0); - // 从Intent中获取笔记关联的小部件(Widget)的ID,如果没有传递则设为无效的小部件ID(AppWidgetManager.INVALID_APPWIDGET_ID),可能用于与桌面小部件交互相关的操作 - int widgetId = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_ID, - AppWidgetManager.INVALID_APPWIDGET_ID); - // 从Intent中获取笔记关联的小部件类型,如果没有传递则设为无效的小部件类型(Notes.TYPE_WIDGET_INVALIDE),用于区分不同类型的小部件与笔记的关联情况 - int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, - Notes.TYPE_WIDGET_INVALIDE); - // 从Intent中获取笔记的背景资源ID,如果没有传递则通过ResourceParser的getDefaultBgId方法获取默认的背景资源ID,用于设置笔记的背景样式 - int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, - ResourceParser.getDefaultBgId(this)); - - // 解析通话记录笔记相关逻辑,如果Intent中包含了通话记录相关的额外数据(电话号码和通话日期),则进行相应处理 - - // 从Intent中获取通话记录的电话号码字符串 - String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER); - // 从Intent中获取通话记录的通话日期(时间戳形式) - 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; - // 通过DataUtils工具类的getNoteIdByPhoneNumberAndCallDate方法,结合内容解析器、电话号码和通话日期查找对应的笔记ID,如果找到(返回值大于0) - if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), - phoneNumber, callDate)) > 0) { - // 则加载对应的笔记实例,如果加载失败则记录错误日志并结束当前Activity,返回false表示初始化失败 - mWorkingNote = WorkingNote.load(this, noteId); - if (mWorkingNote == null) { - Log.e(TAG, "load call note failed with note id" + noteId); - finish(); - return false; - } - } else { - // 如果没有找到对应的笔记ID,则创建一个空的笔记实例,通过WorkingNote的createEmptyNote方法传入相关参数(当前上下文、文件夹ID、小部件ID、小部件类型、背景资源ID)创建新笔记 - mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, - widgetType, bgRes -// 将新创建的空笔记转换为通话记录笔记,传入电话号码和通话日期进行相应设置 - 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没有指定有效的动作(Action),记录错误日志并结束当前Activity,返回false表示不支持这种情况 - Log.e(TAG, "Intent not specified action, should not support"); - finish(); - return false; - } - // 为正在编辑的笔记实例设置设置状态改变监听器为当前Activity(因为当前Activity实现了NoteSettingChangedListener接口),以便在笔记相关设置改变时能做出响应处理 - mWorkingNote.setOnSettingStatusChangedListener(this); - return true; - } - - @Override - protected void onResume() { - super.onResume(); - // 当Activity重新回到前台可见时,调用此方法初始化笔记编辑界面的展示内容等相关设置 - initNoteScreen(); - } - - // 用于初始化笔记编辑界面的展示内容,如设置字体大小、根据笔记模式显示相应内容、更新界面上的时间等信息以及显示提醒相关的头部信息等 - private void initNoteScreen() { - // 根据当前选中的字体大小资源ID,设置笔记编辑框(mNoteEditor)的文本外观(字体大小等样式),通过TextAppearanceResources工具类获取对应的字体外观资源进行设置 - mNoteEditor.setTextAppearance(this, TextAppearanceResources - .getTexAppearanceResource(mFontSizeId)); - // 如果正在编辑的笔记处于清单模式(Check List Mode) - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - // 调用switchToListMode方法将笔记内容切换为清单模式展示,传入笔记内容字符串进行相应处理和界面更新 - 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); - } - // 根据正在编辑的笔记的标题背景资源ID,设置笔记头部视图面板(mHeadViewPanel)的背景资源,更新头部视图的背景样式 - mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); - // 根据正在编辑的笔记的内容背景颜色资源ID,设置笔记编辑区域面板(mNoteEditorPanel)的背景资源,更新编辑区域的背景颜色 - mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - - // 使用DateUtils工具类格式化正在编辑的笔记的修改日期,按照指定的格式(包含显示日期、数字格式日期、显示时间、显示年份等)设置到笔记头部的修改时间TextView(mNoteHeaderHolder.tvModified)中显示 - 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方法显示或隐藏提醒相关的头部信息(如提醒时间、提醒图标等),根据笔记是否设置了提醒来决定显示与否 - showAlertHeader(); - } - - // 根据笔记是否设置了时钟提醒,来显示或隐藏提醒相关的头部信息(提醒时间、提醒图标等) - private void showAlertHeader() { - if (mWorkingNote.hasClockAlert()) { - long time = System.currentTimeMillis(); - if (time > mWorkingNote.getAlertDate()) { - // 如果当前时间大于笔记设置的提醒时间,设置提醒时间TextView显示提示文字(如已过期等),对应的字符串资源ID为R.string.note_alert_expired - mNoteHeaderHolder.tvAlertDate.setText(R.string.note_alert_expired); - } else { - // 如果当前时间小于等于笔记设置的提醒时间,使用DateUtils工具类获取相对时间字符串(相对于当前时间的时间差描述,如几分钟后等),并设置到提醒时间TextView中显示 - mNoteHeaderHolder.tvAlertDate.setText(DateUtils.getRelativeTimeSpanString( - mWorkingNote.getAlertDate(), time, DateUtils.MINUTE_IN_MILLIS)); - } - // 将提醒时间TextView和提醒图标ImageView都设置为可见,展示提醒相关信息 - mNoteHeaderHolder.tvAlertDate.setVisibility(View.VISIBLE); - mNoteHeaderHolder.ivAlertIcon.setVisibility(View.VISIBLE); - } else { - // 如果笔记没有设置时钟提醒,将提醒时间TextView和提醒图标ImageView都设置为不可见,隐藏提醒相关信息 - mNoteHeaderHolder.tvAlertDate.setVisibility(View.GONE); - mNoteHeaderHolder.ivAlertIcon.setVisibility(View.GONE); - }; - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - // 当Activity接收到新的Intent(比如通过启动模式设置等情况,Activity可能会复用而接收到新的启动意图)时,调用此方法重新初始化Activity的状态 - 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 - */ - // 如果正在编辑的笔记不存在于数据库中(可能是新建还未保存的笔记),先调用saveNote方法保存笔记,以便生成笔记ID等相关数据 - if (!mWorkingNote.existInDatabase()) { - saveNote(); - } - // 将正在编辑的笔记的ID保存到outState中,以便在Activity可能被销毁后重新创建时恢复相关数据,使用Intent.EXTRA_UID这个键来标识笔记ID - outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); - Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); - } - - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - // 如果背景颜色选择器视图当前是可见状态,并且触摸事件发生的位置不在背景颜色选择器视图范围内(通过inRangeOfView方法判断) - if (mNoteBgColorSelector.getVisibility() == View.VISIBLE - &&!inRangeOfView(mNoteBgColorSelector, ev)) { - // 则将背景颜色选择器视图设置为不可见,隐藏它,并返回true表示已经处理了此次触摸事件,不再传递给其他触摸事件处理方法 - mNoteBgColorSelector.setVisibility(View.GONE); - return true; - } - - // 如果字体大小选择器视图当前是可见状态,并且触摸事件发生的位置不在字体大小选择器视图范围内(通过inRangeOfView方法判断) - if (mFontSizeSelector.getVisibility() == View.VISIBLE - &&!inRangeOfView(mFontSizeSelector, ev)) { - // 则将字体大小选择器视图设置为不可见,隐藏它,并返回true表示已经处理了此次触摸事件,不再传递给其他触摸事件处理方法 - mFontSizeSelector.setVisibility(View.GONE); - return true; - } - // 如果上述情况都不满足,调用父类的dispatchTouchEvent方法继续处理触摸事件,按照默认的触摸事件传递机制进行处理 - return super.dispatchTouchEvent(ev); - } - - // 判断触摸事件发生的位置是否在指定视图的范围内,用于处理如点击外部区域隐藏相关选择器视图等逻辑 - private boolean inRangeOfView(View view, MotionEvent ev) { - int []location = new int[2]; - // 获取指定视图在屏幕上的坐标位置(左上角坐标),存储到location数组中,location[0]为x坐标,location[1]为y坐标 - view.getLocationOnScreen(location); - int x = location[0]; - int y = location[1]; - // 判断触摸事件的x坐标是否小于视图的x坐标,或者大于视图的x坐标加上视图宽度,或者触摸事件的y坐标小于视图的y坐标,或者大于视图的y坐标加上视图高度,如果满足这些条件之一,则表示触摸事件不在视图范围内,返回false - if (ev.getX() < x - || ev.getX() > (x + view.getWidth()) - || ev.getY() < y - || ev.getY() > (y + view.getHeight())) { - return false; - } - return true; - } - - // 用于初始化Activity中的各种视图资源引用,如查找布局中的各个控件并设置相关点击监听器等操作 - private void initResources() { - // 通过findViewById方法找到笔记标题布局视图(可能包含修改时间、提醒图标、设置背景颜色按钮等控件所在的整体布局),并赋值给mHeadViewPanel变量 - mHeadViewPanel = findViewById(R.id.note_title); - mNoteHeaderHolder = new HeadViewHolder(); - // 通过findViewById方法找到笔记头部的修改时间TextView控件,并赋值给mNoteHeaderHolder.tvModified变量,方便后续操作该控件 - mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); - // 同理,找到提醒图标ImageView控件并赋值给mNoteHeaderHolder.ivAlertIcon变量 - mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); - // 找到提醒时间TextView控件并赋值给mNoteHeaderHolder.tvAlertDate变量 - mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); - // 找到设置背景颜色的ImageView控件并赋值给mNoteHeaderHolder.ibSetBgColor变量,同时为该控件设置点击监听器为当前Activity(因为当前Activity实现了OnClickListener接口),以便响应点击事件进行背景颜色选择相关操作 - mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); - mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); - // 找到用于编辑笔记内容的EditText控件并赋值给mNoteEditor变量,用户在这里输入和修改笔记文本内容 - mNoteEditor = (EditText) findViewById(R.id.note_edit_view); - // 找到笔记编辑区域的整体布局视图(可能包含EditText及相关装饰、滚动等组件所在的布局),并赋值给mNoteEditorPanel变量 - mNoteEditorPanel = findViewById(R.id.sv_note_edit); - // 找到背景颜色选择器视图(可能是一个弹出式布局或者可切换显示的区域用于选择背景颜色),并赋值给mNoteBgColorSelector变量 - mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); - // 遍历背景颜色选择按钮映射表的所有键(即各个背景颜色按钮的ID),通过findViewById方法找到对应的ImageView按钮控件,并为每个按钮设置点击监听器为当前Activity,以便响应点击按钮选择背景颜色的操作 - for (int id : sBgSelectorBtnsMap.keySet()) { - ImageView iv = (ImageView) findViewById(id); - iv.setOnClickListener(this); - } - - // 找到字体大小选择器视图(类似背景颜色选择器,用于选择字体大小的布局区域),并赋值给mFontSizeSelector变量 - mFontSizeSelector = findViewById(R.id.font_size_selector); - // 遍历字体大小选择按钮映射表的所有键(即各个字体大小选择按钮的ID),通过findViewById方法找到对应的视图控件,并为每个按钮设置点击监听器为当前Activity,以便响应点击按钮选择字体大小的操作 - for (int id : sFontSizeBtnsMap.keySet()) { - View view = findViewById(id); - view.setOnClickListener(this); - }; - // 获取应用默认的共享偏好设置实例,通过PreferenceManager的getDefaultSharedPreferences方法传入当前上下文获取,可用于读取和存储用户的个性化配置(如之前设置的字体大小偏好等) - mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); - // 从共享偏好设置中获取字体大小偏好设置的值(对应的键为PREFERENCE_FONT_SIZE),如果不存在则使用ResourceParser.BG_DEFAULT_FONT_SIZE作为默认值,并赋值给mFontSizeId变量,用于后续设置笔记内容的字体大小 - 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} - */ - // 如果获取到的字体大小资源ID大于字体外观资源的数量(可能表示出现异常情况,资源ID不合法等),则将字体大小ID设置为默认的字体大小资源ID(ResourceParser.BG_DEFAULT_FONT_SIZE) - if (mFontSizeId >= TextAppearanceResources.getResourcesSize()) { - mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; - } - // 通过findViewById方法找到用于在清单模式下展示笔记内容条目的线性布局视图,并赋值给mEditTextList变量 - mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); - } - - @Override - protected void onPause() { - super.onPause(); - // 当Activity即将暂停(如切换到后台、失去焦点等情况)时,调用此方法,如果保存笔记成功(saveNote方法返回true),则记录日志提示笔记数据已保存以及保存的笔记内容长度 - if (saveNote()) { - Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); - } - // 调用clearSettingState方法清除当前可能存在的一些设置状态(如隐藏显示的选择器视图等) - clearSettingState(); - } - - // 用于更新与笔记相关联的桌面小部件(Widget)显示内容,根据笔记关联的小部件类型发送广播通知小部件更新 - 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); - } - - // 处理各个视图控件的点击事件逻辑,根据点击的视图控件ID进行不同的操作,如显示/隐藏选择器、设置背景颜色、选择字体大小等 - public void onClick(View v) { - int id = v.getId(); - if (id == R.id.btn_set_bg_color) { - // 如果点击的是设置背景颜色的按钮(mNoteHeaderHolder.ibSetBgColor对应的按钮),则将背景颜色选择器视图设置为可见,显示出背景颜色选择相关的界面 - mNoteBgColorSelector.setVisibility(View.VISIBLE); - // 根据正在编辑的笔记当前的背景颜色ID,找到对应的背景颜色选中状态显示控件,并将其设置为可见,突出显示当前选中的背景颜色(如果之前有选中过的话) - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - - View.VISIBLE); - } else if (sBgSelectorBtnsMap.containsKey(id)) { - // 如果点击的视图控件ID在背景颜色选择按钮映射表中(表示点击了某个具体的背景颜色选择按钮) - // 先将之前选中的背景颜色对应的选中状态显示控件设置为不可见,隐藏之前的选中状态显示 - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.GONE); - // 根据点击的按钮ID,通过背景颜色选择按钮映射表获取对应的新的背景颜色资源ID,并设置给正在编辑的笔记实例,更新笔记的背景颜色属性 - mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); - // 将背景颜色选择器视图设置为不可见,隐藏背景颜色选择界面,完成背景颜色选择操作 - mNoteBgColorSelector.setVisibility(View.GONE); - } else if (sFontSizeBtnsMap.containsKey(id)) { - // 如果点击的视图控件ID在字体大小选择按钮映射表中(表示点击了某个具体的字体大小选择按钮) - // 先将之前 - // 先将之前选中的字体大小对应的选中状态显示控件设置为不可见,隐藏之前的选中状态显示 - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); - // 根据点击的按钮ID,通过字体大小选择按钮映射表获取对应的新的字体大小资源ID,并赋值给mFontSizeId变量,更新当前选中的字体大小 - mFontSizeId = sFontSizeBtnsMap.get(id); - // 将新的字体大小资源ID保存到共享偏好设置中,以便下次进入编辑界面时能恢复该字体大小设置,通过edit方法获取编辑器,putInt方法设置键值对,最后commit方法提交保存更改 - mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); - // 根据新的字体大小资源ID,找到对应的字体大小选中状态显示控件,并将其设置为可见,突出显示当前选中的字体大小 - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); - // 如果正在编辑的笔记处于清单模式(Check List Mode) - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - // 调用getWorkingText方法获取当前笔记的文本内容(会根据清单模式下的勾选情况等进行相应处理) - getWorkingText(); - // 调用switchToListMode方法将笔记内容切换为清单模式展示,传入笔记内容字符串进行相应处理和界面更新 - switchToListMode(mWorkingNote.getContent()); - } else { - // 如果笔记不是清单模式,根据新的字体大小资源ID,设置笔记编辑框(mNoteEditor)的文本外观(字体大小等样式),通过TextAppearanceResources工具类获取对应的字体外观资源进行设置 - mNoteEditor.setTextAppearance(this, - TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); - } - // 将字体大小选择器视图设置为不可见,隐藏字体大小选择界面,完成字体大小选择操作 - mFontSizeSelector.setVisibility(View.GONE); - } - } - - @Override - public void onBackPressed() { - // 当用户按下返回键时调用此方法,先调用clearSettingState方法清除当前可能存在的一些设置状态(如隐藏显示的选择器视图等),如果该方法返回true(表示有需要清除的设置状态并已成功清除),则直接返回,不执行后续保存笔记和关闭Activity的操作 - if (clearSettingState()) { - return; - } - - // 调用saveNote方法保存当前正在编辑的笔记内容 - saveNote(); - // 调用父类的onBackPressed方法,执行默认的返回操作,关闭当前Activity(如果没有被拦截等情况的话) - super.onBackPressed(); - } - - // 用于清除当前界面上一些显示的设置状态,比如隐藏背景颜色选择器视图和字体大小选择器视图等,返回值表示是否有状态被清除(即是否有对应的视图处于显示状态并被隐藏了) - private boolean clearSettingState() { - // 如果背景颜色选择器视图当前是可见状态 - if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { - // 将其设置为不可见,隐藏背景颜色选择器视图,并返回true表示有状态被清除 - mNoteBgColorSelector.setVisibility(View.GONE); - return true; - } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { - // 如果字体大小选择器视图当前是可见状态,将其设置为不可见,隐藏字体大小选择器视图,并返回true表示有状态被清除 - mFontSizeSelector.setVisibility(View.GONE); - return true; - } - // 如果上述两个选择器视图都不是可见状态,则返回false,表示没有需要清除的设置状态 - return false; - } - - // 当笔记的背景颜色发生改变时调用此方法,用于更新界面上相关的显示,比如显示对应的背景颜色选中状态以及更新编辑区域和头部视图的背景资源 - public void onBackgroundColorChanged() { - // 根据正在编辑的笔记当前的背景颜色ID,找到对应的背景颜色选中状态显示控件,并将其设置为可见,突出显示当前选中的背景颜色 - findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( - View.VISIBLE); - // 根据正在编辑的笔记的背景颜色资源ID,设置笔记编辑区域面板(mNoteEditorPanel)的背景资源,更新编辑区域的背景颜色 - mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); - // 根据正在编辑的笔记的标题背景资源ID,设置笔记头部视图面板(mHeadViewPanel)的背景资源,更新头部视图的背景样式 - mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - // 当Activity准备显示选项菜单(Options Menu)时调用此方法,用于配置菜单的显示内容等相关设置 - - // 如果Activity正在结束(比如正在执行关闭操作等情况),则直接返回true,表示不需要进行菜单相关的配置操作了 - if (isFinishing()) { - return true; - } - // 调用clearSettingState方法清除当前可能存在的一些设置状态(如隐藏显示的选择器视图等),确保菜单显示时界面状态是合适的 - clearSettingState(); - // 清空菜单中的所有现有菜单项,准备重新添加需要显示的菜单项 - menu.clear(); - // 如果正在编辑的笔记所属的文件夹ID是通话记录文件夹的ID(Notes.ID_CALL_RECORD_FOLDER),则通过菜单填充器(getMenuInflater)加载通话记录笔记编辑对应的菜单布局资源(R.menu.call_note_edit)到菜单中 - if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { - getMenuInflater().inflate(R.menu.call_note_edit, menu); - } else { - // 如果不是通话记录文件夹的笔记,则加载普通笔记编辑对应的菜单布局资源(R.menu.note_edit)到菜单中 - getMenuInflater().inflate(R.menu.note_edit, menu); - } - // 如果正在编辑的笔记处于清单模式(Check List Mode),将菜单中对应清单模式切换的菜单项(R.id.menu_list_mode)的标题设置为正常模式相关的文字(对应的字符串资源ID为R.string.menu_normal_mode) - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_normal_mode); - } else { - // 如果笔记不是清单模式,将该菜单项的标题设置为清单模式相关的文字(对应的字符串资源ID为R.string.menu_list_mode) - menu.findItem(R.id.menu_list_mode).setTitle(R.string.menu_list_mode); - } - // 如果笔记已经设置了时钟提醒,将菜单中设置提醒的菜单项(R.id.menu_alert)设置为不可见,因为已经设置了提醒就不需要重复设置了 - if (mWorkingNote.hasClockAlert()) { - menu.findItem(R.id.menu_alert).setVisible(false); - } else { - // 如果笔记没有设置时钟提醒,将菜单中删除提醒的菜单项(R.id.menu_delete_remind)设置为不可见,因为没有提醒可删 - menu.findItem(R.id.menu_delete_remind).setVisible(false); - } - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // 处理选项菜单中各个菜单项被点击的事件逻辑,根据菜单项的ID进行不同的操作 - - switch (item.getItemId()) { - case R.id.menu_new_note: - // 如果点击的是新建笔记菜单项(R.id.menu_new_note) - createNewNote(); - break; - case R.id.menu_delete: - // 如果点击的是删除笔记菜单项(R.id.menu_delete) - // 创建一个AlertDialog的构建器,用于构建一个提示删除确认的对话框 - AlertDialog.Builder builder = new AlertDialog.Builder(this); - // 设置对话框的标题,使用对应的字符串资源ID(R.string.alert_title_delete)获取提示文字,如“删除笔记”等 - builder.setTitle(getString(R.string.alert_title_delete)); - // 设置对话框的图标,使用安卓系统默认的警告图标(android.R.drawable.ic_dialog_alert),显示一个警告标识 - builder.setIcon(android.R.drawable.ic_dialog_alert); - // 设置对话框的提示消息内容,使用对应的字符串资源ID(R.string.alert_message_delete_note)获取提示文字,如“确定要删除此笔记吗?”等 - builder.setMessage(getString(R.string.alert_message_delete_note)); - // 设置对话框的确定按钮(点击确认删除的操作),传入安卓系统默认的确认按钮文字(android.R.string.ok)作为按钮文本,同时设置点击事件监听器,在监听器中调用deleteCurrentNote方法删除当前笔记,并关闭当前Activity - builder.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - deleteCurrentNote(); - finish(); - } - }); - // 设置对话框的取消按钮(点击取消删除的操作),传入安卓系统默认的取消按钮文字(android.R.string.cancel)作为按钮文本,这里没有设置点击事件监听器,默认点击取消按钮则对话框关闭,不执行删除操作 - builder.setNegativeButton(android.R.string.cancel, null); - // 显示构建好的对话框,让用户确认是否删除笔记 - builder.show(); - break; - case R.id.menu_font_size: - // 如果点击的是字体大小菜单项(R.id.menu_font_size) - // 将字体大小选择器视图设置为可见,显示出字体大小选择相关的界面 - mFontSizeSelector.setVisibility(View.VISIBLE); - // 根据当前选中的字体大小资源ID,找到对应的字体大小选中状态显示控件,并将其设置为可见,突出显示当前选中的字体大小 - findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); - break; - case R.id.menu_list_mode: - // 如果点击的是清单模式切换菜单项(R.id.menu_list_mode) - // 切换笔记的清单模式状态,通过判断当前的清单模式是否为0(表示非清单模式),如果是则设置为清单模式(TextNote.MODE_CHECK_LIST),否则设置为非清单模式(0) - mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0? - TextNote.MODE_CHECK_LIST : 0); - break; - case R.id.menu_share: - // 如果点击的是分享菜单项(R.id.menu_share) - // 调用getWorkingText方法获取当前笔记的文本内容(会根据清单模式下的勾选情况等进行相应处理) - getWorkingText(); - // 调用sendTo方法分享笔记内容,传入当前上下文和笔记内容字符串,通过Intent.ACTION_SEND意图启动可以接收分享文本的应用进行分享 - sendTo(this, mWorkingNote.getContent()); - break; - case R.id.menu_send_to_desktop: - // 如果点击的是发送到桌面菜单项(R.id.menu_send_to_desktop) - sendToDesktop(); - break; - case R.id.menu_alert: - // 如果点击的是设置提醒菜单项(R.id.menu_alert) - setReminder(); - break; - case R.id.menu_delete_remind: - // 如果点击的是删除提醒菜单项(R.id.menu_delete_remind) - // 将笔记的提醒日期设置为0(表示取消提醒),并传入false表示是取消提醒操作,不是设置提醒操作 - mWorkingNote.setAlertDate(0, false); - break; - default: - break; - } - return true; - } - - // 用于设置笔记的提醒功能,弹出一个时间选择对话框(DateTimePickerDialog)让用户选择提醒的时间日期 - 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 - */ - // 用于分享笔记内容到支持Intent.ACTION_SEND动作且能处理text/plain类型数据的应用(如短信、邮件、社交应用等) - 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); - } - - // 用于创建一个新的笔记,操作流程为先保存当前正在编辑的笔记,然后关闭当前Activity,再启动一个新的NoteEditActivity用于创建新笔记,传入当前笔记的文件夹ID等相关参数 - private void createNewNote() { - // 首先,调用saveNote方法保存当前编辑的笔记内容 - saveNote(); - - // 为了安全和确保状态正确,关闭当前的NoteEditActivity - finish(); - Intent intent = new Intent(this, NoteEditActivity.class); - intent.setAction(Intent.ACTION_INSERT_OR_EDIT); - intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); - startActivity(intent); - } - - // 用于删除当前正在编辑的笔记,根据笔记是否存在于数据库以及是否处于同步模式等情况进行不同的删除或移动到回收站操作,同时标记笔记为已删除状态 - private void deleteCurrentNote() { - if (mWorkingNote.existInDatabase()) { - HashSet ids = new HashSet(); - long id = mWorkingNote.getNoteId(); - if (id!= Notes.ID_ROOT_FOLDER) { - ids.add(id); - } else { - Log.d(TAG, "Wrong note id, should not happen"); - } - if (!isSyncMode()) { - if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) { - Log.e(TAG, "Delete Note error"); - } - } else { - if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) { - Log.e(TAG, "Move notes to trash folder error, should not happens"); - } - } - } - mWorkingNote.markDeleted(true); - } - - // 判断当前是否处于同步模式,通过获取NotesPreferenceActivity中存储的同步账号名称(去除首尾空格后判断长度是否大于0)来确定是否有同步账号设置,进而判断是否处于同步模式 - private boolean isSyncMode() { - return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; - } - - public void onClockAlertChanged(long date, boolean set) { - /** - * User could set clock to an unsaved note, so before setting the - * alert clock, we should save the note first - */ - // 如果正在编辑的笔记不存在于数据库中(可能是新建还未保存的笔记),先调用saveNote方法保存笔记,因为设置提醒需要笔记已经保存有对应的ID等信息 - if (!mWorkingNote.existInDatabase()) { - saveNote(); - } - if (mWorkingNote.getNoteId() > 0) { - Intent intent = new Intent(this, AlarmReceiver.class); - intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId())); - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0); - AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE)); - showAlertHeader(); - if (!set) { - // 如果是取消提醒操作(set为false),则通过AlarmManager取消对应的待处理意图(PendingIntent),从而取消提醒设置 - alarmManager.cancel(pendingIntent); - } else { - // 如果是设置提醒操作(set为true),通过AlarmManager设置提醒,传入提醒时间(date)以及对应的待处理意图(PendingIntent),使用RTC_WAKEUP模式(在指定时间唤醒设备触发提醒,常用于闹钟类提醒) - alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); - } - } 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, "Clock alert setting error"); - showToast(R.string.error_note_empty_for_clock); - } - } - - public void onWidgetChanged() { - updateWidget(); - } - - public void onEditTextDelete(int index, String text) { - int childCount = mEditTextList.getChildCount(); - if (childCount == 1) { - return; - } - - for (int i = index + 1; i < childCount; i++) { - ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i - 1); - } - - mEditTextList.removeViewAt(index); - NoteEditText edit = null; - if (index == 0) { - edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( - R.id.et_edit_text); - } else { - edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( - R.id.et_edit_text); - } - int length = edit.length(); - edit.append(text); - edit.requestFocus(); - edit.setSelection(length); - } - - public void onEditTextEnter(int index, String text) { - /** - * Should not happen, check for debug - */ - if (index > mEditTextList.getChildCount()) { - Log.e(TAG, "Index out of mEditTextList boundrary, should not happen"); - } - - View view = getListItem(text, index); - mEditTextList.addView(view, index); - NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - edit.requestFocus(); - edit.setSelection(0); - for (int i = index + 1; i < mEditTextList.getChildCount(); i++) { - ((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text)) - .setIndex(i); - } - } - - // 用于将笔记内容切换为清单模式展示,会根据传入的文本内容进行分割处理,并创建对应的视图条目添加到mEditTextList线性布局中展示,同时隐藏普通的笔记编辑框,显示清单模式相关的布局 - private void switchToListMode(String text) { - // 先移除mEditTextList线性布局中已有的所有视图条目,准备重新添加根据新内容生成的条目 - mEditTextList.removeAllViews(); - // 根据换行符将传入的文本内容分割为多个字符串数组元素,每个元素代表清单模式下的一个条目内容 - String[] items = text.split("\n"); - int index = 0; - for (String item : items) { - if (!TextUtils.isEmpty(item)) { - // 对于每个非空的条目内容,调用getListItem方法创建对应的视图条目,并添加到mEditTextList线性布局中展示,同时更新索引值 - mEditTextList.addView(getListItem(item, index)); - index++; - } - } - // 添加一个空的视图条目到mEditTextList线性布局末尾,方便用户继续添加新的清单条目内容 - mEditTextList.addView(getListItem("", index)); - // 获取mEditTextList线性布局中最后一个视图条目的编辑文本控件(NoteEditText),并请求获取焦点,以便用户可以直接输入内容 - mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus(); - - // 隐藏普通的笔记编辑框(mNoteEditor),因为切换到清单模式后使用mEditTextList来展示内容了 - mNoteEditor.setVisibility(View.GONE); - // 显示mEditTextList线性布局,展示清单模式下的笔记内容条目 - mEditTextList.setVisibility(View.VISIBLE); - } - - // 根据传入的完整文本内容和用户查询字符串,返回一个包含高亮显示用户查询关键词(如果有查询字符串的话)的Spannable字符串对象,用于在界面上展示高亮显示搜索结果的笔记内容 - private Spannable getHighlightQueryResult(String fullText, String userQuery) { - SpannableString spannable = new SpannableString(fullText == null? "" : fullText); - if (!TextUtils.isEmpty(userQuery)) { - // 将用户查询字符串编译为正则表达式模式,用于后续在笔记内容中匹配查找关键词出现的位置 - mPattern = Pattern.compile(userQuery); - Matcher m = mPattern.matcher(fullText); - int start = 0; - while (m.find(start)) { - // 对于每个匹配到的关键词位置,设置一个BackgroundColorSpan背景色跨度,使用当前上下文获取对应的高亮颜色资源(R.color.user_query_highlight),将关键词所在位置的文本背景设置为高亮颜色,实现高亮显示效果 - spannable.setSpan( - new BackgroundColorSpan(this.getResources().getColor( - R.color.user_query_highlight)), m.start(), m.end(), - Spannable.SPAN_INCLUSIVE_EXCLUSIVE); - start = m.end(); - } - } - return spannable; - } - - // 根据传入的条目文本内容和索引值,创建一个用于在清单模式下展示笔记条目的视图,包含可勾选的CheckBox和编辑文本的NoteEditText等组件,并设置相关属性和监听器 - private View getListItem(String item, int index) { - // 通过LayoutInflater从当前上下文加载名为"note_edit_list_item"的布局文件,创建对应的视图对象 - View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null); - final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - // 根据当前选中的字体大小资源ID,设置编辑文本的NoteEditText的文本外观(字体大小等样式),通过TextAppearanceResources工具类获取对应的字体外观资源进行设置 - edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); - CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item)); - cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked) { - // 如果CheckBox被勾选,设置编辑文本的NoteEditText的画笔标志,添加删除线样式(Paint.STRIKE_THRU_TEXT_FLAG),表示该条目已完成等相关状态(视觉上划掉已完成的内容) - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - } else { - // 如果CheckBox取消勾选,设置编辑文本的NoteEditText的画笔标志为默认的抗锯齿和字距调整样式,恢复正常文本显示外观 - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - } - } - }); - - if (item.startsWith(TAG_CHECKED)) { - cb.setChecked(true); - edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); - item = item.substring(TAG_CHECKED.length(), item.length()).trim(); - } else if (item.startsWith(TAG_UNCHECKED)) { - cb.setChecked(false); - edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); - item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); - } - - edit.setOnTextViewChangeListener(this); - edit.setIndex(index); - edit.setText(getHighlightQueryResult(item, mUserQuery)); - return view; - } - - public void onTextChange(int index, boolean hasText) { - if (index >= mEditTextList.getChildCount()) { - Log.e(TAG, "Wrong index, should not happen"); - return; - } - if (hasText) { - // 如果对应索引位置的条目有文本内容,将该条目对应的CheckBox设置为可见,用于显示勾选状态等相关操作 - mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE); - } else { - // 如果对应索引位置的条目没有文本内容,将该条目对应的CheckBox设置为不可见,隐藏勾选相关的控件显示 - mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.GONE); - } - } - - public void onCheckListModeChanged(int oldMode, int newMode) { - if (newMode == TextNote.MODE_CHECK_LIST) { - // 如果切换为清单模式,调用switchToListMode方法将笔记内容切换为清单模式展示,传入笔记编辑框中的文本内容字符串进行相应处理和界面更新 - switchToListMode(mNoteEditor.getText().toString()); - } else { - // 如果切换为非清单模式 - if (!getWorkingText()) { - // 如果获取当前笔记工作文本(通过getWorkingText方法,会根据清单模式下的勾选情况等整理文本内容)失败(返回false,表示可能没有有效内容等情况) - // 将笔记的工作文本设置为去除未勾选标记(TAG_UNCHECKED + " ")后的原始内容,进行简单的文本清理和转换 - mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", - "")); - } - // 获取包含高亮显示用户查询关键词(如果有查询字符串的话)的笔记内容,并设置到笔记编辑框中显示,同时将光标定位到文本末尾 - mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery)); - // 隐藏mEditTextList线性布局(清单模式相关的布局),因为切换到非清单模式后使用普通笔记编辑框展示内容了 - mEditTextList.setVisibility(View.GONE); - // 显示普通的笔记编辑框(mNoteEditor),展示非清单模式下的笔记内容 - mNoteEditor.setVisibility(View.VISIBLE); - } - } - - // 用于获取当前笔记的工作文本内容,根据笔记是否处于清单模式进行不同的处理,整理出包含勾选状态标记等合适的文本内容,并返回是否存在已勾选的条目 - private boolean getWorkingText() { - boolean hasChecked = false; - if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < mEditTextList.getChildCount(); i++) { - View view = mEditTextList.getChildAt(i); - NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text); - if (!TextUtils.isEmpty(edit.getText())) { - if (((CheckBox) view.findViewById(R.id.cb_edit_item)).isChecked()) { - sb.append(TAG_CHECKED).append(" ").append(edit.getText()).append("\n"); - hasChecked = true; - } else { - sb.append(TAG_UNCHECKED).append(" ").append(edit.getText()).append("\n"); - } - } - } - mWorkingNote.setWorkingText(sb.toString()); - } else { - mWorkingNote.setWorkingText(mNoteEditor.getText().toString()); - } - return hasChecked; - } - - // 用于保存当前正在编辑的笔记内容,先调用getWorkingText方法获取整理后的笔记文本内容,然后通过WorkingNote实例的saveNote方法进行实际的保存操作,返回值表示是否保存成功 - private boolean saveNote() { - getWorkingText(); - 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 - */ - setResult(RESULT_OK); - } - return saved; - } - - // 用于将当前笔记发送到桌面创建快捷方式,操作流程为先确保笔记已保存(如果是新建未保存的笔记则先保存),然后构建一个发送广播的Intent,设置相关的快捷方式信息(如名称、图标、启动意图等),最后发送广播通知系统创建快捷方式 - 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); - } - } - - // 用于生成适合作为桌面快捷方式图标的标题文本,会去除笔记内容中的勾选标记(TAG_CHECKED和TAG_UNCHECKED),然后根据最大长度限制截取合适长度的文本内容作为标题 - 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; - } - - // 用于显示一个Toast提示信息,使用默认的短显示时长(Toast.LENGTH_SHORT),传入对应的字符串资源ID来获取要显示的提示文字内容 - private void showToast(int resId) { - showToast(resId, Toast.LENGTH_SHORT); - } - - // 根据传入的字符串资源ID和显示时长参数,显示一个Toast提示信息,通过Toast.makeText方法创建Toast实例并传入当前上下文、资源ID和显示时长,最后调用show方法显示Toast - private void showToast(int resId, int duration) { - Toast.makeText(this, resId, duration).show(); - } -} \ No newline at end of file