第二次提交

master
浮舟当歌 2 months ago
parent c0cd7d8628
commit 1c2f888347

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK"> <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">

@ -41,9 +41,12 @@ dependencies {
implementation(libs.appcompat) implementation(libs.appcompat)
implementation(libs.material) implementation(libs.material)
implementation(libs.constraintlayout) implementation(libs.constraintlayout)
implementation(files("D:\\Notesmaster2\\Notesmaster2\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar")) implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar"))
implementation(files("D:\\Notesmaster2\\Notesmaster2\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar")) implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar"))
implementation(files("D:\\Notesmaster2\\Notesmaster2\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar")) implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar"))
implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-osgi-4.5.14.jar"))
implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpclient-win-4.5.14.jar"))
implementation(files("D:\\pull\\qw-notes\\httpcomponents-client-4.5.14-bin\\lib\\httpcore-4.4.16.jar"))
testImplementation(libs.junit) testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.espresso.core)

@ -25,10 +25,19 @@ import android.util.Log;
import java.util.HashMap; import java.util.HashMap;
/**
* Contact访
*/
public class Contact { public class Contact {
// sContactCache用于缓存联系人信息以提高访问速度
private static HashMap<String, String> sContactCache; private static HashMap<String, String> sContactCache;
// TAG用于日志记录方便调试和追踪
private static final String TAG = "Contact"; private static final String TAG = "Contact";
/**
* CALLER_ID_SELECTIONSQL
* ID
*/
private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER private static final String CALLER_ID_SELECTION = "PHONE_NUMBERS_EQUAL(" + Phone.NUMBER
+ ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'" + ",?) AND " + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'"
+ " AND " + Data.RAW_CONTACT_ID + " IN " + " AND " + Data.RAW_CONTACT_ID + " IN "
@ -36,17 +45,32 @@ public class Contact {
+ " FROM phone_lookup" + " FROM phone_lookup"
+ " WHERE min_match = '+')"; + " WHERE min_match = '+')";
/**
*
*
*
*
* @param context 访
* @param phoneNumber
* @return null
*/
public static String getContact(Context context, String phoneNumber) { public static String getContact(Context context, String phoneNumber) {
// 检查缓存对象是否为空,如果为空则初始化
if(sContactCache == null) { if(sContactCache == null) {
sContactCache = new HashMap<String, String>(); sContactCache = new HashMap<String, String>();
} }
// 检查缓存中是否已有该电话号码对应的联系人名称
if(sContactCache.containsKey(phoneNumber)) { if(sContactCache.containsKey(phoneNumber)) {
return sContactCache.get(phoneNumber); return sContactCache.get(phoneNumber);
} }
// 准备查询条件对电话号码进行处理以匹配呼叫者ID的最小长度
String selection = CALLER_ID_SELECTION.replace("+", String selection = CALLER_ID_SELECTION.replace("+",
PhoneNumberUtils.toCallerIDMinMatch(phoneNumber)); PhoneNumberUtils.toCallerIDMinMatch(phoneNumber));
// 执行查询,尝试从系统联系人数据库中获取联系人名称
Cursor cursor = context.getContentResolver().query( Cursor cursor = context.getContentResolver().query(
Data.CONTENT_URI, Data.CONTENT_URI,
new String [] { Phone.DISPLAY_NAME }, new String [] { Phone.DISPLAY_NAME },
@ -54,6 +78,7 @@ public class Contact {
new String[] { phoneNumber }, new String[] { phoneNumber },
null); null);
// 处理查询结果,如果找到匹配的联系人则返回名称
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
try { try {
String name = cursor.getString(0); String name = cursor.getString(0);

@ -1,40 +1,55 @@
/* /*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * (c) 2010-2011, MiCode(www.micode.net)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Apache License 2.0
* 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.
*/ */
/**
*
* ContentProvider URI
*/
package net.micode.notes.data; package net.micode.notes.data;
import android.net.Uri; import android.net.Uri;
/**
*
*
* 1.
* 2.
* 3. URI
*/
public class Notes { public class Notes {
/** 内容提供器的授权标识 */
public static final String AUTHORITY = "micode_notes"; public static final String AUTHORITY = "micode_notes";
/** 日志标签 */
public static final String TAG = "Notes"; public static final String TAG = "Notes";
/**
*
* 0- 1- 2-
*/
public static final int TYPE_NOTE = 0; public static final int TYPE_NOTE = 0;
public static final int TYPE_FOLDER = 1; public static final int TYPE_FOLDER = 1;
public static final int TYPE_SYSTEM = 2; public static final int TYPE_SYSTEM = 2;
/** /**
* Following IDs are system folders' identifiers * ID
* {@link Notes#ID_ROOT_FOLDER } is default folder * 0-
* {@link Notes#ID_TEMPARAY_FOLDER } is for notes belonging no folder * -1-
* {@link Notes#ID_CALL_RECORD_FOLDER} is to store call records * -2-
* -3-
*/ */
public static final int ID_ROOT_FOLDER = 0; public static final int ID_ROOT_FOLDER = 0;
public static final int ID_TEMPARAY_FOLDER = -1; public static final int ID_TEMPARAY_FOLDER = -1;
public static final int ID_CALL_RECORD_FOLDER = -2; public static final int ID_CALL_RECORD_FOLDER = -2;
public static final int ID_TRASH_FOLER = -3; public static final int ID_TRASH_FOLER = -3;
/**
* Intent
*/
public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date"; public static final String INTENT_EXTRA_ALERT_DATE = "net.micode.notes.alert_date";
public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id"; public static final String INTENT_EXTRA_BACKGROUND_ID = "net.micode.notes.background_color_id";
public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id"; public static final String INTENT_EXTRA_WIDGET_ID = "net.micode.notes.widget_id";
@ -42,238 +57,161 @@ public class Notes {
public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id"; public static final String INTENT_EXTRA_FOLDER_ID = "net.micode.notes.folder_id";
public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date"; public static final String INTENT_EXTRA_CALL_DATE = "net.micode.notes.call_date";
/**
*
* -1- 0-2x 1-4x
*/
public static final int TYPE_WIDGET_INVALIDE = -1; public static final int TYPE_WIDGET_INVALIDE = -1;
public static final int TYPE_WIDGET_2X = 0; public static final int TYPE_WIDGET_2X = 0;
public static final int TYPE_WIDGET_4X = 1; public static final int TYPE_WIDGET_4X = 1;
/**
*
*/
public static class DataConstants { public static class DataConstants {
/** 普通文本笔记类型 */
public static final String NOTE = TextNote.CONTENT_ITEM_TYPE; public static final String NOTE = TextNote.CONTENT_ITEM_TYPE;
/** 通话记录笔记类型 */
public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE; public static final String CALL_NOTE = CallNote.CONTENT_ITEM_TYPE;
} }
/** /** 查询所有笔记和文件夹的URI */
* Uri to query all notes and folders
*/
public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note"); public static final Uri CONTENT_NOTE_URI = Uri.parse("content://" + AUTHORITY + "/note");
/** /** 查询笔记数据的URI */
* Uri to query data
*/
public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data"); public static final Uri CONTENT_DATA_URI = Uri.parse("content://" + AUTHORITY + "/data");
public interface NoteColumns {
/** /**
* The unique ID for a row *
* <P> Type: INTEGER (long) </P>
*/ */
public interface NoteColumns {
/** 主键ID */
public static final String ID = "_id"; public static final String ID = "_id";
/** /** 父文件夹ID */
* The parent's id for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String PARENT_ID = "parent_id"; public static final String PARENT_ID = "parent_id";
/** /** 创建时间戳 */
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String CREATED_DATE = "created_date"; public static final String CREATED_DATE = "created_date";
/** /** 最后修改时间 */
* Latest modified date
* <P> Type: INTEGER (long) </P>
*/
public static final String MODIFIED_DATE = "modified_date"; public static final String MODIFIED_DATE = "modified_date";
/** 提醒时间 */
/**
* Alert date
* <P> Type: INTEGER (long) </P>
*/
public static final String ALERTED_DATE = "alert_date"; public static final String ALERTED_DATE = "alert_date";
/** /** 内容摘要/文件夹名称 */
* Folder's name or text content of note
* <P> Type: TEXT </P>
*/
public static final String SNIPPET = "snippet"; public static final String SNIPPET = "snippet";
/** /** 关联的小部件ID */
* Note's widget id
* <P> Type: INTEGER (long) </P>
*/
public static final String WIDGET_ID = "widget_id"; public static final String WIDGET_ID = "widget_id";
/** /** 小部件类型 */
* Note's widget type
* <P> Type: INTEGER (long) </P>
*/
public static final String WIDGET_TYPE = "widget_type"; public static final String WIDGET_TYPE = "widget_type";
/** /** 背景色ID */
* Note's background color's id
* <P> Type: INTEGER (long) </P>
*/
public static final String BG_COLOR_ID = "bg_color_id"; public static final String BG_COLOR_ID = "bg_color_id";
/** /** 是否有附件标记 */
* For text note, it doesn't has attachment, for multi-media
* note, it has at least one attachment
* <P> Type: INTEGER </P>
*/
public static final String HAS_ATTACHMENT = "has_attachment"; public static final String HAS_ATTACHMENT = "has_attachment";
/** /** 文件夹内的笔记数量 */
* Folder's count of notes
* <P> Type: INTEGER (long) </P>
*/
public static final String NOTES_COUNT = "notes_count"; public static final String NOTES_COUNT = "notes_count";
/** /** 条目类型(笔记/文件夹) */
* The file type: folder or note
* <P> Type: INTEGER </P>
*/
public static final String TYPE = "type"; public static final String TYPE = "type";
/** /** 同步ID */
* The last sync id
* <P> Type: INTEGER (long) </P>
*/
public static final String SYNC_ID = "sync_id"; public static final String SYNC_ID = "sync_id";
/** /** 本地修改标记 */
* Sign to indicate local modified or not
* <P> Type: INTEGER </P>
*/
public static final String LOCAL_MODIFIED = "local_modified"; public static final String LOCAL_MODIFIED = "local_modified";
/** /** 原始父ID用于临时文件夹 */
* Original parent id before moving into temporary folder
* <P> Type : INTEGER </P>
*/
public static final String ORIGIN_PARENT_ID = "origin_parent_id"; public static final String ORIGIN_PARENT_ID = "origin_parent_id";
/** /** Google Tasks ID */
* The gtask id
* <P> Type : TEXT </P>
*/
public static final String GTASK_ID = "gtask_id"; public static final String GTASK_ID = "gtask_id";
/** /** 版本号 */
* The version code
* <P> Type : INTEGER (long) </P>
*/
public static final String VERSION = "version"; public static final String VERSION = "version";
} }
public interface DataColumns {
/** /**
* The unique ID for a row *
* <P> Type: INTEGER (long) </P>
*/ */
public interface DataColumns {
/** 主键ID */
public static final String ID = "_id"; public static final String ID = "_id";
/** /** MIME类型 */
* The MIME type of the item represented by this row.
* <P> Type: Text </P>
*/
public static final String MIME_TYPE = "mime_type"; public static final String MIME_TYPE = "mime_type";
/** /** 关联的笔记ID */
* The reference id to note that this data belongs to
* <P> Type: INTEGER (long) </P>
*/
public static final String NOTE_ID = "note_id"; public static final String NOTE_ID = "note_id";
/** /** 创建时间 */
* Created data for note or folder
* <P> Type: INTEGER (long) </P>
*/
public static final String CREATED_DATE = "created_date"; public static final String CREATED_DATE = "created_date";
/** /** 修改时间 */
* Latest modified date
* <P> Type: INTEGER (long) </P>
*/
public static final String MODIFIED_DATE = "modified_date"; public static final String MODIFIED_DATE = "modified_date";
/** /** 内容数据 */
* Data's content
* <P> Type: TEXT </P>
*/
public static final String CONTENT = "content"; public static final String CONTENT = "content";
/** 扩展数据字段1整数类型 */
/**
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA1 = "data1"; public static final String DATA1 = "data1";
/** /** 扩展数据字段2整数类型 */
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* integer data type
* <P> Type: INTEGER </P>
*/
public static final String DATA2 = "data2"; public static final String DATA2 = "data2";
/** /** 扩展数据字段3文本类型 */
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA3 = "data3"; public static final String DATA3 = "data3";
/** /** 扩展数据字段4文本类型 */
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA4 = "data4"; public static final String DATA4 = "data4";
/** /** 扩展数据字段5文本类型 */
* Generic data column, the meaning is {@link #MIMETYPE} specific, used for
* TEXT data type
* <P> Type: TEXT </P>
*/
public static final String DATA5 = "data5"; public static final String DATA5 = "data5";
} }
public static final class TextNote implements DataColumns {
/** /**
* Mode to indicate the text in check list mode or not *
* <P> Type: Integer 1:check list mode 0: normal mode </P>
*/ */
public static final class TextNote implements DataColumns {
/** 笔记模式1-清单模式 0-普通模式 */
public static final String MODE = DATA1; public static final String MODE = DATA1;
/** 清单模式常量 */
public static final int MODE_CHECK_LIST = 1; public static final int MODE_CHECK_LIST = 1;
/** 内容类型(目录) */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/text_note";
/** 内容项类型(单条) */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/text_note";
/** 文本笔记专用URI */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note"); public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/text_note");
} }
public static final class CallNote implements DataColumns {
/** /**
* Call date for this record *
* <P> Type: INTEGER (long) </P>
*/ */
public static final class CallNote implements DataColumns {
/** 通话日期使用DATA1字段存储 */
public static final String CALL_DATE = DATA1; public static final String CALL_DATE = DATA1;
/** /** 电话号码使用DATA3字段存储 */
* Phone number for this record
* <P> Type: TEXT </P>
*/
public static final String PHONE_NUMBER = DATA3; public static final String PHONE_NUMBER = DATA3;
/** 内容类型(目录) */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note"; public static final String CONTENT_TYPE = "vnd.android.cursor.dir/call_note";
/** 内容项类型(单条) */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note"; public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/call_note";
/** 通话笔记专用URI */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note"); public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/call_note");
} }
} }

@ -27,19 +27,29 @@ import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.NoteColumns;
/**
* SQLiteOpenHelper
*
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper { public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 数据库名称常量
private static final String DB_NAME = "note.db"; private static final String DB_NAME = "note.db";
// 数据库版本常量
private static final int DB_VERSION = 4; private static final int DB_VERSION = 4;
/**
*
*/
public interface TABLE { public interface TABLE {
// 笔记表名
public static final String NOTE = "note"; public static final String NOTE = "note";
// 数据表名
public static final String DATA = "data"; public static final String DATA = "data";
} }
// 日志标签
private static final String TAG = "NotesDatabaseHelper"; private static final String TAG = "NotesDatabaseHelper";
// 单例实例
private static NotesDatabaseHelper mInstance; private static NotesDatabaseHelper mInstance;
private static final String CREATE_NOTE_TABLE_SQL = private static final String CREATE_NOTE_TABLE_SQL =

@ -85,38 +85,58 @@ public class NotesProvider extends ContentProvider {
return true; return true;
} }
@Override /**
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, * Cursor
* URIID
*
* @param uri URI
* @param projection null
* @param selection WHEREWHEREnull
* @param selectionArgs selection"?"
* @param sortOrder null
* @return Cursornull
* @throws IllegalArgumentException URI
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) { String sortOrder) {
Cursor c = null; Cursor c = null;
SQLiteDatabase db = mHelper.getReadableDatabase(); SQLiteDatabase db = mHelper.getReadableDatabase();
String id = null; String id = null;
// 根据URI匹配类型执行不同的查询逻辑
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case URI_NOTE: case URI_NOTE:
// 查询整个NOTE表
c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null, c = db.query(TABLE.NOTE, projection, selection, selectionArgs, null, null,
sortOrder); sortOrder);
break; break;
case URI_NOTE_ITEM: case URI_NOTE_ITEM:
// 查询NOTE表中指定ID的记录
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id c = db.query(TABLE.NOTE, projection, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder); + parseSelection(selection), selectionArgs, null, null, sortOrder);
break; break;
case URI_DATA: case URI_DATA:
// 查询整个DATA表
c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null, c = db.query(TABLE.DATA, projection, selection, selectionArgs, null, null,
sortOrder); sortOrder);
break; break;
case URI_DATA_ITEM: case URI_DATA_ITEM:
// 查询DATA表中指定ID的记录
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id c = db.query(TABLE.DATA, projection, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs, null, null, sortOrder); + parseSelection(selection), selectionArgs, null, null, sortOrder);
break; break;
case URI_SEARCH: case URI_SEARCH:
case URI_SEARCH_SUGGEST: case URI_SEARCH_SUGGEST:
// 处理搜索查询,不允许指定排序或投影
if (sortOrder != null || projection != null) { if (sortOrder != null || projection != null) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"do not specify sortOrder, selection, selectionArgs, or projection" + "with this query"); "do not specify sortOrder, selection, selectionArgs, or projection" + "with this query");
} }
// 获取搜索字符串
String searchString = null; String searchString = null;
if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) { if (mMatcher.match(uri) == URI_SEARCH_SUGGEST) {
if (uri.getPathSegments().size() > 1) { if (uri.getPathSegments().size() > 1) {
@ -131,6 +151,7 @@ public class NotesProvider extends ContentProvider {
} }
try { try {
// 执行模糊搜索查询
searchString = String.format("%%%s%%", searchString); searchString = String.format("%%%s%%", searchString);
c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY, c = db.rawQuery(NOTES_SNIPPET_SEARCH_QUERY,
new String[] { searchString }); new String[] { searchString });
@ -141,63 +162,93 @@ public class NotesProvider extends ContentProvider {
default: default:
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// 设置Cursor的通知URI以便内容变化时能自动更新
if (c != null) { if (c != null) {
c.setNotificationUri(getContext().getContentResolver(), uri); c.setNotificationUri(getContext().getContentResolver(), uri);
} }
return c; return c;
} }
@Override
public Uri insert(Uri uri, ContentValues values) { /**
* URI
*
* URIURI
*
* @param uri URI
* @param values
* @return URIID
* @throws IllegalArgumentException URI
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
// 获取可写数据库实例
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
long dataId = 0, noteId = 0, insertedId = 0; long dataId = 0, noteId = 0, insertedId = 0;
// 根据URI类型执行不同的插入逻辑
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case URI_NOTE: case URI_NOTE:
// 插入笔记数据并获取新记录的ID
insertedId = noteId = db.insert(TABLE.NOTE, null, values); insertedId = noteId = db.insert(TABLE.NOTE, null, values);
break; break;
case URI_DATA: case URI_DATA:
// 检查并获取关联的笔记ID
if (values.containsKey(DataColumns.NOTE_ID)) { if (values.containsKey(DataColumns.NOTE_ID)) {
noteId = values.getAsLong(DataColumns.NOTE_ID); noteId = values.getAsLong(DataColumns.NOTE_ID);
} else { } else {
Log.d(TAG, "Wrong data format without note id:" + values.toString()); Log.d(TAG, "Wrong data format without note id:" + values.toString());
} }
// 插入数据记录并获取新记录的ID
insertedId = dataId = db.insert(TABLE.DATA, null, values); insertedId = dataId = db.insert(TABLE.DATA, null, values);
break; break;
default: default:
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// Notify the note uri
// 如果插入的是笔记或关联笔记的数据通知笔记URI的数据变更
if (noteId > 0) { if (noteId > 0) {
getContext().getContentResolver().notifyChange( getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null); ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null);
} }
// Notify the data uri // 如果插入的是数据记录通知数据URI的数据变更
if (dataId > 0) { if (dataId > 0) {
getContext().getContentResolver().notifyChange( getContext().getContentResolver().notifyChange(
ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null); ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null);
} }
// 返回新插入记录的完整URI
return ContentUris.withAppendedId(uri, insertedId); return ContentUris.withAppendedId(uri, insertedId);
} }
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) { /**
* URI
*
* @param uri URI
* @param selection SQL WHEREWHERE
* @param selectionArgs selection"?"
* @return int
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int count = 0; int count = 0;
String id = null; String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
boolean deleteData = false; boolean deleteData = false;
// 根据URI类型执行不同的删除操作
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case URI_NOTE: case URI_NOTE:
// 删除笔记记录并确保只删除ID大于0的记录系统文件夹不允许删除
selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 "; selection = "(" + selection + ") AND " + NoteColumns.ID + ">0 ";
count = db.delete(TABLE.NOTE, selection, selectionArgs); count = db.delete(TABLE.NOTE, selection, selectionArgs);
break; break;
case URI_NOTE_ITEM: case URI_NOTE_ITEM:
// 删除单个笔记项,同样需要检查是否为系统文件夹
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
/**
* ID that smaller than 0 is system folder which is not allowed to
* trash
*/
long noteId = Long.valueOf(id); long noteId = Long.valueOf(id);
if (noteId <= 0) { if (noteId <= 0) {
break; break;
@ -206,10 +257,12 @@ public class NotesProvider extends ContentProvider {
NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs); NoteColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
break; break;
case URI_DATA: case URI_DATA:
// 删除数据记录并标记需要通知笔记URI变更
count = db.delete(TABLE.DATA, selection, selectionArgs); count = db.delete(TABLE.DATA, selection, selectionArgs);
deleteData = true; deleteData = true;
break; break;
case URI_DATA_ITEM: case URI_DATA_ITEM:
// 删除单个数据项并标记需要通知笔记URI变更
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
count = db.delete(TABLE.DATA, count = db.delete(TABLE.DATA,
DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs); DataColumns.ID + "=" + id + parseSelection(selection), selectionArgs);
@ -218,37 +271,57 @@ public class NotesProvider extends ContentProvider {
default: default:
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// 如果有记录被删除,通知内容观察者更新
if (count > 0) { if (count > 0) {
if (deleteData) { if (deleteData) {
// 数据删除时需要额外通知笔记URI变更
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
} }
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
} }
return count; return count;
} }
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { /**
*
*
* @param uri URI
* @param values ContentValues
* @param selection WHEREnull
* @param selectionArgs WHEREnull
* @return
* @throws IllegalArgumentException URI
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int count = 0; int count = 0;
String id = null; String id = null;
SQLiteDatabase db = mHelper.getWritableDatabase(); SQLiteDatabase db = mHelper.getWritableDatabase();
boolean updateData = false; boolean updateData = false;
// 根据URI匹配不同的操作类型
switch (mMatcher.match(uri)) { switch (mMatcher.match(uri)) {
case URI_NOTE: case URI_NOTE:
// 更新笔记表的多条记录,并增加版本号
increaseNoteVersion(-1, selection, selectionArgs); increaseNoteVersion(-1, selection, selectionArgs);
count = db.update(TABLE.NOTE, values, selection, selectionArgs); count = db.update(TABLE.NOTE, values, selection, selectionArgs);
break; break;
case URI_NOTE_ITEM: case URI_NOTE_ITEM:
// 更新笔记表的单条记录,并增加版本号
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
increaseNoteVersion(Long.valueOf(id), selection, selectionArgs); increaseNoteVersion(Long.valueOf(id), selection, selectionArgs);
count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id count = db.update(TABLE.NOTE, values, NoteColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs); + parseSelection(selection), selectionArgs);
break; break;
case URI_DATA: case URI_DATA:
// 更新数据表的多条记录
count = db.update(TABLE.DATA, values, selection, selectionArgs); count = db.update(TABLE.DATA, values, selection, selectionArgs);
updateData = true; updateData = true;
break; break;
case URI_DATA_ITEM: case URI_DATA_ITEM:
// 更新数据表的单条记录
id = uri.getPathSegments().get(1); id = uri.getPathSegments().get(1);
count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id count = db.update(TABLE.DATA, values, DataColumns.ID + "=" + id
+ parseSelection(selection), selectionArgs); + parseSelection(selection), selectionArgs);
@ -258,20 +331,34 @@ public class NotesProvider extends ContentProvider {
throw new IllegalArgumentException("Unknown URI " + uri); throw new IllegalArgumentException("Unknown URI " + uri);
} }
// 如果有记录被更新,则通知内容观察者
if (count > 0) { if (count > 0) {
if (updateData) { if (updateData) {
// 更新数据表时需要额外通知笔记URI的变化
getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null); getContext().getContentResolver().notifyChange(Notes.CONTENT_NOTE_URI, null);
} }
getContext().getContentResolver().notifyChange(uri, null); getContext().getContentResolver().notifyChange(uri, null);
} }
return count; return count;
} }
private String parseSelection(String selection) { private String parseSelection(String selection) {
return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : ""); return (!TextUtils.isEmpty(selection) ? " AND (" + selection + ')' : "");
} }
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) { /**
*
*
* SQL UPDATE(VERSION)1
* ID
*
* @param id IDid <= 0使ID
* @param selection SQL WHERE(WHERE)?
* @param selectionArgs selection?
*/
private void increaseNoteVersion(long id, String selection, String[] selectionArgs) {
// 构建基础UPDATE语句设置版本号+1
StringBuilder sql = new StringBuilder(120); StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE "); sql.append("UPDATE ");
sql.append(TABLE.NOTE); sql.append(TABLE.NOTE);
@ -279,22 +366,30 @@ public class NotesProvider extends ContentProvider {
sql.append(NoteColumns.VERSION); sql.append(NoteColumns.VERSION);
sql.append("=" + NoteColumns.VERSION + "+1 "); sql.append("=" + NoteColumns.VERSION + "+1 ");
// 处理WHERE条件
if (id > 0 || !TextUtils.isEmpty(selection)) { if (id > 0 || !TextUtils.isEmpty(selection)) {
sql.append(" WHERE "); sql.append(" WHERE ");
} }
// 添加ID条件(如果id有效)
if (id > 0) { if (id > 0) {
sql.append(NoteColumns.ID + "=" + String.valueOf(id)); sql.append(NoteColumns.ID + "=" + String.valueOf(id));
} }
// 处理selection条件(如果存在)
if (!TextUtils.isEmpty(selection)) { if (!TextUtils.isEmpty(selection)) {
String selectString = id > 0 ? parseSelection(selection) : selection; String selectString = id > 0 ? parseSelection(selection) : selection;
// 替换selection中的占位符
for (String args : selectionArgs) { for (String args : selectionArgs) {
selectString = selectString.replaceFirst("\\?", args); selectString = selectString.replaceFirst("\\?", args);
} }
sql.append(selectString); sql.append(selectString);
} }
// 执行SQL语句
mHelper.getWritableDatabase().execSQL(sql.toString()); mHelper.getWritableDatabase().execSQL(sql.toString());
} }
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {

@ -25,11 +25,19 @@ import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
/**
* Task
*/
public class MetaData extends Task { public class MetaData extends Task {
private final static String TAG = MetaData.class.getSimpleName(); private final static String TAG = MetaData.class.getSimpleName();
private String mRelatedGid = null; private String mRelatedGid = null;
/**
*
* @param gid GTask ID
* @param metaInfo JSON
*/
public void setMeta(String gid, JSONObject metaInfo) { public void setMeta(String gid, JSONObject metaInfo) {
try { try {
metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid); metaInfo.put(GTaskStringUtils.META_HEAD_GTASK_ID, gid);
@ -40,20 +48,33 @@ public class MetaData extends Task {
setName(GTaskStringUtils.META_NOTE_NAME); setName(GTaskStringUtils.META_NOTE_NAME);
} }
/**
* GTask ID
* @return GTask ID
*/
public String getRelatedGid() { public String getRelatedGid() {
return mRelatedGid; return mRelatedGid;
} }
/**
*
* @return notesnulltruefalse
*/
@Override @Override
public boolean isWorthSaving() { public boolean isWorthSaving() {
return getNotes() != null; return getNotes() != null;
} }
/**
* JSON
* @param js JSON
*/
@Override @Override
public void setContentByRemoteJSON(JSONObject js) { public void setContentByRemoteJSON(JSONObject js) {
super.setContentByRemoteJSON(js); super.setContentByRemoteJSON(js);
if (getNotes() != null) { if (getNotes() != null) {
try { try {
// 解析notes字段中的JSON数据获取关联GTask ID
JSONObject metaInfo = new JSONObject(getNotes().trim()); JSONObject metaInfo = new JSONObject(getNotes().trim());
mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID); mRelatedGid = metaInfo.getString(GTaskStringUtils.META_HEAD_GTASK_ID);
} catch (JSONException e) { } catch (JSONException e) {
@ -63,17 +84,32 @@ public class MetaData extends Task {
} }
} }
/**
* JSON
* @param js JSON
* @throws IllegalAccessError
*/
@Override @Override
public void setContentByLocalJSON(JSONObject js) { public void setContentByLocalJSON(JSONObject js) {
// this function should not be called
throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called"); throw new IllegalAccessError("MetaData:setContentByLocalJSON should not be called");
} }
/**
* JSON
* @return
* @throws IllegalAccessError
*/
@Override @Override
public JSONObject getLocalJSONFromContent() { public JSONObject getLocalJSONFromContent() {
throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called"); throw new IllegalAccessError("MetaData:getLocalJSONFromContent should not be called");
} }
/**
*
* @param c
* @return
* @throws IllegalAccessError
*/
@Override @Override
public int getSyncAction(Cursor c) { public int getSyncAction(Cursor c) {
throw new IllegalAccessError("MetaData:getSyncAction should not be called"); throw new IllegalAccessError("MetaData:getSyncAction should not be called");

@ -34,15 +34,23 @@ import net.micode.notes.data.Notes.TextNote;
import java.util.ArrayList; import java.util.ArrayList;
/**
*
*/
public class Note { public class Note {
private ContentValues mNoteDiffValues; private ContentValues mNoteDiffValues;
private NoteData mNoteData; private NoteData mNoteData;
private static final String TAG = "Note"; private static final String TAG = "Note";
/** /**
* Create a new note id for adding a new note to databases * ID
* @param context
* @param folderId ID
* @return ID0
* @throws IllegalStateException noteId-1
*/ */
public static synchronized long getNewNoteId(Context context, long folderId) { public static synchronized long getNewNoteId(Context context, long folderId) {
// Create a new note in the database // 初始化笔记基本属性
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
long createdTime = System.currentTimeMillis(); long createdTime = System.currentTimeMillis();
values.put(NoteColumns.CREATED_DATE, createdTime); values.put(NoteColumns.CREATED_DATE, createdTime);
@ -50,8 +58,11 @@ public class Note {
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.LOCAL_MODIFIED, 1);
values.put(NoteColumns.PARENT_ID, folderId); values.put(NoteColumns.PARENT_ID, folderId);
// 插入数据库并获取URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
// 从URI解析笔记ID
long noteId = 0; long noteId = 0;
try { try {
noteId = Long.valueOf(uri.getPathSegments().get(1)); noteId = Long.valueOf(uri.getPathSegments().get(1));
@ -65,63 +76,101 @@ public class Note {
return noteId; return noteId;
} }
/**
*
*/
public Note() { public Note() {
mNoteDiffValues = new ContentValues(); mNoteDiffValues = new ContentValues();
mNoteData = new NoteData(); mNoteData = new NoteData();
} }
/**
*
* @param key
* @param value
*/
public void setNoteValue(String key, String value) { public void setNoteValue(String key, String value) {
mNoteDiffValues.put(key, value); mNoteDiffValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
} }
/**
*
* @param key
* @param value
*/
public void setTextData(String key, String value) { public void setTextData(String key, String value) {
mNoteData.setTextData(key, value); mNoteData.setTextData(key, value);
} }
/**
* ID
* @param id ID
*/
public void setTextDataId(long id) { public void setTextDataId(long id) {
mNoteData.setTextDataId(id); mNoteData.setTextDataId(id);
} }
/**
* ID
* @return ID
*/
public long getTextDataId() { public long getTextDataId() {
return mNoteData.mTextDataId; return mNoteData.mTextDataId;
} }
/**
* ID
* @param id ID
*/
public void setCallDataId(long id) { public void setCallDataId(long id) {
mNoteData.setCallDataId(id); mNoteData.setCallDataId(id);
} }
/**
*
* @param key
* @param value
*/
public void setCallData(String key, String value) { public void setCallData(String key, String value) {
mNoteData.setCallData(key, value); mNoteData.setCallData(key, value);
} }
/**
*
* @return truefalse
*/
public boolean isLocalModified() { public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
} }
/**
*
* @param context
* @param noteId ID
* @return truefalse
* @throws IllegalArgumentException noteId<=0
*/
public boolean syncNote(Context context, long noteId) { public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) { if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId); throw new IllegalArgumentException("Wrong note id:" + noteId);
} }
// 无修改则直接返回成功
if (!isLocalModified()) { if (!isLocalModified()) {
return true; return true;
} }
/** // 更新笔记基础信息
* In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and
* {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the
* note data info
*/
if (context.getContentResolver().update( if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) { null) == 0) {
Log.e(TAG, "Update note error, should not happen"); Log.e(TAG, "Update note error, should not happen");
// Do not return, fall through
} }
mNoteDiffValues.clear(); mNoteDiffValues.clear();
// 更新笔记内容数据
if (mNoteData.isLocalModified() if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) { && (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
return false; return false;
@ -130,17 +179,19 @@ public class Note {
return true; return true;
} }
/**
*
*/
private class NoteData { private class NoteData {
private long mTextDataId; private long mTextDataId;
private ContentValues mTextDataValues; private ContentValues mTextDataValues;
private long mCallDataId; private long mCallDataId;
private ContentValues mCallDataValues; private ContentValues mCallDataValues;
private static final String TAG = "NoteData"; private static final String TAG = "NoteData";
/**
*
*/
public NoteData() { public NoteData() {
mTextDataValues = new ContentValues(); mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues(); mCallDataValues = new ContentValues();
@ -148,10 +199,19 @@ public class Note {
mCallDataId = 0; mCallDataId = 0;
} }
/**
*
* @return truefalse
*/
boolean isLocalModified() { boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
} }
/**
* ID
* @param id ID
* @throws IllegalArgumentException id<=0
*/
void setTextDataId(long id) { void setTextDataId(long id) {
if(id <= 0) { if(id <= 0) {
throw new IllegalArgumentException("Text data id should larger than 0"); throw new IllegalArgumentException("Text data id should larger than 0");
@ -159,6 +219,11 @@ public class Note {
mTextDataId = id; mTextDataId = id;
} }
/**
* ID
* @param id ID
* @throws IllegalArgumentException id<=0
*/
void setCallDataId(long id) { void setCallDataId(long id) {
if (id <= 0) { if (id <= 0) {
throw new IllegalArgumentException("Call data id should larger than 0"); throw new IllegalArgumentException("Call data id should larger than 0");
@ -166,32 +231,48 @@ public class Note {
mCallDataId = id; mCallDataId = id;
} }
/**
*
* @param key
* @param value
*/
void setCallData(String key, String value) { void setCallData(String key, String value) {
mCallDataValues.put(key, value); mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
} }
/**
*
* @param key
* @param value
*/
void setTextData(String key, String value) { void setTextData(String key, String value) {
mTextDataValues.put(key, value); mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
} }
Uri pushIntoContentResolver(Context context, long noteId) {
/** /**
* Check for safety *
* @param context
* @param noteId ID
* @return URInull
* @throws IllegalArgumentException noteId<=0
*/ */
Uri pushIntoContentResolver(Context context, long noteId) {
if (noteId <= 0) { if (noteId <= 0) {
throw new IllegalArgumentException("Wrong note id:" + noteId); throw new IllegalArgumentException("Wrong note id:" + noteId);
} }
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<>();
ContentProviderOperation.Builder builder = null; ContentProviderOperation.Builder builder = null;
// 处理文本数据
if(mTextDataValues.size() > 0) { if(mTextDataValues.size() > 0) {
mTextDataValues.put(DataColumns.NOTE_ID, noteId); mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) { if (mTextDataId == 0) {
// 新文本数据则插入
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues); mTextDataValues);
@ -203,6 +284,7 @@ public class Note {
return null; return null;
} }
} else { } else {
// 已有文本数据则更新
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId)); Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues); builder.withValues(mTextDataValues);
@ -211,9 +293,11 @@ public class Note {
mTextDataValues.clear(); mTextDataValues.clear();
} }
// 处理通话数据
if(mCallDataValues.size() > 0) { if(mCallDataValues.size() > 0) {
mCallDataValues.put(DataColumns.NOTE_ID, noteId); mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) { if (mCallDataId == 0) {
// 新通话数据则插入
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues); mCallDataValues);
@ -225,6 +309,7 @@ public class Note {
return null; return null;
} }
} else { } else {
// 已有通话数据则更新
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId)); Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues); builder.withValues(mCallDataValues);
@ -233,16 +318,14 @@ public class Note {
mCallDataValues.clear(); mCallDataValues.clear();
} }
// 批量执行操作
if (operationList.size() > 0) { if (operationList.size() > 0) {
try { try {
ContentProviderResult[] results = context.getContentResolver().applyBatch( ContentProviderResult[] results = context.getContentResolver().applyBatch(
Notes.AUTHORITY, operationList); Notes.AUTHORITY, operationList);
return (results == null || results.length == 0 || results[0] == null) ? null return (results == null || results.length == 0 || results[0] == null) ? null
: ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId);
} catch (RemoteException e) { } catch (RemoteException | OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null;
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
return null; return null;
} }

@ -37,7 +37,15 @@ import java.util.HashSet;
public class DataUtils { public class DataUtils {
public static final String TAG = "DataUtils"; public static final String TAG = "DataUtils";
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) { /**
*
*
* @param resolver ContentResolver
* @param ids IDnull
* @return boolean true()false
*/
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
// 处理空参数情况
if (ids == null) { if (ids == null) {
Log.d(TAG, "the ids is null"); Log.d(TAG, "the ids is null");
return true; return true;
@ -47,8 +55,10 @@ public class DataUtils {
return true; return true;
} }
// 构建批量删除操作列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) { for (long id : ids) {
// 跳过系统根文件夹的删除
if(id == Notes.ID_ROOT_FOLDER) { if(id == Notes.ID_ROOT_FOLDER) {
Log.e(TAG, "Don't delete system folder root"); Log.e(TAG, "Don't delete system folder root");
continue; continue;
@ -57,6 +67,8 @@ public class DataUtils {
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id)); .newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
operationList.add(builder.build()); operationList.add(builder.build());
} }
// 执行批量删除操作
try { try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) { if (results == null || results.length == 0 || results[0] == null) {
@ -70,23 +82,46 @@ public class DataUtils {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} }
return false; return false;
} }
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
/**
*
*
* @param resolver ContentResolver
* @param id ID
* @param srcFolderId ID
* @param desFolderId ID
*/
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
// 创建ContentValues对象并设置笔记的新位置和修改状态
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(NoteColumns.PARENT_ID, desFolderId); values.put(NoteColumns.PARENT_ID, desFolderId);
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId); values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
values.put(NoteColumns.LOCAL_MODIFIED, 1); values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 更新笔记在数据库中的位置信息
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null); resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
} }
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids, /**
*
*
* @param resolver ContentResolver
* @param ids IDnull()
* @param folderId ID
* @return truefalse
*/
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
long folderId) { long folderId) {
// 处理空ID集合的特殊情况
if (ids == null) { if (ids == null) {
Log.d(TAG, "the ids is null"); Log.d(TAG, "the ids is null");
return true; return true;
} }
// 构建批量更新操作列表
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>(); ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
for (long id : ids) { for (long id : ids) {
ContentProviderOperation.Builder builder = ContentProviderOperation ContentProviderOperation.Builder builder = ContentProviderOperation
@ -96,6 +131,7 @@ public class DataUtils {
operationList.add(builder.build()); operationList.add(builder.build());
} }
// 执行批量操作并处理结果
try { try {
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList); ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
if (results == null || results.length == 0 || results[0] == null) { if (results == null || results.length == 0 || results[0] == null) {
@ -109,34 +145,52 @@ public class DataUtils {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} }
return false; return false;
} }
/** /**
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}} * Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
*/ */
// 定义一个静态方法,用于获取用户文件夹数量
public static int getUserFolderCount(ContentResolver resolver) { public static int getUserFolderCount(ContentResolver resolver) {
Cursor cursor =resolver.query(Notes.CONTENT_NOTE_URI, // 查询数据库,获取符合条件的记录数量
new String[] { "COUNT(*)" }, Cursor cursor = resolver.query(
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", Notes.CONTENT_NOTE_URI, // 要查询的URI内容提供者的地址
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)}, new String[] { "COUNT(*)" }, // 要返回的列,这里只返回计数结果
null); NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?", // 查询条件:类型为文件夹且不在回收站中
new String[] { // 查询条件的参数值
String.valueOf(Notes.TYPE_FOLDER), // 类型为文件夹
String.valueOf(Notes.ID_TRASH_FOLER) // 排除回收站中的文件夹
},
null // 排序方式,这里不需要排序
);
int count = 0; int count = 0; // 初始化计数器为0
if(cursor != null) { if(cursor != null) { // 检查Cursor对象是否有效
if(cursor.moveToFirst()) { if(cursor.moveToFirst()) { // 将游标移动到第一条记录
try { try {
count = cursor.getInt(0); count = cursor.getInt(0); // 获取第一列的值即COUNT(*)的结果)
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
// 如果发生数组越界异常,记录错误日志
Log.e(TAG, "get folder count failed:" + e.toString()); Log.e(TAG, "get folder count failed:" + e.toString());
} finally { } finally {
cursor.close(); cursor.close(); // 无论是否发生异常,都要关闭游标
} }
} }
} }
return count; return count; // 返回文件夹数量
} }
/**
*
*
* @param resolver ContentResolver
* @param noteId ID
* @param type
* @return boolean truefalse
*/
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
// 查询条件匹配指定笔记ID、指定类型且父ID不等于回收站文件夹ID
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null,
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
@ -145,6 +199,7 @@ public class DataUtils {
boolean exist = false; boolean exist = false;
if (cursor != null) { if (cursor != null) {
// 如果查询结果包含记录,则标记为存在
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
exist = true; exist = true;
} }
@ -153,12 +208,21 @@ public class DataUtils {
return exist; return exist;
} }
/**
* ID
*
* @param resolver
* @param noteId ID
* @return boolean truefalse
*/
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
// 构建URI并查询指定ID的笔记
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null); null, null, null, null);
boolean exist = false; boolean exist = false;
if (cursor != null) { if (cursor != null) {
// 如果查询结果包含记录,则标记为存在
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
exist = true; exist = true;
} }
@ -167,12 +231,21 @@ public class DataUtils {
return exist; return exist;
} }
/**
* ID
*
* @param resolver ContentResolver
* @param dataId ID
* @return boolean truefalse
*/
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
// 构建URI并查询指定ID的数据记录
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null); null, null, null, null);
boolean exist = false; boolean exist = false;
if (cursor != null) { if (cursor != null) {
// 如果查询结果包含记录,则标记为存在
if (cursor.getCount() > 0) { if (cursor.getCount() > 0) {
exist = true; exist = true;
} }
@ -181,13 +254,24 @@ public class DataUtils {
return exist; return exist;
} }
/**
*
*
* @param resolver ContentResolver
* @param name
* @return boolean - truefalse
*/
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
// 查询非回收站文件夹中是否存在指定名称的文件夹
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?", " AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null); new String[] { name }, null);
boolean exist = false; boolean exist = false;
// 处理查询结果
if(cursor != null) { if(cursor != null) {
if(cursor.getCount() > 0) { if(cursor.getCount() > 0) {
exist = true; exist = true;
@ -197,7 +281,15 @@ public class DataUtils {
return exist; return exist;
} }
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) { /**
*
*
* @param resolver ContentResolver
* @param folderId ID
* @return HashSet<AppWidgetAttribute> null
*/
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
// 查询指定文件夹下的所有笔记小部件数据
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
NoteColumns.PARENT_ID + "=?", NoteColumns.PARENT_ID + "=?",
@ -206,10 +298,12 @@ public class DataUtils {
HashSet<AppWidgetAttribute> set = null; HashSet<AppWidgetAttribute> set = null;
if (c != null) { if (c != null) {
// 如果查询结果不为空则遍历Cursor构建小部件属性集合
if (c.moveToFirst()) { if (c.moveToFirst()) {
set = new HashSet<AppWidgetAttribute>(); set = new HashSet<AppWidgetAttribute>();
do { do {
try { try {
// 从Cursor中读取小部件数据并创建属性对象
AppWidgetAttribute widget = new AppWidgetAttribute(); AppWidgetAttribute widget = new AppWidgetAttribute();
widget.widgetId = c.getInt(0); widget.widgetId = c.getInt(0);
widget.widgetType = c.getInt(1); widget.widgetType = c.getInt(1);
@ -222,17 +316,28 @@ public class DataUtils {
c.close(); c.close();
} }
return set; return set;
} }
/**
* ID
*
* @param resolver ContentResolver
* @param noteId ID
* @return
*/
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
// 查询条件指定noteId和mime类型为CallNote类型的数据
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.PHONE_NUMBER }, new String [] { CallNote.PHONE_NUMBER },
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
null); null);
// 处理查询结果
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
try { try {
// 返回第一行第一列的电话号码
return cursor.getString(0); return cursor.getString(0);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call number fails " + e.toString()); Log.e(TAG, "Get call number fails " + e.toString());
@ -243,7 +348,16 @@ public class DataUtils {
return ""; return "";
} }
/**
* 便ID
*
* @param resolver ContentResolver访
* @param phoneNumber 便
* @param callDate 便
* @return 便ID0
*/
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
// 查询条件通话日期、MIME类型和电话号码使用PHONE_NUMBERS_EQUAL函数比较
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
new String [] { CallNote.NOTE_ID }, new String [] { CallNote.NOTE_ID },
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
@ -251,9 +365,11 @@ public class DataUtils {
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
null); null);
// 处理查询结果
if (cursor != null) { if (cursor != null) {
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
try { try {
// 返回第一条记录的NOTE_ID
return cursor.getLong(0); return cursor.getLong(0);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
Log.e(TAG, "Get call note id fails " + e.toString()); Log.e(TAG, "Get call note id fails " + e.toString());
@ -264,7 +380,16 @@ public class DataUtils {
return 0; return 0;
} }
/**
* ID()
*
* @param resolver ContentResolver
* @param noteId ID
* @return ()
* @throws IllegalArgumentException ID
*/
public static String getSnippetById(ContentResolver resolver, long noteId) { public static String getSnippetById(ContentResolver resolver, long noteId) {
// 查询指定ID的笔记片段
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
new String [] { NoteColumns.SNIPPET }, new String [] { NoteColumns.SNIPPET },
NoteColumns.ID + "=?", NoteColumns.ID + "=?",
@ -273,6 +398,7 @@ public class DataUtils {
if (cursor != null) { if (cursor != null) {
String snippet = ""; String snippet = "";
// 如果查询到结果,获取第一条记录的片段内容
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
snippet = cursor.getString(0); snippet = cursor.getString(0);
} }
@ -282,9 +408,22 @@ public class DataUtils {
throw new IllegalArgumentException("Note is not found with id: " + noteId); throw new IllegalArgumentException("Note is not found with id: " + noteId);
} }
/**
*
*
*
* 1.
* 2.
*
* @param snippet null
* @return nullnull
*/
public static String getFormattedSnippet(String snippet) { public static String getFormattedSnippet(String snippet) {
if (snippet != null) { if (snippet != null) {
// 去除首尾空白字符
snippet = snippet.trim(); snippet = snippet.trim();
// 查找第一个换行符位置并截取
int index = snippet.indexOf('\n'); int index = snippet.indexOf('\n');
if (index != -1) { if (index != -1) {
snippet = snippet.substring(0, index); snippet = snippet.substring(0, index);

@ -39,8 +39,17 @@ public class ResourceParser {
public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM;
// Font colors
public static final int FONT_COLOR_BLACK = 0;
public static final int FONT_COLOR_RED = 1;
public static final int FONT_COLOR_BLUE = 2;
public static final int FONT_COLOR_GREEN = 3;
public static final int FONT_COLOR_WHITE = 4;
public static final int DEFAULT_FONT_COLOR = FONT_COLOR_BLACK;
public static class NoteBgResources { public static class NoteBgResources {
private final static int [] BG_EDIT_RESOURCES = new int [] { public final static int [] BG_EDIT_RESOURCES = new int [] {
R.drawable.edit_yellow, R.drawable.edit_yellow,
R.drawable.edit_blue, R.drawable.edit_blue,
R.drawable.edit_white, R.drawable.edit_white,
@ -178,4 +187,25 @@ public class ResourceParser {
return TEXTAPPEARANCE_RESOURCES.length; return TEXTAPPEARANCE_RESOURCES.length;
} }
} }
public static class TextColorResources {
private final static int [] TEXT_COLOR_RESOURCES = new int [] {
android.R.color.black,
android.R.color.holo_red_dark,
android.R.color.holo_blue_dark,
android.R.color.holo_green_dark,
android.R.color.white
};
public static int getTextColorResource(int id) {
if (id >= TEXT_COLOR_RESOURCES.length) {
return DEFAULT_FONT_COLOR;
}
return TEXT_COLOR_RESOURCES[id];
}
public static int getResourcesSize() {
return TEXT_COLOR_RESOURCES.length;
}
}
} }

@ -30,9 +30,11 @@ import android.content.SharedPreferences;
import android.graphics.Paint; import android.graphics.Paint;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.format.DateUtils; import android.text.format.DateUtils;
import android.text.style.BackgroundColorSpan; import android.text.style.BackgroundColorSpan;
import android.util.Log; import android.util.Log;
@ -43,6 +45,7 @@ import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton; import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.CompoundButton.OnCheckedChangeListener;
@ -82,6 +85,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
public TextView tvAlertDate; public TextView tvAlertDate;
public ImageView ibSetBgColor; public ImageView ibSetBgColor;
public Button ibSetFontColor;
} }
private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>(); private static final Map<Integer, Integer> sBgSelectorBtnsMap = new HashMap<Integer, Integer>();
@ -118,6 +123,25 @@ public class NoteEditActivity extends Activity implements OnClickListener,
sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select); sFontSelectorSelectionMap.put(ResourceParser.TEXT_SUPER, R.id.iv_super_select);
} }
// Font color maps
private static final Map<Integer, Integer> sFontColorBtnsMap = new HashMap<Integer, Integer>();
static {
sFontColorBtnsMap.put(R.id.iv_font_black, ResourceParser.FONT_COLOR_BLACK);
sFontColorBtnsMap.put(R.id.iv_font_red, ResourceParser.FONT_COLOR_RED);
sFontColorBtnsMap.put(R.id.iv_font_blue, ResourceParser.FONT_COLOR_BLUE);
sFontColorBtnsMap.put(R.id.iv_font_green, ResourceParser.FONT_COLOR_GREEN);
sFontColorBtnsMap.put(R.id.iv_font_white, ResourceParser.FONT_COLOR_WHITE);
}
private static final Map<Integer, Integer> sFontColorSelectorSelectionMap = new HashMap<Integer, Integer>();
static {
sFontColorSelectorSelectionMap.put(ResourceParser.FONT_COLOR_BLACK, R.id.iv_font_black_select);
sFontColorSelectorSelectionMap.put(ResourceParser.FONT_COLOR_RED, R.id.iv_font_red_select);
sFontColorSelectorSelectionMap.put(ResourceParser.FONT_COLOR_BLUE, R.id.iv_font_blue_select);
sFontColorSelectorSelectionMap.put(ResourceParser.FONT_COLOR_GREEN, R.id.iv_font_green_select);
sFontColorSelectorSelectionMap.put(ResourceParser.FONT_COLOR_WHITE, R.id.iv_font_white_select);
}
private static final String TAG = "NoteEditActivity"; private static final String TAG = "NoteEditActivity";
private HeadViewHolder mNoteHeaderHolder; private HeadViewHolder mNoteHeaderHolder;
@ -126,6 +150,8 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private View mNoteBgColorSelector; private View mNoteBgColorSelector;
private View mFontColorSelector;
private View mFontSizeSelector; private View mFontSizeSelector;
private EditText mNoteEditor; private EditText mNoteEditor;
@ -136,8 +162,10 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private SharedPreferences mSharedPrefs; private SharedPreferences mSharedPrefs;
private int mFontSizeId; private int mFontSizeId;
private int mFontColorId;
private static final String PREFERENCE_FONT_SIZE = "pref_font_size"; private static final String PREFERENCE_FONT_SIZE = "pref_font_size";
private static final String PREFERENCE_FONT_COLOR = "pref_font_color";
private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10; private static final int SHORTCUT_ICON_TITLE_MAX_LEN = 10;
@ -149,6 +177,25 @@ public class NoteEditActivity extends Activity implements OnClickListener,
private String mUserQuery; private String mUserQuery;
private Pattern mPattern; private Pattern mPattern;
// 定义mTextWatcher变量
private TextWatcher mTextWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 此方法为接口必须实现的方法,但我们不需要在此做任何操作
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// 此方法为接口必须实现的方法,但我们不需要在此做任何操作
}
@Override
public void afterTextChanged(Editable s) {
// 文本变化后的处理逻辑
// 此处可以留空,因为我们目前没有特殊的处理需求
}
};
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -370,31 +417,50 @@ public class NoteEditActivity extends Activity implements OnClickListener,
mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon); mNoteHeaderHolder.ivAlertIcon = (ImageView) findViewById(R.id.iv_alert_icon);
mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date); mNoteHeaderHolder.tvAlertDate = (TextView) findViewById(R.id.tv_alert_date);
mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color); mNoteHeaderHolder.ibSetBgColor = (ImageView) findViewById(R.id.btn_set_bg_color);
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this); mNoteHeaderHolder.ibSetFontColor = (Button) findViewById(R.id.btn_set_font_color);
mNoteEditor = (EditText) findViewById(R.id.note_edit_view); mNoteEditor = (EditText) findViewById(R.id.note_edit_view);
mNoteEditorPanel = findViewById(R.id.sv_note_edit); mNoteEditorPanel = findViewById(R.id.sv_note_edit);
mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector); mNoteBgColorSelector = findViewById(R.id.note_bg_color_selector);
for (int id : sBgSelectorBtnsMap.keySet()) { mFontColorSelector = findViewById(R.id.font_color_selector);
mFontSizeSelector = findViewById(R.id.font_size_selector);
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list);
mNoteHeaderHolder.ibSetBgColor.setOnClickListener(this);
mNoteHeaderHolder.ibSetFontColor.setOnClickListener(this);
/**
* Initialize the Chinese input method editor watcher
*/
mNoteEditor.addTextChangedListener(mTextWatcher);
for (Integer id : sBgSelectorBtnsMap.keySet()) {
ImageView iv = (ImageView) findViewById(id); ImageView iv = (ImageView) findViewById(id);
iv.setOnClickListener(this); iv.setOnClickListener(this);
} }
mFontSizeSelector = findViewById(R.id.font_size_selector); for (Integer id : sFontSizeBtnsMap.keySet()) {
for (int id : sFontSizeBtnsMap.keySet()) {
View view = findViewById(id); View view = findViewById(id);
view.setOnClickListener(this); view.setOnClickListener(this);
}; }
for (Integer id : sFontColorBtnsMap.keySet()) {
View view = findViewById(id);
view.setOnClickListener(this);
}
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE); mFontSizeId = mSharedPrefs.getInt(PREFERENCE_FONT_SIZE, ResourceParser.BG_DEFAULT_FONT_SIZE);
mFontColorId = mSharedPrefs.getInt(PREFERENCE_FONT_COLOR, ResourceParser.DEFAULT_FONT_COLOR);
/** /**
* HACKME: Fix bug of store the resource id in shared preference. * Prepare for setting font size
* The id may larger than the length of resources, in this case,
* return the {@link ResourceParser#BG_DEFAULT_FONT_SIZE}
*/ */
if(mFontSizeId >= TextAppearanceResources.getResourcesSize()) { mNoteEditor.setTextAppearance(this, ResourceParser.TextAppearanceResources
mFontSizeId = ResourceParser.BG_DEFAULT_FONT_SIZE; .getTexAppearanceResource(mFontSizeId));
} /**
mEditTextList = (LinearLayout) findViewById(R.id.note_edit_list); * Set font color
*/
mNoteEditor.setTextColor(getResources().getColor(
ResourceParser.TextColorResources.getTextColorResource(mFontColorId)));
} }
@Override @Override
@ -425,30 +491,86 @@ public class NoteEditActivity extends Activity implements OnClickListener,
setResult(RESULT_OK, intent); setResult(RESULT_OK, intent);
} }
@Override
public void onClick(View v) { public void onClick(View v) {
int id = v.getId(); int id = v.getId();
if (id == R.id.btn_set_bg_color) { if (id == R.id.btn_set_bg_color) {
// user clicks to set background
if (mNoteBgColorSelector.getVisibility() == View.GONE) {
mFontSizeSelector.setVisibility(View.GONE);
mFontColorSelector.setVisibility(View.GONE);
mNoteBgColorSelector.setVisibility(View.VISIBLE); mNoteBgColorSelector.setVisibility(View.VISIBLE);
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( if (mWorkingNote.getBgColorId() >= 0
- View.VISIBLE); && mWorkingNote.getBgColorId() < ResourceParser.NoteBgResources.BG_EDIT_RESOURCES.length) {
} else if (sBgSelectorBtnsMap.containsKey(id)) { findViewById(
sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.VISIBLE);
}
} else {
mNoteBgColorSelector.setVisibility(View.GONE);
}
return;
} else if (id == R.id.btn_set_font_color) {
// user clicks to set font color
if (mFontColorSelector.getVisibility() == View.GONE) {
mNoteBgColorSelector.setVisibility(View.GONE);
mFontSizeSelector.setVisibility(View.GONE);
mFontColorSelector.setVisibility(View.VISIBLE);
if (mFontColorId >= 0 && mFontColorId < ResourceParser.TextColorResources.getResourcesSize()) {
findViewById(sFontColorSelectorSelectionMap.get(mFontColorId)).setVisibility(View.VISIBLE);
}
} else {
mFontColorSelector.setVisibility(View.GONE);
}
return;
}
/**
* User choose a color to set, should change the UI and save it
*/
for (Map.Entry<Integer, Integer> entry : sBgSelectorBtnsMap.entrySet()) {
if (entry.getKey() == id) {
int bgColorId = entry.getValue();
findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility( findViewById(sBgSelectorSelectionMap.get(mWorkingNote.getBgColorId())).setVisibility(
View.GONE); View.GONE);
mWorkingNote.setBgColorId(sBgSelectorBtnsMap.get(id)); mWorkingNote.setBgColorId(bgColorId);
mNoteBgColorSelector.setVisibility(View.GONE); mNoteBgColorSelector.setVisibility(View.GONE);
} else if (sFontSizeBtnsMap.containsKey(id)) { break;
}
}
/**
* User choose a font size to set, should change the UI and save it
*/
for (Map.Entry<Integer, Integer> entry : sFontSizeBtnsMap.entrySet()) {
if (entry.getKey() == id) {
int fontSizeId = entry.getValue();
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.GONE);
mFontSizeId = sFontSizeBtnsMap.get(id); mFontSizeId = fontSizeId;
mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).commit();
findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE); findViewById(sFontSelectorSelectionMap.get(mFontSizeId)).setVisibility(View.VISIBLE);
if (mWorkingNote.getCheckListMode() == TextNote.MODE_CHECK_LIST) { mSharedPrefs.edit().putInt(PREFERENCE_FONT_SIZE, mFontSizeId).apply();
getWorkingText(); mNoteEditor.setTextAppearance(this, ResourceParser.TextAppearanceResources
switchToListMode(mWorkingNote.getContent()); .getTexAppearanceResource(mFontSizeId));
} else {
mNoteEditor.setTextAppearance(this,
TextAppearanceResources.getTexAppearanceResource(mFontSizeId));
}
mFontSizeSelector.setVisibility(View.GONE); mFontSizeSelector.setVisibility(View.GONE);
break;
}
}
/**
* User choose a font color to set, should change the UI and save it
*/
for (Map.Entry<Integer, Integer> entry : sFontColorBtnsMap.entrySet()) {
if (entry.getKey() == id) {
int fontColorId = entry.getValue();
findViewById(sFontColorSelectorSelectionMap.get(mFontColorId)).setVisibility(View.GONE);
mFontColorId = fontColorId;
findViewById(sFontColorSelectorSelectionMap.get(mFontColorId)).setVisibility(View.VISIBLE);
mSharedPrefs.edit().putInt(PREFERENCE_FONT_COLOR, mFontColorId).apply();
mNoteEditor.setTextColor(getResources().getColor(
ResourceParser.TextColorResources.getTextColorResource(mFontColorId)));
mFontColorSelector.setVisibility(View.GONE);
break;
}
} }
} }
@ -469,6 +591,9 @@ public class NoteEditActivity extends Activity implements OnClickListener,
} else if (mFontSizeSelector.getVisibility() == View.VISIBLE) { } else if (mFontSizeSelector.getVisibility() == View.VISIBLE) {
mFontSizeSelector.setVisibility(View.GONE); mFontSizeSelector.setVisibility(View.GONE);
return true; return true;
} else if (mFontColorSelector.getVisibility() == View.VISIBLE) {
mFontColorSelector.setVisibility(View.GONE);
return true;
} }
return false; return false;
} }

@ -69,50 +69,74 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
update(context, appWidgetManager, appWidgetIds, false); update(context, appWidgetManager, appWidgetIds, false);
} }
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds, /**
*
*
* NoteWidgetProvider
* 1. widgetId
* 2.
* 3. (/)
*
* @param context
* @param appWidgetManager AppWidgetManager
* @param appWidgetIds ID
* @param privacyMode true
*/
private void update(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds,
boolean privacyMode) { boolean privacyMode) {
// 遍历所有需要更新的小部件ID
for (int i = 0; i < appWidgetIds.length; i++) { for (int i = 0; i < appWidgetIds.length; i++) {
if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) { if (appWidgetIds[i] != AppWidgetManager.INVALID_APPWIDGET_ID) {
// 初始化默认背景和意图
int bgId = ResourceParser.getDefaultBgId(context); int bgId = ResourceParser.getDefaultBgId(context);
String snippet = ""; String snippet = "";
// 准备编辑笔记的Intent
Intent intent = new Intent(context, NoteEditActivity.class); Intent intent = new Intent(context, NoteEditActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]); intent.putExtra(Notes.INTENT_EXTRA_WIDGET_ID, appWidgetIds[i]);
intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType()); intent.putExtra(Notes.INTENT_EXTRA_WIDGET_TYPE, getWidgetType());
// 从数据库查询小部件关联的笔记信息
Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]); Cursor c = getNoteWidgetInfo(context, appWidgetIds[i]);
if (c != null && c.moveToFirst()) { if (c != null && c.moveToFirst()) {
// 检查是否存在重复widgetId的笔记
if (c.getCount() > 1) { if (c.getCount() > 1) {
Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]); Log.e(TAG, "Multiple message with same widget id:" + appWidgetIds[i]);
c.close(); c.close();
return; return;
} }
// 获取笔记内容和背景色
snippet = c.getString(COLUMN_SNIPPET); snippet = c.getString(COLUMN_SNIPPET);
bgId = c.getInt(COLUMN_BG_COLOR_ID); bgId = c.getInt(COLUMN_BG_COLOR_ID);
intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID)); intent.putExtra(Intent.EXTRA_UID, c.getLong(COLUMN_ID));
intent.setAction(Intent.ACTION_VIEW); intent.setAction(Intent.ACTION_VIEW); // 查看模式
} else { } else {
// 没有关联笔记时使用默认内容
snippet = context.getResources().getString(R.string.widget_havenot_content); snippet = context.getResources().getString(R.string.widget_havenot_content);
intent.setAction(Intent.ACTION_INSERT_OR_EDIT); intent.setAction(Intent.ACTION_INSERT_OR_EDIT); // 新建/编辑模式
} }
if (c != null) { if (c != null) {
c.close(); c.close();
} }
// 配置RemoteViews
RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId()); RemoteViews rv = new RemoteViews(context.getPackageName(), getLayoutId());
rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId)); rv.setImageViewResource(R.id.widget_bg_image, getBgResourceId(bgId));
intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId); intent.putExtra(Notes.INTENT_EXTRA_BACKGROUND_ID, bgId);
/**
* Generate the pending intent to start host for the widget // 设置PendingIntent
*/
PendingIntent pendingIntent = null; PendingIntent pendingIntent = null;
if (privacyMode) { if (privacyMode) {
// 隐私模式:显示提示文本,点击进入笔记列表
rv.setTextViewText(R.id.widget_text, rv.setTextViewText(R.id.widget_text,
context.getString(R.string.widget_under_visit_mode)); context.getString(R.string.widget_under_visit_mode));
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], new Intent( pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i],
context, NotesListActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); new Intent(context, NotesListActivity.class),
PendingIntent.FLAG_UPDATE_CURRENT);
} else { } else {
// 正常模式:显示笔记内容,点击进入编辑界面
rv.setTextViewText(R.id.widget_text, snippet); rv.setTextViewText(R.id.widget_text, snippet);
pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent, pendingIntent = PendingIntent.getActivity(context, appWidgetIds[i], intent,
PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent.FLAG_UPDATE_CURRENT);
@ -122,7 +146,8 @@ public abstract class NoteWidgetProvider extends AppWidgetProvider {
appWidgetManager.updateAppWidget(appWidgetIds[i], rv); appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
} }
} }
} }
protected abstract int getBgResourceId(int bgId); protected abstract int getBgResourceId(int bgId);

