/* * 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; public class NoteEditActivity extends Activity implements OnClickListener, NoteSettingChangedListener, OnTextViewChangeListener { //该类对标签的编辑 //继承系统中关于监听的类 private class HeadViewHolder { //创建一个私有类,用于界面设置 public TextView tvModified; public ImageView ivAlertIcon; public TextView tvAlertDate; public ImageView ibSetBgColor; //界面设置,包括文本,图片,背景,时间 } private static final Map sBgSelectorBtnsMap = new HashMap(); //使用Map实现数据的储存 static { //对HashMap的设置,颜色相对应链接 //put函数用来将指定的值与指定键相连 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); } private static final Map sBgSelectorSelectionMap = new HashMap(); //按钮与设置背景颜色的对应 static { //put函数用来将指定的值与指定键相连 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 sFontSizeBtnsMap = new HashMap(); //按钮与设置操作字体大小的对应 static { //put函数用来将指定的值与指定键相连 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); } //设置字体大小 private static final Map sFontSelectorSelectionMap = new HashMap(); //按钮与设置操作字体大小的对应 static { //put函数用来将指定的值与指定键相连 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); } //字体设置界面的大小设置 private static final String TAG = "NoteEditActivity"; //为本模块进行标签设置“NoteEditActivity" private HeadViewHolder mNoteHeaderHolder; private View mHeadViewPanel; //对表头操作 private View mNoteBgColorSelector; //背景颜色设置 private View mFontSizeSelector; //字体设置 private EditText mNoteEditor; //文本设置 private View mNoteEditorPanel; //文本编辑控制板 private WorkingNote mWorkingNote; //进行初始化 private SharedPreferences mSharedPrefs; //数据储存 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'); //字符串标记 private LinearLayout mEditTextList; //文本编辑,线性布局 private String mUserQuery; //用户请求 private Pattern mPattern; //正则表达式模式 @Override protected void onCreate(Bundle savedInstanceState) { //创建一个界面自定义操作 super.onCreate(savedInstanceState);//调用父类 this.setContentView(R.layout.note_edit);//视图的设置显示 if (savedInstanceState == null && !initActivityState(getIntent())) { finish();//结束activity return; } //判断传入参数是否为空,且对activity进行初始化是否成功 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); //调用父类函数,保存界面状态 if (savedInstanceState != null && savedInstanceState.containsKey(Intent.EXTRA_UID)) { Intent intent = new Intent(Intent.ACTION_VIEW);//新建Intent intent.putExtra(Intent.EXTRA_UID, savedInstanceState.getLong(Intent.EXTRA_UID)); //利用此前的extra_uid初始化一个intent if (!initActivityState(intent)) { finish(); return; } //初始化失败,就退出结束 Log.d(TAG, "Restoring from killed activity"); } //如果保存了关闭前的实例状态且其中包含着便签标识符,则将该标识符添加到初始化Activity的Intent中 } 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())) { long noteId = intent.getLongExtra(Intent.EXTRA_UID, 0); mUserQuery = ""; //如果用户实例化标签时,系统并未给出标签ID /** * Starting from the searched result */ if (intent.hasExtra(SearchManager.EXTRA_DATA_KEY)) { //根据键值查找ID noteId = Long.parseLong(intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); //获取便签ID mUserQuery = intent.getStringExtra(SearchManager.USER_QUERY); } if (!DataUtils.visibleInNoteDatabase(getContentResolver(), noteId, Notes.TYPE_NOTE)) { //如果ID数据库中没有找到 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); //使Edit界面适应软键盘弹出 } else if(TextUtils.equals(Intent.ACTION_INSERT_OR_EDIT, intent.getAction())) { //getAction获得字符串,判断intent,是否需要新建便签 // 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); //窗口ID int widgetType = intent.getIntExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, Notes.TYPE_WIDGET_INVALIDE); //widget的类型 int bgResId = intent.getIntExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, ResourceParser.getDefaultBgId(this)); //背景ID // Parse call-record note 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; if ((noteId = DataUtils.getNoteIdByPhoneNumberAndCallDate(getContentResolver(), phoneNumber, callDate)) > 0) { //根据电话号码和日期找到对应标识符,赋给noteId mWorkingNote = WorkingNote.load(this, noteId); //导入便签 if (mWorkingNote == null) { //mWorkingNote中空,报错警告 Log.e(TAG, "load call note failed with note id" + noteId); //警告 finish(); return false; } //若根据电话号码和通话时间未获取到便签id,则执行下面程序 } else { mWorkingNote = WorkingNote.createEmptyNote(this, folderId, widgetId, widgetType, bgResId); //没有找到noteId里的信息,创建一个新的便签并且初始化 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 { Log.e(TAG, "Intent not specified action, should not support"); //报错 finish(); return false; } mWorkingNote.setOnSettingStatusChangedListener(this); //监听器 return true; } @Override protected void onResume() { //重写Activity的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()) { //for循环遍历 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 { //没超过时,显示还有多久 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); }; //此时WorkingNote对象中不含提醒,则设置标题中相关提醒的控件为不可见 } @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()); //将便签的ID信息写入到intent的EXTRA_UID项中,便于之后恢复的时候调用 Log.d(TAG, "Save working note id: " + mWorkingNote.getNoteId()+"onSavelnstanceState"); //使用Log来保存信息 } @Override public boolean dispatchTouchEvent(MotionEvent ev) { //屏幕触摸反应 if (mNoteBgColorSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mNoteBgColorSelector, ev)) { //颜色背景选择界面可见且触摸范围在颜色选择范围外 mNoteBgColorSelector.setVisibility(View.GONE); //颜色选择器 return true; } if (mFontSizeSelector.getVisibility() == View.VISIBLE && !inRangeOfView(mFontSizeSelector, ev)) { //字体大小选择界面可见且触摸范围在字体大小选择范围外 mFontSizeSelector.setVisibility(View.GONE); return true; } return super.dispatchTouchEvent(ev); //调用父类 } private boolean inRangeOfView(View view, MotionEvent ev) { //对触控屏幕操作 int []location = new int[2]; //获取x-y位置 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; } private void initResources() { //初始化过程 mHeadViewPanel = findViewById(R.id.note_title); //找到标题栏 mNoteHeaderHolder = new HeadViewHolder(); //实例化HeadViewHolder,初始化 mNoteHeaderHolder.tvModified = (TextView) findViewById(R.id.tv_modified_date); //日期 mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); //闹钟提醒图标 mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); //提醒日期 mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); //设置背景颜色按钮 mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); //设置监听器 mNoteEditor = (EditText) findViewById(R.id.note_edit_view); //文本编辑初始化 mNoteEditorPanel = findViewById(R.id.sv_note_edit); //便签编辑器 mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); //便签背景选择 for (int id : sBgSelectorBtnsMap.keySet()) { ImageView iv = (ImageView) findViewById(id); iv.setOnClickListener(this); } //为背景颜色选择界面的每一个按钮设置相对应的资源文件,并且设置了点击事件监听器 mFontSizeSelector = findViewById(R.id.font_size_selector); //文字大小选择器 for (int id : sFontSizeBtnsMap.keySet()) { View view = findViewById(id); view.setOnClickListener(this); }; //为文字大小选择界面的每一个按钮设置相对应的资源文件,并且设置了点击事件监听器 mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); //默认大小字体 /** * HACKME: Fix bug of store the resource id in shared preference. * The id may larger than the length of resources, in this case, * return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE} */ if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { //字体大小大于最大时,设置为默认长度 mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; } mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); ////便签文本布局列表 } @Override protected void onPause() { super.onPause(); if(saveNote()) { //保存标签 Log.d(TAG, "Note data was saved with length:" + mWorkingNote.getContent().length()); //暂停时即进行便签的存储,记录log文件 } clearSettingState(); //清除状态设置 } private void updateWidget() { //同步桌面挂件 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); //实例化Intent,用来AppWidgetManager进行message传输 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不同的目的组件 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { //将桌面挂件的标识作为附加信息添加到Intent中 mWorkingNote.getWidgetId() //广播Intent }); sendBroadcast(intent); //发送出去 setResult(RESULT_OK, intent); //设置当前Activity结束后将结束信息发送给其父活动,回复相关有用的信息 } public void onClick(View v) { //点击并且执行 int id = v.getId(); if (id == R.id.btn_set_bg_color) { mNoteBgColorSelector.setVisibility(View.VISIBLE); findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); } else if (sBgSelectorBtnsMap.containsKey(id)) { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.GONE); mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); mNoteBgColorSelector.setVisibility(View.GONE); } else if (sFontSizeBtnsMap.containsKey(id)) { findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); mFontSizeId = sFontSizeBtnsMap.get(id); mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit(); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { getWorkingText(); switchToListMode(mWorkingNote.getContent()); } else { mNoteEditor.setTextAppearance(this, TextAppearanceResources.getTexAppearanceResource(mFontSizeId)); } mFontSizeSelector.setVisibility(View.GONE); } } @Override public void onBackPressed() { if(clearSettingState()) { return; } saveNote(); super.onBackPressed(); } private boolean clearSettingState() { if (mNoteBgColorSelector.getVisibility() == View.VISIBLE) { mNoteBgColorSelector.setVisibility(View.GONE); return true; } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { mFontSizeSelector.setVisibility(View.GONE); return true; } return false; } public void onBackgroundColorChanged() { findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( View.VISIBLE); mNoteEditorPanel.setBackgroundResource(mWorkingNote.getBgColorResId()); mHeadViewPanel.setBackgroundResource(mWorkingNote.getTitleBgResId()); } @Override public boolean onPrepareOptionsMenu(Menu menu) { if (isFinishing()) { return true; } clearSettingState(); menu.clear(); if (mWorkingNote.getFolderId() == Notes.ID_CALL_RECORD_FOLDER) { getMenuInflater().inflate(R.menu.call_note_edit, menu); //MenuInflater是用来实例化Menu目录下的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 /* * 函数功能:动态改变菜单选项内容 * 函数实现:如下注释 */ public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { //根据菜单的id来编剧相关项目 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)); // 设置标签的标题为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(); } }); //添加“YES”按钮 builder.setNegativeButton(android.R.string.cancel, null); //添加“NO”的按钮 builder.show(); //显示对话框 break; case R.id.menu_font_size: //字体大小的编辑 mFontSizeSelector.setVisibility(View.VISIBLE); // 将字体选择器置为可见 findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); // 通过id找到相应的大小 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()); // 用sendto函数将运行文本发送到遍历的本文内 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(); //显示对话框 } /** * 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链接选项 intent.putExtra(Intent.EXTRA_TEXT, info); //将需要传递的便签信息放入text文件中 intent.setType("text/plain"); //编辑连接器的类型 context.startActivity(intent); //在action中进行链接 } private void createNewNote() { // Firstly, save current editing notes //保存当前便签 saveNote(); // For safety, start a new NoteEditActivity finish(); Intent intent = new Intent(this, NoteEditActivity.class); //设置链接器 intent.setAction(Intent.ACTION_INSERT_OR_EDIT); //该活动定义为创建或编辑 intent.putExtra(Notes.INTENT_EXTRA_FOLDER_ID, mWorkingNote.getFolderId()); //将运行便签的id添加到INTENT_EXTRA_FOLDER_ID标记中 startActivity(intent); //开始activity并链接 } private void deleteCurrentNote() { if (mWorkingNote.existInDatabase()) { //假如当前运行的便签内存有数据 HashSet ids = new HashSet(); long id = mWorkingNote.getNoteId(); if (id != Notes.ID_ROOT_FOLDER) { ids.add(id); //如果不是头文件夹建立一个hash表把便签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); //将这些标签的删除标记置为true } 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 */ 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())); //若有有运行的便签就是建立一个链接器将标签id都存在uri中 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 { /** * 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(); } //Widget发生改变触发事件 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); } //用ID把编辑框存在便签编辑框中 mEditTextList.removeViewAt(index); //删除视图 NoteEditText edit = null; if(index == 0) { edit = (NoteEditText) mEditTextList.getChildAt(0).findViewById( R.id.et_edit_text); //如果原来编辑的索引值为0则编辑当前行,否则编辑上一行 } else { edit = (NoteEditText) mEditTextList.getChildAt(index - 1).findViewById( R.id.et_edit_text); //index不为0,则将edit定位到index-1对应的EditText项 } 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); } } //切换为列表模式 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); //建立一个状态机检查Pattern并进行匹配 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)); //实例化CheckBox组件,打勾 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); //true edit.setPaintFlags(edit.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG); item = item.substring(TAG_CHECKED.length(), item.length()).trim(); //去掉TAG_CHECKED和空格 } else if (item.startsWith(TAG_UNCHECKED)) { //不勾选 cb.setChecked(false); //false edit.setPaintFlags(Paint.ANTI_ALIAS_FLAG | Paint.DEV_KERN_TEXT_FLAG); item = item.substring(TAG_UNCHECKED.length(), item.length()).trim(); //去掉TAG_UNCHECKED和空格 } 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; //初始化check标记 if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { // 若模式为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; //扩展字符串为已打钩并把标记置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() { /** * Before send message to home, we should make sure that current * editing note is exists in databases. So, for new note, firstly * save it */ if (!mWorkingNote.existInDatabase()) { saveNote(); } if (mWorkingNote.getNoteId() > 0) { //如果有内容 Intent sender = new Intent(); Intent shortcutIntent = new Intent(this, NoteEditActivity.class); //建立发送到桌面的连接器 shortcutIntent.setAction(Intent.ACTION_VIEW); //创建视图,并连接 shortcutIntent.putExtra(Intent.EXTRA_UID, mWorkingNote.getNoteId()); sender.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); sender.putExtra(Intent.EXTRA_SHORTCUT_NAME, makeShortcutIconTitle(mWorkingNote.getContent())); sender.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(this, R.drawable.icon_app)); sender.putExtra("duplicate", true); sender.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); showToast(R.string.info_note_enter_desktop); sendBroadcast(sender); //在桌面显示 } else { /** * There is the condition that user has input nothing (the note is * not worthy saving), we have no note id, remind the user that he * should input something */ Log.e(TAG, "Send to desktop error"); showToast(R.string.error_note_empty_for_send_to_desktop); } //为空报错 } private String makeShortcutIconTitle(String content) { content = content.replace(TAG_CHECKED, ""); content = content.replace(TAG_UNCHECKED, ""); return content.length() > SHORTCUT_ICON_TITLE_MAX_LEN ? content.substring(0, SHORTCUT_ICON_TITLE_MAX_LEN) : content; }//编辑小图标标题 private void showToast(int resId) { showToast(resId, Toast.LENGTH_SHORT); }//显示提示视图 private void showToast(int resId, int duration) { Toast.makeText(this, resId, duration).show(); }//持续显示 }