/* * 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 { /** * 内部类 HeadViewHolder 用于存储笔记头部视图的引用。 */ private class HeadViewHolder { // 显示笔记修改日期的 TextView public TextView tvModified; // 提醒图标 ImageView public ImageView ivAlertIcon; // 显示提醒日期的 TextView public TextView tvAlertDate; // 设置背景颜色的按钮 ImageView public ImageView ibSetBgColor; } // 背景选择按钮与背景颜色资源 ID 的映射 private static final Map sBgSelectorBtnsMap = new HashMap(); static { // 将黄色背景选择按钮 ID 与黄色背景资源 ID 关联 sBgSelectorBtnsMap.put(R.id.iv_bg_yellow, ResourceParser.YELLOW); // 将红色背景选择按钮 ID 与红色背景资源 ID 关联 sBgSelectorBtnsMap.put(R.id.iv_bg_red, ResourceParser.RED); // 将蓝色背景选择按钮 ID 与蓝色背景资源 ID 关联 sBgSelectorBtnsMap.put(R.id.iv_bg_blue, ResourceParser.BLUE); // 将绿色背景选择按钮 ID 与绿色背景资源 ID 关联 sBgSelectorBtnsMap.put(R.id.iv_bg_green, ResourceParser.GREEN); // 将白色背景选择按钮 ID 与白色背景资源 ID 关联 sBgSelectorBtnsMap.put(R.id.iv_bg_white, ResourceParser.WHITE); } // 背景颜色资源 ID 与选中状态图标 ID 的映射 private static final Map sBgSelectorSelectionMap = new HashMap(); static { // 将黄色背景资源 ID 与黄色背景选中状态图标 ID 关联 sBgSelectorSelectionMap.put(ResourceParser.YELLOW, R.id.iv_bg_yellow_select); // 将红色背景资源 ID 与红色背景选中状态图标 ID 关联 sBgSelectorSelectionMap.put(ResourceParser.RED, R.id.iv_bg_red_select); // 将蓝色背景资源 ID 与蓝色背景选中状态图标 ID 关联 sBgSelectorSelectionMap.put(ResourceParser.BLUE, R.id.iv_bg_blue_select); // 将绿色背景资源 ID 与绿色背景选中状态图标 ID 关联 sBgSelectorSelectionMap.put(ResourceParser.GREEN, R.id.iv_bg_green_select); // 将白色背景资源 ID 与白色背景选中状态图标 ID 关联 sBgSelectorSelectionMap.put(ResourceParser.WHITE, R.id.iv_bg_white_select); } // 字体大小选择按钮与字体大小资源 ID 的映射 private static final Map sFontSizeBtnsMap = new HashMap(); static { // 将大字体选择按钮 ID 与大字体资源 ID 关联 sFontSizeBtnsMap.put(R.id.ll_font_large, ResourceParser.TEXT_LARGE); // 将小字体选择按钮 ID 与小字体资源 ID 关联 sFontSizeBtnsMap.put(R.id.ll_font_small, ResourceParser.TEXT_SMALL); // 将正常字体选择按钮 ID 与正常字体资源 ID 关联 sFontSizeBtnsMap.put(R.id.ll_font_normal, ResourceParser.TEXT_MEDIUM); // 将超大字体选择按钮 ID 与超大字体资源 ID 关联 sFontSizeBtnsMap.put(R.id.ll_font_super, ResourceParser.TEXT_SUPER); } // 字体大小资源 ID 与选中状态图标 ID 的映射 private static final Map sFontSelectorSelectionMap = new HashMap(); static { // 将大字体资源 ID 与大字体选中状态图标 ID 关联 sFontSelectorSelectionMap.put(ResourceParser.TEXT_LARGE, R.id.iv_large_select); // 将小字体资源 ID 与小字体选中状态图标 ID 关联 sFontSelectorSelectionMap.put(ResourceParser.TEXT_SMALL, R.id.iv_small_select); // 将正常字体资源 ID 与正常字体选中状态图标 ID 关联 sFontSelectorSelectionMap.put(ResourceParser.TEXT_MEDIUM, R.id.iv_medium_select); // 将超大字体资源 ID 与超大字体选中状态图标 ID 关联 sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); } // 日志标签 private static final String TAG = "NoteEditActivity"; // 笔记头部视图持有者 private HeadViewHolder mNoteHeaderHolder; // 笔记头部视图面板 private View mHeadViewPanel; // 笔记背景颜色选择器视图 private View mNoteBgColorSelector; // 字体大小选择器视图 private View mFontSizeSelector; // 笔记编辑器 EditText private EditText mNoteEditor; // 笔记编辑器面板视图 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; // 已勾选标记 public static final String TAG_CHECKED = String.valueOf('\u221A'); // 未勾选标记 public static final String TAG_UNCHECKED = String.valueOf('\u25A1'); // 编辑文本列表的 LinearLayout private LinearLayout mEditTextList; // 用户查询字符串 private String mUserQuery; // 正则表达式模式 private Pattern mPattern; /** * Activity 创建时调用的方法。 * 用于设置布局、初始化活动状态和资源。 * * @param savedInstanceState 保存的实例状态 */ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 设置布局 this.setContentView(R.layout.note_edit); // 如果 savedInstanceState 为空且初始化活动状态失败,则关闭活动 if (savedInstanceState == null && !initActivityState(getIntent())) { finish(); return; } // 初始化资源 initResources(); } /** * 恢复 Activity 状态时调用的方法。 * 当 Activity 因内存不足被杀死后重新启动时,恢复之前的状态。 * * @param savedInstanceState 保存的实例状态 */ @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); // 如果 savedInstanceState 不为空且包含 Intent.EXTRA_UID if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { // 创建一个新的 Intent 用于查看笔记 Intent intent = new Intent(Intent.ACTION_VIEW); // 将保存的笔记 ID 放入 Intent 中 intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); // 初始化活动状态,如果失败则关闭活动 if (!initActivityState(intent)) { finish(); return; } // 记录日志 Log.d(TAG, "Restoring from killed activity"); } } /** * 初始化活动状态的方法。 * 根据传入的 Intent 初始化工作笔记对象。 * * @param intent 传入的 Intent * @return 初始化成功返回 true,失败返回 false */ private boolean initActivityState(Intent intent) { // 初始化工作笔记对象为 null mWorkingNote = null; // 如果 Intent 的动作是 ACTION_VIEW if (TextUtils.equals(Intent.ACTION_VIEW, intent.getAction())) { // 获取笔记 ID long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); // 初始化用户查询字符串为空 mUserQuery = ""; // 如果 Intent 包含搜索结果相关信息 if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { // 从搜索结果中获取笔记 ID 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) { // 如果加载失败,记录错误日志并关闭活动 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 的动作是 ACTION_INSERT_OR_EDIT,创建新笔记 // 获取文件夹 ID 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)); // 解析通话记录笔记 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; // 根据电话号码和通话日期查找笔记 ID 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; } // 设置笔记设置状态改变监听器 mWorkingNote.setOnSettingStatusChangedListener(this); return true; } /** * Activity 恢复时调用的方法。 * 用于初始化笔记界面。 */ @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 { // 如果未超过提醒时间,显示相对提醒时间(如“10分钟后”) 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); } } /** * 当 Activity 接收到新的 Intent 时调用此方法。用于重新初始化活动状态。 * * @param intent 接收到的新 Intent */ @Override protected void onNewIntent(Intent intent) { // 调用父类的 onNewIntent 方法 super.onNewIntent(intent); // 初始化活动状态 initActivityState(intent); } /** * 在 Activity 被销毁前保存实例状态的方法。如果笔记是新创建且未保存到数据库,先保存笔记,然后将笔记 ID 保存到 Bundle 中。 * * @param outState 用于保存实例状态的 Bundle */ @Override protected void onSaveInstanceState(Bundle outState) { // 调用父类的 onSaveInstanceState 方法 super.onSaveInstanceState(outState); /** * 对于没有笔记 ID 的新笔记,我们应该先保存它以生成一个 ID。如果正在编辑的笔记不值得保存, * 则没有 ID,这相当于创建一个新笔记。 */ if (!mWorkingNote.existInDatabase()) { // 保存笔记 saveNote(); } // 将工作笔记的 ID 放入 outState 中 outState.putLong(Intent.EXTRA_UID, mWorkingNote.getNoteId()); // 记录日志,显示保存的工作笔记 ID Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId() + " onSaveInstanceState"); } /** * 分发触摸事件的方法。如果背景颜色选择器或字体大小选择器可见,且触摸事件不在其范围内,则隐藏选择器。 * * @param ev 触摸事件 * @return 如果处理了触摸事件返回 true,否则调用父类的 dispatchTouchEvent 方法 */ @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; } // 调用父类的 dispatchTouchEvent 方法处理触摸事件 return super.dispatchTouchEvent(ev); } /** * 判断触摸事件是否在指定视图范围内的方法。 * * @param view 要检查的视图 * @param ev 触摸事件 * @return 如果触摸事件在视图范围内返回 true,否则返回 false */ private boolean inRangeOfView(View view, MotionEvent ev) { // 用于存储视图在屏幕上的位置 int[] location = new int[2]; // 获取视图在屏幕上的位置 view.getLocationOnScreen(location); // 获取视图的 X 坐标 int x = location[0]; // 获取视图的 Y 坐标 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); // 遍历背景颜色选择按钮的 ID for (int id : sBgSelectorBtnsMap.keySet()) { // 查找背景颜色选择按钮 ImageView iv = (ImageView) findViewById(id); // 为背景颜色选择按钮设置点击监听器 iv.setOnClickListener(this); } // 查找并初始化字体大小选择器 mFontSizeSelector = findViewById(R.id.font_size_selector); // 遍历字体大小选择按钮的 ID 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); /** * 修复在共享偏好设置中存储资源 ID 的 bug。如果 ID 大于资源数组的长度, * 则返回默认的字体大小 ID。 */ if (mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } // 查找并初始化编辑文本列表 mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); } /** * Activity 暂停时调用的方法。保存笔记数据,并清除设置状态。 */ @Override protected void onPause() { // 调用父类的 onPause 方法 super.onPause(); // 保存笔记,如果保存成功则记录日志 if (saveNote()) { Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); } // 清除设置状态 clearSettingState(); } /** * 更新小部件的方法。根据笔记的小部件类型,发送广播更新相应的小部件。 */ private void updateWidget() { // 创建一个用于更新小部件的 Intent Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); // 检查笔记的小部件类型是否为 2x if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_2X) { // 设置 Intent 的目标类为 2x 小部件提供者 intent.setClass(this, NoteWidgetProvider_2x.class); } else if (mWorkingNote.getWidgetType() == Notes.TYPE_WIDGET_4X) { // 设置 Intent 的目标类为 4x 小部件提供者 intent.setClass(this, NoteWidgetProvider_4x.class); } else { // 如果是不支持的小部件类型,记录错误日志并返回 Log.e(TAG, "Unspported widget type"); return; } // 将笔记的小部件 ID 放入 Intent 中 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{ mWorkingNote.getWidgetId() }); // 发送广播更新小部件 sendBroadcast(intent); // 设置 Activity 的结果为成功 setResult(RESULT_OK, intent); } /** * 处理视图点击事件的方法。根据点击的视图 ID,执行相应的操作,如显示背景颜色选择器、设置背景颜色、设置字体大小等。 * * @param v 被点击的视图 */ public void onClick(View v) { // 获取被点击视图的 ID 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); // 设置工作笔记的背景颜色 ID mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); // 隐藏背景颜色选择器 mNoteBgColorSelector.setVisibility(View.GONE); } else if (sFontSizeBtnsMap.containsKey(id)) { // 如果点击的是字体大小选择按钮 // 隐藏当前选中的字体大小的选中标记 findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); // 更新字体大小 ID mFontSizeId = sFontSizeBtnsMap.get(id); // 将新的字体大小 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(); // 调用父类的 onBackPressed 方法处理返回操作 super.onBackPressed(); } /** * 清除设置状态的方法。如果背景颜色选择器或字体大小选择器可见,则隐藏它们并返回 true;否则返回 false。 * * @return 如果清除了设置状态返回 true,否则返回 false */ 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()); } /** * 准备选项菜单的方法。在菜单显示之前,清除设置状态,根据笔记的文件夹 ID 加载不同的菜单布局, * 并根据笔记的检查列表模式和提醒状态设置菜单项的标题和可见性。 * * @param menu 要准备的菜单 * @return 如果 Activity 正在结束返回 true,否则返回父类的 onPrepareOptionsMenu 方法的结果 */ @Override public boolean onPrepareOptionsMenu(Menu menu) { // 检查 Activity 是否正在结束 if (isFinishing()) { return true; } // 清除设置状态 clearSettingState(); // 清除菜单中的所有菜单项 menu.clear(); // 检查笔记的文件夹 ID 是否为通话记录文件夹 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; } @Override /** * 处理选项菜单中菜单项的点击事件 * * @param item 被点击的菜单项 * @return 如果事件已处理则返回 true */ 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(); } }); // 设置取消按钮,点击后不做任何操作 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; } /** * 设置提醒的方法,弹出日期时间选择对话框 */ 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(); } /** * 将笔记内容分享到支持文本分享的应用 * * @param context 上下文对象 * @param info 要分享的笔记内容 */ 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() { // 首先保存当前正在编辑的笔记 saveNote(); // 为了安全起见,关闭当前活动 finish(); // 创建一个新的笔记编辑活动意图 Intent intent = new Intent(this, NoteEditActivity.class); // 设置意图动作为插入或编辑 intent.setAction(Intent.ACTION_INSERT_OR_EDIT); // 传递当前笔记所在文件夹的 ID intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); // 启动新的笔记编辑活动 startActivity(intent); } /** * 删除当前笔记的方法 */ private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { // 创建一个存储笔记 ID 的集合 HashSet ids = new HashSet(); // 获取当前笔记的 ID long id = mWorkingNote.getNoteId(); if (id != Notes.ID_ROOT_FOLDER) { // 如果笔记 ID 不是根文件夹 ID,则将其添加到集合中 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); } /** * 判断是否处于同步模式 * * @return 如果有同步账户则返回 true,否则返回 false */ private boolean isSyncMode() { return NotesPreferenceActivity.getSyncAccountName(this).trim().length() > 0; } /** * 当笔记的提醒时钟设置发生变化时调用的方法 * * @param date 提醒日期 * @param set 是否设置提醒 */ public void onClockAlertChanged(long date, boolean set) { /** * 用户可能会对未保存的笔记设置时钟提醒,因此在设置提醒时钟之前,我们应该先保存笔记 */ if (!mWorkingNote.existInDatabase()) { saveNote(); } if (mWorkingNote.getNoteId() > 0) { // 创建一个广播意图,用于触发提醒 Intent intent = new Intent(this, AlarmReceiver.class); // 设置意图的数据为笔记的 URI 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) { // 如果取消提醒,取消闹钟 alarmManager.cancel(pendingIntent); } else { // 如果设置提醒,设置闹钟 alarmManager.set(AlarmManager.RTC_WAKEUP, date, pendingIntent); } } else { /** * 存在用户未输入任何内容(笔记不值得保存)的情况,此时没有笔记 ID,提醒用户应该输入一些内容 */ Log.e(TAG, "Clock alert setting error"); showToast(R.string.error_note_empty_for_clock); } } /** * 当笔记的小部件设置发生变化时调用的方法 */ public void onWidgetChanged() { // 更新小部件 updateWidget(); } /** * 当编辑文本被删除时调用的方法 * * @param index 被删除文本的索引 * @param text 被删除的文本内容 */ 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); } /** * 当在编辑文本中按下回车键时调用的方法 * * @param index 按下回车键的编辑文本的索引 * @param text 当前编辑文本的内容 */ public void onEditTextEnter(int index, String text) { /** * 这种情况不应该发生,用于调试检查 */ 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); } } /** * 切换到列表模式的方法 * * @param text 笔记内容 */ 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); } /** * 获取高亮显示查询结果的方法 * * @param fullText 完整的笔记内容 * @param userQuery 用户的查询关键字 * @return 高亮显示查询结果的 Spannable 对象 */ private Spannable getHighlightQueryResult(String fullText, String userQuery) { // 创建一个 SpannableString 对象,用于存储完整的笔记内容 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; } /** * 获取列表项视图的方法 * * @param item 列表项的内容 * @param index 列表项的索引 * @return 列表项视图 */ 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; } /** * 当编辑文本内容发生变化时调用的方法 * * @param index 编辑文本的索引 * @param hasText 编辑文本是否有内容 */ 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); } } /** * 当笔记的列表模式发生变化时调用的方法 * * @param oldMode 旧的列表模式 * @param newMode 新的列表模式 */ 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); } } /** * 获取当前工作文本,根据待办列表模式的不同进行处理 * @return 如果存在已选中的待办事项则返回 true,否则返回 false */ private boolean getWorkingText() { boolean hasChecked = false; // 如果当前处于待办列表模式 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { // 创建一个 StringBuilder 用于拼接待办事项 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; } /** * 保存当前笔记 * @return 如果保存成功则返回 true,否则返回 false */ private boolean saveNote() { // 获取当前工作文本 getWorkingText(); // 调用 WorkingNote 的 saveNote 方法保存笔记 boolean saved = mWorkingNote.saveNote(); if (saved) { /** * 从列表视图进入编辑视图有两种模式:打开一个笔记,创建/编辑一个笔记。 * 打开笔记需要在从编辑视图返回时回到列表中的原始位置,而创建新笔记需要回到列表顶部。 * 此代码 RESULT_OK 用于标识创建/编辑状态 */ setResult(RESULT_OK); } return saved; } /** * 将当前笔记发送到桌面,创建快捷方式 */ private void sendToDesktop() { /** * 在向主屏幕发送消息之前,需要确保当前编辑的笔记已经存在于数据库中。 * 因此,对于新笔记,首先保存它 */ if (!mWorkingNote.existInDatabase()) { saveNote(); } // 如果笔记 ID 大于 0,说明笔记已成功保存 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 { /** * 存在用户未输入任何内容的情况(笔记不值得保存),此时没有笔记 ID, * 提醒用户应该输入一些内容 */ Log.e(TAG, "Send to desktop error"); showToast(R.string.error_note_empty_for_send_to_desktop); } } /** * 生成快捷方式图标的标题,去除标记并截取长度 * @param content 笔记内容 * @return 生成的快捷方式图标标题 */ private String makeShortcutIconTitle(String content) { // 去除内容中的选中标记 content = content.replace(TAG_CHECKED, ""); // 去除内容中的未选中标记 content = content.replace(TAG_UNCHECKED, ""); // 如果内容长度超过最大长度,截取前 SHORTCUT_ICON_TITLE_MAX_LEN 个字符 return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; } /** * 显示短时间的 Toast 提示信息 * @param resId 提示信息的资源 ID */ private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); } /** * 显示指定时长的 Toast 提示信息 * @param resId 提示信息的资源 ID * @param duration Toast 显示的时长 */ private void showToast(int resId, int duration) { Toast.makeText(this, resId, duration).show(); } }