@ -123,6 +123,18 @@
android:background="@drawable/bg_color_btn_mask" android:background="@drawable/bg_color_btn_mask"
android:layout_gravity="top|right" /> android:layout_gravity="top|right" />
<Button
android:id="@+id/btn_set_font_color"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/menu_font_color"
android:drawableLeft="@android:drawable/ic_menu_edit"
android:drawablePadding="5dp"
android:padding="10dp"
android:layout_marginBottom="20dp"
android:layout_marginLeft="10dp"
android:layout_gravity="bottom|left" />
<LinearLayout <LinearLayout
android:id="@+id/note_bg_color_selector" android:id="@+id/note_bg_color_selector"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -237,6 +249,125 @@
</FrameLayout> </FrameLayout>
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/font_color_selector"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/note_edit_color_selector_panel"
android:layout_marginBottom="70dip"
android:layout_marginLeft="8dip"
android:layout_gravity="bottom|left"
android:visibility="gone">
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_font_black"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black" />
<ImageView
android:id="@+id/iv_font_black_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginRight="5dip"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_font_red"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_red_dark" />
<ImageView
android:id="@+id/iv_font_red_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="3dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_font_blue"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_blue_dark" />
<ImageView
android:id="@+id/iv_font_blue_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:layout_marginRight="2dip"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_font_green"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_green_dark" />
<ImageView
android:id="@+id/iv_font_green_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
<FrameLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1">
<ImageView
android:id="@+id/iv_font_white"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white" />
<ImageView
android:id="@+id/iv_font_white_select"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:focusable="false"
android:visibility="gone"
android:src="@drawable/selected" />
</FrameLayout>
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/font_size_selector" android:id="@+id/font_size_selector"
android:layout_width="fill_parent" android:layout_width="fill_parent"

