You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
xiaomi-Notes/NoteEditActivity.java

1150 lines
52 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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;
// 导入 Android 标准库中的类
import android.app.Activity; // Activity 类,是所有 Android 应用的基本组件,表示单一屏幕的界面。
import android.app.AlarmManager; // AlarmManager 类,用于设置定时事件或闹钟。
import android.app.AlertDialog; // AlertDialog 类,用于显示对话框。
import android.app.PendingIntent; // PendingIntent 类,表示一个未来的 Intent 操作。
import android.app.SearchManager; // SearchManager 类,用于实现搜索功能。
import android.appwidget.AppWidgetManager; // AppWidgetManager 类,用于操作应用小部件。
import android.content.ContentUris; // ContentUris 类,用于构建和解析内容提供者的 URI。
import android.content.Context; // Context 类,提供应用环境信息,常用于访问系统服务。
import android.content.DialogInterface; // DialogInterface 类,处理对话框的交互事件。
import android.content.Intent; // Intent 类,用于启动活动或发送广播。
import android.content.SharedPreferences; // SharedPreferences 类,用于存储应用的首选项(键值对数据)。
import android.graphics.Paint; // Paint 类,用于设置文本或图形的样式和颜色。
import android.os.Bundle; // Bundle 类,用于在活动之间传递数据。
import android.preference.PreferenceManager; // PreferenceManager 类,用于访问 SharedPreferences。
import android.text.Spannable; // Spannable 接口,允许动态改变文本的格式。
import android.text.SpannableString; // SpannableString 类,实现了 Spannable 接口,用于设置可变的文本。
import android.text.TextUtils; // TextUtils 类,提供文本处理的工具方法。
import android.text.format.DateUtils; // DateUtils 类,提供格式化日期和时间的方法。
import android.text.style.BackgroundColorSpan; // BackgroundColorSpan 类,用于设置文本的背景颜色。
import android.util.Log; // Log 类,用于输出日志。
import android.view.LayoutInflater; // LayoutInflater 类,用于加载布局文件。
import android.view.Menu; // Menu 类,用于创建和处理应用菜单。
import android.view.MenuItem; // MenuItem 类,用于表示菜单项。
import android.view.MotionEvent; // MotionEvent 类,用于处理触摸事件。
import android.view.View; // View 类,所有 UI 组件的基类。
import android.view.View.OnClickListener; // OnClickListener 接口,用于处理点击事件。
import android.view.WindowManager; // WindowManager 类,用于管理窗口和显示。
import android.widget.CheckBox; // CheckBox 类,表示复选框。
import android.widget.CompoundButton; // CompoundButton 类,是一个开关类的父类,如 CheckBox 和 Switch。
import android.widget.CompoundButton.OnCheckedChangeListener; // OnCheckedChangeListener 接口,用于处理复选框状态变化事件。
import android.widget.EditText; // EditText 类,表示一个文本输入框。
import android.widget.ImageView; // ImageView 类,表示显示图片的控件。
import android.widget.LinearLayout; // LinearLayout 类,一种常用的布局管理器。
import android.widget.TextView; // TextView 类,用于显示文本。
import android.widget.Toast; // Toast 类,用于显示短暂的提示信息。
// 导入应用程序自定义的类
import net.micode.notes.R; // 应用资源类,用于访问应用中的资源文件。
import net.micode.notes.data.Notes; // Notes 类,可能用于表示笔记数据。
import net.micode.notes.data.Notes.TextNote; // TextNote 类,表示文本类型的笔记。
import net.micode.notes.model.WorkingNote; // WorkingNote 类,处理正在编辑的笔记的数据。
import net.micode.notes.model.WorkingNote.NoteSettingChangedListener; // NoteSettingChangedListener 接口,用于监听笔记设置的变化。
import net.micode.notes.tool.DataUtils; // DataUtils 类,提供与数据相关的工具方法。
import net.micode.notes.tool.ResourceParser; // ResourceParser 类,用于解析资源。
import net.micode.notes.tool.ResourceParser.TextAppearanceResources; // TextAppearanceResources 类,用于处理文本外观资源。
import net.micode.notes.ui.DateTimePickerDialog.OnDateTimeSetListener; // DateTimePickerDialog.OnDateTimeSetListener 接口,用于监听日期时间选择器的设置事件。
import net.micode.notes.ui.NoteEditText.OnTextViewChangeListener; // OnTextViewChangeListener 接口,用于监听文本框内容变化的事件。
import net.micode.notes.widget.NoteWidgetProvider_2x; // NoteWidgetProvider_2x 类表示2x大小的笔记小部件。
import net.micode.notes.widget.NoteWidgetProvider_4x; // NoteWidgetProvider_4x 类表示4x大小的笔记小部件。
// 导入 Java 标准库中的类
import java.util.HashMap; // HashMap 类,用于存储键值对。
import java.util.HashSet; // HashSet 类,用于存储唯一元素的集合。
import java.util.Map; // Map 接口,表示键值对映射。
import java.util.regex.Matcher; // Matcher 类,用于处理正则表达式的匹配。
import java.util.regex.Pattern; // Pattern 类,用于定义正则表达式模式。
// 定义 NoteEditActivity 类,继承自 Activity 类,且实现了三个接口
public class NoteEditActivity extends Activity implements OnClickListener,
NoteSettingChangedListener, OnTextViewChangeListener {
// 内部类HeadViewHolder用于存放活动页面中头部视图的组件如修改时间、提醒图标等
private class HeadViewHolder {
public TextView tvModified; // 显示修改时间的 TextView
public ImageView ivAlertIcon; // 显示提醒图标的 ImageView
public TextView tvAlertDate; // 显示提醒日期的 TextView
public ImageView ibSetBgColor; // 设置背景颜色的 ImageView
}
// 静态常量:存储背景颜色选择按钮与颜色资源之间的映射关系
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
static {
// 映射按钮 ID 到颜色资源(如黄色背景对应黄色资源)
sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW);
sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED);
sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE);
sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN);
sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE);
}
// 静态常量:存储颜色资源与对应选中状态按钮 ID 之间的映射关系
private static final Map<Integer, Integer> sBgSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
// 映射颜色资源到选中按钮 ID如黄色背景选中时显示黄色选中图标
sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select);
sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select);
sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select);
sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select);
sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select);
}
// 静态常量:存储字体大小选择按钮与字体大小资源之间的映射关系
private static final Map<Integer, Integer> sFontSizeBtnsMap = new HashMap<Integer, Integer>();
static {
// 映射字体大小选择按钮 ID 到字体大小资源(如大号字体对应大号字体资源)
sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE);
sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL);
sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM);
sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER);
}
// 静态常量:存储字体大小资源与对应选中状态按钮 ID 之间的映射关系
private static final Map<Integer, Integer> sFontSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
// 映射字体大小资源到选中按钮 ID如大号字体选中时显示大号选中图标
sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select);
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
}
// 定义 TAG 常量,用于日志调试时标记当前 Activity
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;
// 定义一个 WorkingNote 变量,用于存储当前正在编辑的笔记对象
private WorkingNote mWorkingNote;
// 定义 SharedPreferences 变量,用于存储和获取用户设置的首选项
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;
// 定义常量:表示复选框选中的符号
public static final String TAG_CHECKED = String.valueOf('\u221A');
// 定义常量:表示复选框未选中的符号
public static final String TAG_UNCHECKED = String.valueOf('\u25A1');
// 定义一个 LinearLayout 变量,用于存储编辑框列表的布局引用
private LinearLayout mEditTextList;
// 定义一个 String 变量,用于存储用户的查询文本
private String mUserQuery;
// 定义一个 Pattern 变量,用于存储正则表达式模式,用于匹配用户查询中的内容
private Pattern mPattern;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 设置当前 Activity 的布局
this.setContentView(R.layout.note_edit);
// 如果没有保存状态且初始化活动状态失败,则结束当前 Activity
if (savedInstanceState == null && !initActivityState(getIntent())) {
finish();
return;
}
// 初始化相关资源(如字体大小、背景色等)
initResources();
}
/**
* Current activity may be killed when the memory is low. Once it is killed, for another time
* user load this activity, we should restore the former state
*/
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); // 调用父类的 onRestoreInstanceState 方法
if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) {
// 如果 savedInstanceState 不为空且包含 EXTRA_UID 键
Intent intent = new Intent(Intent.ACTION_VIEW); // 创建一个 ACTION_VIEW 的 Intent 对象
intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); // 将 EXTRA_UID 从 Bundle 中取出并放入 Intent 中
if (!initActivityState(intent)) { // 使用 intent 初始化活动的状态
finish(); // 如果初始化失败,结束当前 Activity
return; // 退出方法
}
Log.d(TAG, "Restoring from killed activity"); // 日志输出,表示从被杀死的 Activity 中恢复
}
}
private boolean initActivityState(Intent intent) {
/**
* If the user specified the {@link Intent#ACTION_VIEW} but not provided with id,
* then jump to the NotesListActivity
*/
mWorkingNote = null;
if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) {
// 获取笔记ID如果没有提供ID则默认为0
long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0);
mUserQuery = "";// 用户的查询字符串
/**
* Starting from the searched result
*/
if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) {
noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY);
// 获取用户的查询字符串
}
// 检查笔记是否存在于数据库中
if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) {
// 如果笔记不存在跳转到NotesListActivity笔记列表页面
Intent jump = new Intent(this, NotesListActivity.class);
startActivity(jump);
showToast(R.string.error_note_not_exist); // 显示笔记不存在的提示
finish(); // 关闭当前活动
return false; // 返回false表示初始化失败
} else {
// 如果笔记存在,加载笔记
mWorkingNote = WorkingNote.load(this, noteId);
if (mWorkingNote == null) {
Log.e(TAG, "load note failed with note id" + noteId); // 如果加载失败,记录错误日志
finish(); // 关闭当前活动
return false; // 返回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的action是 ACTION_INSERT_OR_EDIT插入或编辑
// New note
long folderId = intent.getLongExtra(Notes.INTENT_EXTRA_FOLDER_ID, 0);
// 获取小部件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));
// Parse call-record note
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; // 返回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的action不在预期的类型中记录错误并关闭活动
Log.e(TAG, "Intent not specified action, should not support");
finish(); // 关闭当前活动
return false; // 返回false表示初始化失败
}
// 设置工作笔记的状态监听器
mWorkingNote.setOnSettingStatusChangedListener(this);
// 返回true表示初始化成功
return true;
}
@Override
protected void onResume() {
super.onResume();
// 在活动恢复时初始化笔记屏幕
initNoteScreen();
}
private void initNoteScreen() {
// 设置编辑器字体的样式,字体大小由 mFontSizeId 决定
mNoteEditor.setTextAppearance(this, TextAppearanceResources
.getTexAppearanceResource(mFontSizeId));
// 检查当前笔记是否是待办事项模式CheckList 模式)
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 {
// 否则显示相对时间例如1分钟之前3小时之前等
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);
}
};
// 当新 Intent 被传递进来时,重新初始化活动状态
@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) {
// 判断笔记背景色选择器mNoteBgColorSelector是否可见并且触摸事件是否发生在其区域外
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mNoteBgColorSelector, ev)) {
// 如果触摸事件发生在背景色选择器的区域外,则将其隐藏
mNoteBgColorSelector.setVisibility(View.GONE);
return true; // 返回true表示该事件已经被处理不再向下传递
}
// 判断字体大小选择器mFontSizeSelector是否可见并且触摸事件是否发生在其区域外
if (mFontSizeSelector.getVisibility() == View.VISIBLE
&& !inRangeOfView(mFontSizeSelector, ev)) {
// 如果触摸事件发生在字体大小选择器的区域外,则将其隐藏
mFontSizeSelector.setVisibility(View.GONE);
return true; // 返回true表示该事件已经被处理不再向下传递
}
// 如果上述两个条件都不满足,则交由父类处理触摸事件
return super.dispatchTouchEvent(ev);
}
/**
* 判断触摸事件是否发生在指定视图view区域内
* @param view 要判断的视图
* @param ev 触摸事件
* @return 如果触摸点在视图内返回true否则返回false
*/
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; // 触摸点在视图外部返回false
}
return true; // 触摸点在视图内部返回true
}
private void initResources() {
// 查找并初始化笔记标题视图
mHeadViewPanel = findViewById(R.id.note_title);
mNoteHeaderHolder = new HeadViewHolder();
// 初始化并绑定各个视图控件
mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); // 显示修改日期的TextView
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); // 显示提醒图标的ImageView
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); // 显示提醒日期的TextView
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); // 设置背景色的按钮ImageView
// 为设置背景色的按钮设置点击监听器
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
// 初始化笔记编辑区域的控件
mNoteEditor = (EditText) findViewById(R.id.note_edit_view); // 编辑笔记内容的EditText
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);
// 获取用户设置的字体大小ID如果没有设置则使用默认值
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; // 如果字体ID不合法则使用默认字体大小
}
// 初始化笔记编辑列表视图
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
}
// 重写 onPause 方法,在活动暂停时保存笔记并清除设置状态
@Override
protected void onPause() {
super.onPause();
// 调用 saveNote() 方法保存笔记内容,若保存成功,输出日志
if(saveNote()) {
Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length());
}
// 清除设置状态(例如背景色选择器和字体大小选择器等)
clearSettingState();
}
// 更新小部件的显示内容
private void updateWidget() {
// 创建一个 Intent 用于通知 AppWidgetManager 更新小部件
Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
// 根据当前笔记的 widget 类型,选择相应的小部件提供者类
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 {
// 如果遇到不支持的 widget 类型,输出错误日志并返回
Log.e(TAG, "Unspported widget type");
return;
}
// 将当前小部件的 ID 传递给小部件更新的 Intent
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {
mWorkingNote.getWidgetId()
});
// 发送广播通知更新小部件
sendBroadcast(intent);
// 设置结果为 RESULT_OK
setResult(RESULT_OK, intent);
}
// 处理点击事件,根据不同的按钮 ID 执行不同操作
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);
// 保存字体大小设置到 SharedPreferences 中
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);
}
}
// 重写 onBackPressed 方法,返回之前保存笔记或清除设置
@Override
public void onBackPressed() {
// 如果清除设置状态成功,则直接返回
if(clearSettingState()) {
return;
}
// 保存笔记数据
saveNote();
// 调用父类的 onBackPressed 方法
super.onBackPressed();
}
// 清除设置状态的方法,关闭背景色选择器或字体大小选择器
private boolean clearSettingState() {
// 如果背景色选择器可见,隐藏它并返回 true
if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) {
mNoteBgColorSelector.setVisibility(View.GONE);
return true;
// 如果字体大小选择器可见,隐藏它并返回 true
} else if (mFontSizeSelector.getVisibility() == View.VISIBLE) {
mFontSizeSelector.setVisibility(View.GONE);
return true;
}
// 如果都不可见,返回 false
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; // 如果 Activity 正在销毁,直接返回不做任何操作
}
clearSettingState(); // 清除设置状态(这个方法实现的细节不在代码中)
menu.clear(); // 清空当前菜单项
// 根据当前笔记的文件夹 ID 加载不同的菜单
if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) {
getMenuInflater().inflate(R.menu.call_note_edit, menu); // 如果是通话记录文件夹,加载 call_note_edit 菜单
} 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; // 返回 true表示菜单准备完毕
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_new_note: // 创建新笔记
createNewNote();
break;
case R.id.menu_delete: // 删除当前笔记
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.alert_title_delete)); // 设置弹窗标题
builder.setIcon(android.R.drawable.ic_dialog_alert); // 设置弹窗图标
builder.setMessage(getString(R.string.alert_message_delete_note)); // 设置弹窗消息内容
builder.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() { // 确定按钮
public void onClick(DialogInterface dialog, int which) {
deleteCurrentNote(); // 删除当前笔记
finish(); // 结束当前 Activity
}
});
builder.setNegativeButton(android.R.string.cancel, null); // 取消按钮
builder.show(); // 显示弹窗
break;
case R.id.menu_font_size: // 显示字体大小选择器
mFontSizeSelector.setVisibility(View.VISIBLE); // 显示字体大小选择器
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); // 根据当前字体大小显示对应选项
break;
case R.id.menu_list_mode: // 切换检查列表模式
mWorkingNote.setCheckListMode(mWorkingNote.getCheckListMode() == 0 ?
TextNote.MODE_CHECK_LIST : 0); // 切换检查列表模式状态
break;
case R.id.menu_share: // 分享当前笔记内容
getWorkingText(); // 获取当前笔记内容
sendTo(this, mWorkingNote.getContent()); // 将内容分享
break;
case R.id.menu_send_to_desktop: // 将笔记发送到桌面
sendToDesktop(); // 调用发送到桌面的方法
break;
case R.id.menu_alert: // 设置提醒
setReminder(); // 调用设置提醒的方法
break;
case R.id.menu_delete_remind: // 删除提醒
mWorkingNote.setAlertDate(0, false); // 清除提醒日期
break;
default:
break;
}
return true; // 返回 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 sendTo(Context context, String info) {
// 创建一个新的 Intent动作为发送数据 (ACTION_SEND)
Intent intent = new Intent(Intent.ACTION_SEND);
// 将要发送的文本信息放入 Intent 中
intent.putExtra(Intent.EXTRA_TEXT, info);
// 设置发送的数据类型为纯文本
intent.setType("text/plain");
// 启动一个新的活动,允许用户选择一个可以处理该 Intent 的应用(例如邮件、短信或社交媒体应用等)
context.startActivity(intent);
}
// Method to delete the current note from the database or move it to trash if in sync mode
private void deleteCurrentNote() {
// Check if the current note exists in the database
if (mWorkingNote.existInDatabase()) {
HashSet<Long> ids = new HashSet<Long>();
long id = mWorkingNote.getNoteId();
// Check if the note ID is not the root folder ID
if (id != Notes.ID_ROOT_FOLDER) {
ids.add(id); // Add the note ID to the set for deletion
} else {
Log.d(TAG, "Wrong note id, should not happen");
}
// If not in sync mode, delete the note from the database
if (!isSyncMode()) {
if (!DataUtils.batchDeleteNotes(getContentResolver(), ids)) {
Log.e(TAG, "Delete Note error");
}
} else {
// If in sync mode, move the note to the trash folder instead of deleting it
if (!DataUtils.batchMoveToFolder(getContentResolver(), ids, Notes.ID_TRASH_FOLER)) {
Log.e(TAG, "Move notes to trash folder error, should not happens");
}
}
}
// Mark the note as deleted (whether actually deleted or moved to trash)
mWorkingNote.markDeleted(true);
}
// Method to check if the app is in sync mode by checking the sync account name
private boolean isSyncMode() {
return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0;
}
// Method to handle changes to the clock alert for a note
public void onClockAlertChanged(long date, boolean set) {
// If the note doesn't exist in the database, save it before setting the clock alert
if (!mWorkingNote.existInDatabase()) {
saveNote();
}
// Ensure the note has a valid ID before setting the clock alert
if (mWorkingNote.getNoteId() > 0) {
Intent intent = new Intent(this, AlarmReceiver.class);
// Set the URI with the note ID to uniquely identify the note
intent.setData(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, mWorkingNote.getNoteId()));
// Create a PendingIntent to trigger the alarm when it's time
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0);
AlarmManager alarmManager = ((AlarmManager) getSystemService(ALARM_SERVICE));
showAlertHeader();
// If 'set' is true, schedule the alarm; otherwise, cancel the alarm
if (!set) {
alarmManager.cancel(pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent);
}
} else {
// If the note doesn't have an ID, display an error since the user has not input any content
Log.e(TAG, "Clock alert setting error");
showToast(R.string.error_note_empty_for_clock);
}
}
// Method to handle changes made to the widget, requiring a widget update
public void onWidgetChanged() {
updateWidget();
}
// Method to handle the deletion of text from the edit text
public void onEditTextDelete(int index, String text) {
int childCount = mEditTextList.getChildCount();
// If there is only one child, no need to delete anything
if (childCount == 1) {
return;
}
// Loop through the remaining child views to adjust their indices
for (int i = index + 1; i < childCount; i++) {
// Adjust the index of the text views after the deleted item
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i - 1);
}
// Remove the view at the specified index
mEditTextList.removeViewAt(index);
// Get the reference to the edit text after deletion
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);
}
// Append the text to the new edit text and set the cursor position
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 boundary, should not happen");
}
/**
* 根据输入的文本和索引,获取一个新的视图项
* getListItem() 方法应该根据索引和文本内容返回一个合适的视图通常是一个EditText组件
*/
View view = getListItem(text, index);
/**
* 将新创建的视图添加到 mEditTextList 中,指定其位置为 index
*/
mEditTextList.addView(view, index);
/**
* 获取视图中的 EditText 控件(假设它的 ID 是 et_edit_text
* 然后请求焦点,使其成为当前活动的输入框
*/
NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
edit.requestFocus();
/**
* 设置新获取的 EditText 控件的光标位置为 0即文本框的最前面
*/
edit.setSelection(0);
/**
* 遍历当前列表中,索引值大于当前插入位置的所有 EditText 控件
* 并将它们的索引值更新,确保它们在列表中的顺序正确
*/
for (int i = index + 1; i < mEditTextList.getChildCount(); i++) {
((NoteEditText) mEditTextList.getChildAt(i).findViewById(R.id.et_edit_text))
.setIndex(i);
}
}
// 切换到列表模式的函数
private void switchToListMode(String text) {
// 清空现有的视图
mEditTextList.removeAllViews();
// 将输入的文本按行分割成数组
String[] items = text.split("\n");
// 用于给每个项分配索引
int index = 0;
// 遍历分割后的每一项,如果该项不为空,则添加到视图中
for (String item : items) {
if(!TextUtils.isEmpty(item)) {
// 添加列表项视图
mEditTextList.addView(getListItem(item, index));
index++; // 索引递增
}
}
// 添加一个空白的列表项,通常用于空白行或末尾
mEditTextList.addView(getListItem("", index));
// 设置焦点到新添加的空白项
mEditTextList.getChildAt(index).findViewById(R.id.et_edit_text).requestFocus();
// 隐藏编辑器,显示列表
mNoteEditor.setVisibility(View.GONE);
mEditTextList.setVisibility(View.VISIBLE);
}
// 获取高亮显示查询结果的函数
private Spannable getHighlightQueryResult(String fullText, String userQuery) {
// 创建一个可编辑的字符串,用于高亮显示
SpannableString spannable = new SpannableString(fullText == null ? "" : fullText);
// 如果查询条件不为空,则进行高亮处理
if (!TextUtils.isEmpty(userQuery)) {
// 编译用户的查询模式
mPattern = Pattern.compile(userQuery);
Matcher m = mPattern.matcher(fullText);
int start = 0;
// 查找匹配的文本,逐一进行高亮处理
while (m.find(start)) {
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;
}
// 获取列表项视图的函数
private View getListItem(String item, int index) {
// 从布局中加载一个新的列表项视图
View view = LayoutInflater.from(this).inflate(R.layout.note_edit_list_item, null);
// 获取该视图中的编辑框控件
final NoteEditText edit = (NoteEditText) view.findViewById(R.id.et_edit_text);
// 设置文本样式
edit.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
// 获取复选框控件
CheckBox cb = ((CheckBox) view.findViewById(R.id.cb_edit_item));
cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
// 当复选框的选中状态发生变化时,修改文本的删除线效果
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
// 选中时加上删除线效果
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
// 未选中时去掉删除线
edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG);
}
}
});
// 判断列表项的状态,是否为已选中项
if (item.startsWith(TAG_CHECKED)) {
// 如果是已选中项,设置复选框为选中,并且加上删除线
cb.setChecked(true);
edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
// 移除标记,获取真实文本内容
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) {
mEditTextList.getChildAt(index).findViewById(R.id.cb_edit_item).setVisibility(View.VISIBLE);
} else {
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(mNoteEditor.getText().toString()); // 切换到列表模式
} else {
// 如果当前文本不为空,清除未选中的项
if (!getWorkingText()) {
mWorkingNote.setWorkingText(mWorkingNote.getContent().replace(TAG_UNCHECKED + " ", ""));
}
// 设置编辑器文本为高亮显示的查询结果
mNoteEditor.setText(getHighlightQueryResult(mWorkingNote.getContent(), mUserQuery));
mEditTextList.setVisibility(View.GONE); // 隐藏列表视图
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; // 返回是否有选中的项
}
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;
}
private void sendToDesktop() {
/**
* 在发送消息到桌面之前,我们需要确保当前正在编辑的笔记已存在于数据库中。
* 对于新笔记,首先需要保存它。
*/
if (!mWorkingNote.existInDatabase()) {
saveNote(); // 如果笔记不存在于数据库中,先保存笔记
}
// 确保笔记ID有效
if (mWorkingNote.getNoteId() > 0) {
Intent sender = new Intent(); // 创建一个Intent对象用于发送广播
Intent shortcutIntent = new Intent(this, NoteEditActivity.class); // 创建指向NoteEditActivity的Intent
shortcutIntent.setAction(Intent.ACTION_VIEW); // 设置Intent的动作为查看
shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); // 将当前笔记的ID传递给Intent
sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); // 将shortcutIntent作为快捷方式的Intent
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"); // 设置广播的action为安装快捷方式
showToast(R.string.info_note_enter_desktop); // 显示快捷方式添加到桌面的提示
sendBroadcast(sender); // 发送广播,通知系统添加快捷方式
} else {
/**
* 如果笔记为空即用户没有输入任何内容无法生成有效的笔记ID提醒用户
* 输入有效的内容以便创建快捷方式。
*/
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); // 简化的showToast调用使用短时间显示
}
private void showToast(int resId, int duration) {
Toast.makeText(this, resId, duration).show(); // 显示指定资源ID的Toast消息
}
}