BackupUtils.java: // Check if external storage is available if (!externalStorageAvailable()) { Log.d(TAG, "Media was not mounted"); return STATE_SD_CARD_UNMOUONTED; } // Get a print stream for exporting to text PrintStream ps = getExportToTextPrintStream(); if (ps == null) { Log.e(TAG, "get print stream error"); return STATE_SYSTEM_ERROR; } // First export folder and its notes Cursor folderCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR " + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null); if (folderCursor != null) { if (folderCursor.moveToFirst()) { do { // Print folder's name String folderName = ""; if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) { folderName = mContext.getString(R.string.call_record_folder_name); } else { folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET); } if (!TextUtils.isEmpty(folderName)) { ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName)); } String folderId = folderCursor.getString(NOTE_COLUMN_ID); exportFolderToText(folderId, ps); } while (folderCursor.moveToNext()); } folderCursor.close(); } // Export notes in root's folder Cursor noteCursor = mContext.getContentResolver().query( Notes.CONTENT_NOTE_URI, NOTE_PROJECTION, NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID + "=0", null, null); if (noteCursor != null) { if (noteCursor.moveToFirst()) { do { ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format( mContext.getString(R.string.format_datetime_mdhm), noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE)))); // Query data belong to this note String noteId = noteCursor.getString(NOTE_COLUMN_ID); exportNoteToText(noteId, ps); } while (noteCursor.moveToNext()); } noteCursor.close(); } ps.close(); return STATE_SUCCESS; /** * Get a print stream pointed to the file {@generateExportedTextFile} */ private PrintStream getExportToTextPrintStream() { File file = generateFileMountedOnSDcard(mContext, R.string.file_path, R.string.file_name_txt_format); if (file == null) { Log.e(TAG, "create file to exported failed"); return null; } mFileName = file.getName(); mFileDirectory = mContext.getString(R.string.file_path); PrintStream ps = null; try { FileOutputStream fos = new FileOutputStream(file); ps = new PrintStream(fos); } catch (FileNotFoundException e) { e.printStackTrace(); return null; } catch (NullPointerException e) { e.printStackTrace(); return null; } return ps; } /** * Generate the text file to store imported data */ private static File generateFileMountedOnSDcard(Context context, int filePathResId, int fileNameFormatResId) { StringBuilder sb = new StringBuilder(); sb.append(Environment.getExternalStorageDirectory()); sb.append(context.getString(filePathResId)); File filedir = new File(sb.toString()); sb.append(context.getString( fileNameFormatResId, DateFormat.format(context.getString(R.string.format_date_ymd), System.currentTimeMillis()))); File file = new File(sb.toString()); try { if (!filedir.exists()) { filedir.mkdir(); } if (!file.exists()) { file.createNewFile(); } return file; } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } DataUtils.java: /** * 根据指定的便签ID和类型,判断便签是否可见在便签数据库中 * 可见性判断基于便签的类型和是否位于回收站外 * * @param resolver ContentResolver用于查询 * @param noteId 便签ID * @param type 便签类型 * @return 如果便签可见则返回true,否则返回false */ public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) { // 构造查询条件,查询指定ID和类型的便签,排除回收站便签 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER, new String [] {String.valueOf(type)}, null); boolean exist = false; if (cursor != null) { if (cursor.getCount() > 0) { exist = true; } cursor.close(); } return exist; } /** * 检查指定ID的便签是否存在于数据库中 * * @param resolver ContentResolver用于查询 * @param noteId 便签ID * @return 如果便签存在则返回true,否则返回false */ public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) { // 直接查询指定ID的便签,无条件限制 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), null, null, null, null); boolean exist = false; if (cursor != null) { if (cursor.getCount() > 0) { exist = true; } cursor.close(); } return exist; } /** * 检查指定ID的数据项是否存在于数据库中 * * @param resolver ContentResolver用于查询 * @param dataId 数据ID * @return 如果数据存在则返回true,否则返回false */ public static boolean existInDataDatabase(ContentResolver resolver, long dataId) { // 直接查询指定ID的数据项,无条件限制 Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId), null, null, null, null); boolean exist = false; if (cursor != null) { if (cursor.getCount() > 0) { exist = true; } cursor.close(); } return exist; } /** * 检查指定名称的文件夹是否可见在数据库中 * 可见性判断基于文件夹类型和是否位于回收站外 * * @param resolver ContentResolver用于查询 * @param name 文件夹名称 * @return 如果文件夹可见则返回true,否则返回false */ public static boolean checkVisibleFolderName(ContentResolver resolver, String name) { // 构造查询条件,查询指定名称的文件夹,排除回收站文件夹 Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null, NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + " AND " + NoteColumns.SNIPPET + "=?", new String[] { name }, null); boolean exist = false; if(cursor != null) { if(cursor.getCount() > 0) { exist = true; } cursor.close(); } return exist; } /** * 获取指定文件夹下的所有便签小部件集合 * * @param resolver ContentResolver用于查询 * @param folderId 文件夹ID * @return 便签小部件的HashSet集合,如果不存在则返回null */ public static HashSet getFolderNoteWidget(ContentResolver resolver, long folderId) { // 构造查询条件,查询指定文件夹ID的所有便签小部件 Cursor c = resolver.query(Notes.CONTENT_NOTE_URI, new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }, NoteColumns.PARENT_ID + "=?", new String[] { String.valueOf(folderId) }, null); HashSet set = null; if (c != null) { if (c.moveToFirst()) { set = new HashSet(); do { try { AppWidgetAttribute widget = new AppWidgetAttribute(); widget.widgetId = c.getInt(0); widget.widgetType = c.getInt(1); set.add(widget); } catch (IndexOutOfBoundsException e) { Log.e(TAG, e.toString()); } } while (c.moveToNext()); } c.close(); } return set; } /** * 根据便签ID获取相关的电话号码 * * @param resolver ContentResolver用于查询 * @param noteId 便签ID * @return 电话号码字符串,如果查询失败或没有相关记录则返回空字符串 */ public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) { // 构造查询条件,查询指定便签ID的电话号码 Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.PHONE_NUMBER }, CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?", new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }, null); if (cursor != null && cursor.moveToFirst()) { try { return cursor.getString(0); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "Get call number fails " + e.toString()); } finally { cursor.close(); } } return ""; } /** * 根据电话号码和呼叫日期获取便签ID * * @param resolver ContentResolver用于查询 * @param phoneNumber 电话号码 * @param callDate 呼叫日期 * @return 便签ID,如果查询失败或没有相关记录则返回0 */ public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) { // 构造查询条件,查询匹配电话号码和呼叫日期的便签ID Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI, new String [] { CallNote.NOTE_ID }, CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" + CallNote.PHONE_NUMBER + ",?)", new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }, null); if (cursor != null) { if (cursor.moveToFirst()) { try { return cursor.getLong(0); } catch (IndexOutOfBoundsException e) { Log.e(TAG, "Get call note id fails " + e.toString()); } } cursor.close(); } return 0; } /** * 根据便签ID获取便签的摘要信息 * * @param resolver ContentResolver用于查询 * @param noteId 便签ID * @return 便签的摘要字符串,如果查询失败或便签不存在则抛出IllegalArgumentException */ public static String getSnippetById(ContentResolver resolver, long noteId) { // 构造查询条件,查询指定便签ID的摘要信息 Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, new String [] { NoteColumns.SNIPPET }, NoteColumns.ID + "=?", new String [] { String.valueOf(noteId)}, null); if (cursor != null) { String snippet = ""; if (cursor.moveToFirst()) { snippet = cursor.getString(0); } cursor.close(); return snippet; } throw new IllegalArgumentException("Note is not found with id: " + noteId); } /** * 格式化便签的摘要信息 * 去除摘要前后的空白字符,并截取到第一个换行符之前的部分 * * @param snippet 原始摘要字符串 * @return 格式化后的摘要字符串,如果输入为null则返回null */ public static String getFormattedSnippet(String snippet) { if (snippet != null) { snippet = snippet.trim(); int index = snippet.indexOf('\n'); if (index != -1) { snippet = snippet.substring(0, index); } } return snippet; } GTaskStringUtils.java: /* * 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. */ /** * The GTaskStringUtils class is a utility class for string constants used in GTasks. * It defines a series of constant strings for use in GTasks-related operations, * such as action types, entity attributes, and user-related information. */ package net.micode.notes.tool; public class GTaskStringUtils { // Action identifier constant public final static String GTASK_JSON_ACTION_ID = "action_id"; // Action list constant public final static String GTASK_JSON_ACTION_LIST = "action_list"; // Action type constant public final static String GTASK_JSON_ACTION_TYPE = "action_type"; // Action type for creation public final static String GTASK_JSON_ACTION_TYPE_CREATE = "create"; // Action type for retrieving all items public final static String GTASK_JSON_ACTION_TYPE_GETALL = "get_all"; // Action type for moving public final static String GTASK_JSON_ACTION_TYPE_MOVE = "move"; // Action type for updating public final static String GTASK_JSON_ACTION_TYPE_UPDATE = "update"; // Creator identifier constant public final static String GTASK_JSON_CREATOR_ID = "creator_id"; // Child entity constant public final static String GTASK_JSON_CHILD_ENTITY = "child_entity"; // Client version constant public final static String GTASK_JSON_CLIENT_VERSION = "client_version"; // Completed status constant public final static String GTASK_JSON_COMPLETED = "completed"; // Current list identifier constant public final static String GTASK_JSON_CURRENT_LIST_ID = "current_list_id"; // Default list identifier constant public final static String GTASK_JSON_DEFAULT_LIST_ID = "default_list_id"; // Deleted status constant public final static String GTASK_JSON_DELETED = "deleted"; // Destination list constant public final static String GTASK_JSON_DEST_LIST = "dest_list"; // Destination parent constant public final static String GTASK_JSON_DEST_PARENT = "dest_parent"; // Destination parent type constant public final static String GTASK_JSON_DEST_PARENT_TYPE = "dest_parent_type"; // Entity change constant public final static String GTASK_JSON_ENTITY_DELTA = "entity_delta"; // Entity type constant public final static String GTASK_JSON_ENTITY_TYPE = "entity_type"; // Whether to retrieve deleted items constant public final static String GTASK_JSON_GET_DELETED = "get_deleted"; // Entity identifier constant public final static String GTASK_JSON_ID = "id"; // Index constant public final static String GTASK_JSON_INDEX = "index"; // Last modified time constant public final static String GTASK_JSON_LAST_MODIFIED = "last_modified"; // Latest synchronization point constant public final static String GTASK_JSON_LATEST_SYNC_POINT = "latest_sync_point"; // List identifier constant public final static String GTASK_JSON_LIST_ID = "list_id"; // Lists constant public final static String GTASK_JSON_LISTS = "lists"; // Name constant public final static String GTASK_JSON_NAME = "name"; // New identifier constant public final static String GTASK_JSON_NEW_ID = "new_id"; // Notes constant public final static String GTASK_JSON_NOTES = "notes"; // Parent identifier constant public final static String GTASK_JSON_PARENT_ID = "parent_id"; // Prior sibling identifier constant public final static String GTASK_JSON_PRIOR_SIBLING_ID = "prior_sibling_id"; // Results constant public final static String GTASK_JSON_RESULTS = "results"; // Source list constant public final static String GTASK_JSON_SOURCE_LIST = "source_list"; // Tasks constant public final static String GTASK_JSON_TASKS = "tasks"; // Type constant public final static String GTASK_JSON_TYPE = "type"; // Group type constant public final static String GTASK_JSON_TYPE_GROUP = "GROUP"; // Task type constant public final static String GTASK_JSON_TYPE_TASK = "TASK"; // User information constant public final static String GTASK_JSON_USER = "user"; // MIUI Notes folder prefix constant public final static String MIUI_FOLDER_PREFFIX = "[MIUI_Notes]"; // Default folder name constant public final static String FOLDER_DEFAULT = "Default"; // Call note folder name constant public final static String FOLDER_CALL_NOTE = "Call_Note"; // Metadata folder name constant public final static String FOLDER_META = "METADATA"; // Metadata GTasks identifier constant public final static String META_HEAD_GTASK_ID = "meta_gid"; // Metadata note constant public final static String META_HEAD_NOTE = "meta_note"; // Metadata content constant public final static String META_HEAD_DATA = "meta_data"; // Metadata note name constant, indicating not to update and delete public final static String META_NOTE_NAME = "[META INFO] DON'T UPDATE AND DELETE"; } ResourceParser.java: * * 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.tool; import android.content.Context; import android.preference.PreferenceManager; import net.micode.notes.R; import net.micode.notes.ui.NotesPreferenceActivity; /** * ResourceParser类用于解析与笔记应用相关的资源,如背景颜色和文本大小等。 */ public class ResourceParser { // 定义颜色常量 public static final int YELLOW = 0; public static final int BLUE = 1; public static final int WHITE = 2; public static final int GREEN = 3; public static final int RED = 4; // 默认背景颜色 public static final int BG_DEFAULT_COLOR = YELLOW; // 定义文本大小常量 public static final int TEXT_SMALL = 0; public static final int TEXT_MEDIUM = 1; public static final int TEXT_LARGE = 2; public static final int TEXT_SUPER = 3; // 默认文本大小 public static final int BG_DEFAULT_FONT_SIZE = TEXT_MEDIUM; /** * NoteBgResources类用于获取笔记编辑背景资源。 */ public static class NoteBgResources { // 定义编辑背景资源数组 private final static int [] BG_EDIT_RESOURCES = new int [] { R.drawable.edit_yellow, R.drawable.edit_blue, R.drawable.edit_white, R.drawable.edit_green, R.drawable.edit_red }; // 定义编辑标题背景资源数组 private final static int [] BG_EDIT_TITLE_RESOURCES = new int [] { R.drawable.edit_title_yellow, R.drawable.edit_title_blue, R.drawable.edit_title_white, R.drawable.edit_title_green, R.drawable.edit_title_red }; /** * 根据颜色ID获取笔记背景资源。 * * @param id 颜色ID * @return 对应的背景资源ID */ public static int getNoteBgResource(int id) { return BG_EDIT_RESOURCES[id]; } /** * 根据颜色ID获取笔记标题背景资源。 * * @param id 颜色ID * @return 对应的标题背景资源ID */ public static int getNoteTitleBgResource(int id) { return BG_EDIT_TITLE_RESOURCES[id]; } } /** * 获取默认背景颜色ID。 * * @param context 上下文环境 * @return 默认背景颜色ID */ public static int getDefaultBgId(Context context) { if (PreferenceManager.getDefaultSharedPreferences(context).getBoolean( NotesPreferenceActivity.PREFERENCE_SET_BG_COLOR_KEY, false)) { return (int) (Math.random() * NoteBgResources.BG_EDIT_RESOURCES.length); } else { return BG_DEFAULT_COLOR; } } /** * NoteItemBgResources类用于获取笔记列表项和文件夹的背景资源。 */ public static class NoteItemBgResources { // 定义首项背景资源数组 private final static int [] BG_FIRST_RESOURCES = new int [] { R.drawable.list_yellow_up, R.drawable.list_blue_up, R.drawable.list_white_up, R.drawable.list_green_up, R.drawable.list_red_up }; // 定义普通项背景资源数组 private final static int [] BG_NORMAL_RESOURCES = new int [] { R.drawable.list_yellow_middle, R.drawable.list_blue_middle, R.drawable.list_white_middle, R.drawable.list_green_middle, R.drawable.list_red_middle }; // 定义末项背景资源数组 private final static int [] BG_LAST_RESOURCES = new int [] { R.drawable.list_yellow_down, R.drawable.list_blue_down, R.drawable.list_white_down, R.drawable.list_green_down, R.drawable.list_red_down, }; // 定义单一行背景资源数组 private final static int [] BG_SINGLE_RESOURCES = new int [] { R.drawable.list_yellow_single, R.drawable.list_blue_single, R.drawable.list_white_single, R.drawable.list_green_single, R.drawable.list_red_single }; /** * 根据颜色ID获取笔记背景首项资源。 * * @param id 颜色ID * @return 对应的首项背景资源ID */ public static int getNoteBgFirstRes(int id) { return BG_FIRST_RESOURCES[id]; } /** * 根据颜色ID获取笔记背景末项资源。 * * @param id 颜色ID * @return 对应的末项背景资源ID */ public static int getNoteBgLastRes(int id) { return BG_LAST_RESOURCES[id]; } /** * 根据颜色ID获取笔记单一行背景资源。 * * @param id 颜色ID * @return 对应的单一行背景资源ID */ public static int getNoteBgSingleRes(int id) { return BG_SINGLE_RESOURCES[id]; } /** * 根据颜色ID获取笔记普通项背景资源。 * * @param id 颜色ID * @return 对应的普通项背景资源ID */ public static int getNoteBgNormalRes(int id) { return BG_NORMAL_RESOURCES[id]; } /** * 获取文件夹背景资源。 * * @return 文件夹背景资源ID */ public static int getFolderBgRes() { return R.drawable.list_folder; } } /** * WidgetBgResources类用于获取小部件的背景资源。 */ public static class WidgetBgResources { // 定义2x小部件背景资源数组 private final static int [] BG_2X_RESOURCES = new int [] { R.drawable.widget_2x_yellow, R.drawable.widget_2x_blue, R.drawable.widget_2x_white, R.drawable.widget_2x_green, R.drawable.widget_2x_red, }; /** * 根据颜色ID获取2x小部件背景资源。 * * @param id 颜色ID * @return 对应的2x小部件背景资源ID */ public static int getWidget2xBgResource(int id) { return BG_2X_RESOURCES[id]; } // 定义4x小部件背景资源数组 private final static int [] BG_4X_RESOURCES = new int [] { R.drawable.widget_4x_yellow, R.drawable.widget_4x_blue, R.drawable.widget_4x_white, R.drawable.widget_4x_green, R.drawable.widget_4x_red }; /** * 根据颜色ID获取4x小部件背景资源。 * * @param id 颜色ID * @return 对应的4x小部件背景资源ID */ public static int getWidget4xBgResource(int id) { return BG_4X_RESOURCES[id]; } } /** * TextAppearanceResources类用于获取文本外观资源。 */ public static class TextAppearanceResources { // 定义文本外观资源数组 private final static int [] TEXTAPPEARANCE_RESOURCES = new int [] { R.style.TextAppearanceNormal, R.style.TextAppearanceMedium, R.style.TextAppearanceLarge, R.style.TextAppearanceSuper }; /** * 根据文本大小ID获取文本外观资源。 * * @param id 文本大小ID * @return 对应的文本外观资源ID */ public static int getTexAppearanceResource(int id) { /** * 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 (id >= TEXTAPPEARANCE_RESOURCES.length) { return BG_DEFAULT_FONT_SIZE; } return TEXTAPPEARANCE_RESOURCES[id]; } /** * 获取文本外观资源数组的大小。 * * @return 文本外观资源数组的大小 */ public static int getResourcesSize() { return TEXTAPPEARANCE_RESOURCES.length; } } }