@ -49,10 +49,16 @@
<string name="menu_select_all">全选</string> <string name="menu_select_all">全选</string>
<string name="menu_deselect_all">取消全选</string> <string name="menu_deselect_all">取消全选</string>
<string name="menu_font_size">文字大小</string> <string name="menu_font_size">文字大小</string>
<string name="menu_font_color">文字颜色</string>
<string name="menu_font_small"></string> <string name="menu_font_small"></string>
<string name="menu_font_normal">正常</string> <string name="menu_font_normal">正常</string>
<string name="menu_font_large"></string> <string name="menu_font_large"></string>
<string name="menu_font_super">超大</string> <string name="menu_font_super">超大</string>
<string name="menu_font_color_black">黑色</string>
<string name="menu_font_color_red">红色</string>
<string name="menu_font_color_blue">蓝色</string>
<string name="menu_font_color_green">绿色</string>
<string name="menu_font_color_white">白色</string>
<string name="menu_list_mode">进入清单模式</string> <string name="menu_list_mode">进入清单模式</string>
<string name="menu_normal_mode">退出清单模式</string> <string name="menu_normal_mode">退出清单模式</string>
<string name="menu_folder_view">查看文件夹</string> <string name="menu_folder_view">查看文件夹</string>
@ -110,6 +116,7 @@
<string name="preferences_toast_cannot_change_account">正在同步中,不能修改同步帐号</string> <string name="preferences_toast_cannot_change_account">正在同步中,不能修改同步帐号</string>
<string name="preferences_toast_success_set_accout">同步帐号已设置为%1$s</string> <string name="preferences_toast_success_set_accout">同步帐号已设置为%1$s</string>
<string name="preferences_bg_random_appear_title">新建便签背景颜色随机</string> <string name="preferences_bg_random_appear_title">新建便签背景颜色随机</string>
<string name="pref_title_font_color">文字颜色</string>
<string name="button_delete">删除</string> <string name="button_delete">删除</string>
<string name="call_record_folder_name">通话便签</string> <string name="call_record_folder_name">通话便签</string>
<string name="hint_foler_name">请输入名称</string> <string name="hint_foler_name">请输入名称</string>
@ -120,7 +127,7 @@
<string name="datetime_dialog_ok">设置</string> <string name="datetime_dialog_ok">设置</string>
<string name="datetime_dialog_cancel">取消</string> <string name="datetime_dialog_cancel">取消</string>
<plurals name="search_results_title"> <plurals name="search_results_title">
<item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合<xliff:g id="SEARCH">%2$s</xliff:g>的搜索结果</item> <item quantity="other"><xliff:g id="NUMBER">%1$s</xliff:g> 条符合"<xliff:g id="SEARCH">%2$s</xliff:g>"的搜索结果</item>
</plurals> </plurals>
</resources> </resources>

@ -53,10 +53,16 @@
<string name="menu_select_all">Select all</string> <string name="menu_select_all">Select all</string>
<string name="menu_deselect_all">Deselect all</string> <string name="menu_deselect_all">Deselect all</string>
<string name="menu_font_size">Font size</string> <string name="menu_font_size">Font size</string>
<string name="menu_font_color">Font color</string>
<string name="menu_font_small">Small</string> <string name="menu_font_small">Small</string>
<string name="menu_font_normal">Medium</string> <string name="menu_font_normal">Medium</string>
<string name="menu_font_large">Large</string> <string name="menu_font_large">Large</string>
<string name="menu_font_super">Super</string> <string name="menu_font_super">Super</string>
<string name="menu_font_color_black">Black</string>
<string name="menu_font_color_red">Red</string>
<string name="menu_font_color_blue">Blue</string>
<string name="menu_font_color_green">Green</string>
<string name="menu_font_color_white">White</string>
<string name="menu_list_mode">Enter check list</string> <string name="menu_list_mode">Enter check list</string>
<string name="menu_normal_mode">Leave check list</string> <string name="menu_normal_mode">Leave check list</string>
<string name="menu_folder_view">View folder</string> <string name="menu_folder_view">View folder</string>
@ -64,7 +70,7 @@
<string name="menu_folder_change_name">Change folder name</string> <string name="menu_folder_change_name">Change folder name</string>
<string name="folder_exist">The folder %1$s exist, please rename</string> <string name="folder_exist">The folder %1$s exist, please rename</string>
<string name="menu_share">Share</string> <string name="menu_share">Share</string>
<string name="menu_send_to_desktop">Send to home</string> <string name="menu_send_to_desktop">Send to desktop</string>
<string name="menu_alert">Remind me</string> <string name="menu_alert">Remind me</string>
<string name="menu_remove_remind">Delete reminder</string> <string name="menu_remove_remind">Delete reminder</string>
<string name="menu_title_select_folder">Select folder</string> <string name="menu_title_select_folder">Select folder</string>
@ -132,4 +138,9 @@
<item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item> <item quantity="other"><xliff:g id="number" example="15">%1$s</xliff:g> results for \"<xliff:g id="search" example="???">%2$s</xliff:g>\"</item>
</plurals> </plurals>
<!-- settings -->
<string name="pref_title_font_size">Font size</string>
<string name="pref_title_font_color">Font color</string>
<string name="pref_title_note_style">Note style</string>
</resources> </resources>

Loading…
Cancel
Save